スクレイピングとは?新人エンジニアが練習用サイトでデータ取得に挑戦

はじめに

こんにちは!26卒・文系未経験で入社し、7月からシステム開発部で働いている新人エンジニアの未来です。

前回のバリデーションの記事に続いて、2本目の記事になります。

前回の記事はこちら↓

Laravelのバリデーションとは?新人エンジニアが超初心者目線で解説

今回のテーマは スクレイピング です。

この記事では、超初心者の目線のまま、次の流れで書き残しておきます。

  1. スクレイピングって何?どんなときに使える?
  2. 使う前に気をつけること
  3. 静的ページと動的ページの違い
  4. 練習用サイトで実際に動かしてみる

使用言語 / ツール:Python 3.12 / requests / Beautiful Soup / Playwright(パッケージ管理には uv を使用)

私と同じ文系出身の新人エンジニアや勉強中の方の参考になれば嬉しいです!

そもそもスクレイピングって何?

スクレイピング(scraping)=Webサイトに表示されている情報からプログラムを用いて、必要な情報だけ自動的に取り出し、使いやすい形に整理する技術のことです。

普段私たちは、ブラウザでページを開いて、目で見て、必要なところをコピーしたりしていますよね。スクレイピングは、この「開く → 探す → 取り出す」をプログラムに代わりにやってもらうイメージです。

プログラムがやっていることを分解すると、次の流れになります。

  1. Webページにアクセスして、中身(HTML)を受け取る
  2. HTMLの中から、目的のデータがある場所を探す
  3. データを取り出して、ファイルなどに保存する

よく似た言葉に クローリング があります。クローリングは「リンクをたどってページを巡回すること」、スクレイピングは「ページから情報を取り出すこと」です。検索エンジンは、クローリングでページを集め、集めたページの中身を解析しています。

どんなときに使える?

たとえば、こんな場面で役立ちます。

  • データ分析・研究:公開されているお知らせや記事の一覧を集めて分析する
  • 自社サイトの監視:自分たちのサイトの表示内容やリンク切れを定期的にチェックする
  • 情報収集の自動化:毎日手作業でコピーしている公開情報を、自動で記録する

使う前に気をつけること

スクレイピングは便利ですが、どんなサイトでも自由にやってよいわけではありません。始める前に、次の点を確認しましょう。

  1. 利用規約を確認する サイトによっては、利用規約でスクレイピングなどの自動的なデータ取得を禁止しています。規約で禁止されているサイトでは、やらないのが大前提です。
  2. robots.txt を確認する robots.txt は、サイトが「このページはプログラムで巡回しないでね」と伝えるためのファイルです。https://(サイトのドメイン)/robots.txt で確認できます。ただし robots.txt はあくまでサイト側からのお願いなので、利用規約の確認とセットで考えましょう。
  3. サーバーに負荷をかけない プログラムは人間よりずっと速くアクセスできてしまいます。1回ごとに間隔を空ける、必要なページだけにアクセスする、といった配慮が必要です。
  4. 取得したデータの扱いに気をつける 取得した文章や画像には、著作権で保護されているものがあり、個人情報が含まれることもあります。取得できたからといって、自由に公開・再配布してよいわけではありません。

この記事では、これらの点を気にせず練習できるよう、スクレイピングの練習用に公開されているサイトを使います。

その前に、スクレイピングで知っておきたい「ページの種類」の違いを見ておきましょう。

静的ページと動的ページ

静的ページ は、サーバーから届いたHTMLの中に、最初からデータが書かれているページです。HTMLを受け取って読めば、データが取り出せます。

動的ページ は、届いたHTMLの時点ではデータが画面の形になっておらず、ブラウザがJavaScriptを実行してから画面にデータを表示するページです。

なお、「静的・動的」という言葉は、サーバー側でHTMLを作るかどうかという意味で使われることもあります。この記事では、JavaScriptを実行しなくてもデータが取れるページを「静的ページ」、実行しないと取れないページを「動的ページ」と呼びます。

ここで問題になるのが、Pythonの requests のような「HTMLを受け取るだけ」の方法です。requests はJavaScriptを実行しないので、動的ページでは、ブラウザで見えているはずのデータがHTMLの中に見つかりません。

そこで使うのが Playwright です。Playwrightはプログラムから本物のブラウザを動かすツールで、JavaScriptが実行された後のページから、データを取り出せます。

参考:Playwright for Python 公式ドキュメント(https://playwright.dev/python/)

次の章では、実際に「requestsだと取れない」ことを確かめてから、Playwrightで取得してみます。

やってみよう①:準備と「requestsだと取れない」の確認

今回使うのは、スクレイピングの練習用サイト Quotes to Scrape(https://quotes.toscrape.com/ )です。有名人の名言と著者が並んでいるサイトで、同じ内容を JavaScriptで表示する版(https://quotes.toscrape.com/js/ )も用意されています。

このサイトは、スクレイピングサービスを提供している Zyte社(旧 Scrapinghub)が、スクレイピングの学習用に公開しているサンドボックス(練習場)「toscrape.com」の一部です。

練習のためにアクセスされることを前提に用意されているので、今回はこのサイトで試していきます。自分で別のサイトを試すときは、必ず利用規約と robots.txt を確認してからにしましょう。

参考:toscrape.com(https://toscrape.com/)

参考:Quotes to Scrape(https://quotes.toscrape.com/)

環境を作る

Pythonのパッケージ管理には uv を使います。uvはPython本体のインストールから、ライブラリの管理まで1つでできるツールです。

インストール方法はOSによって違うので、公式ドキュメントを見て入れてください。

参考:uv 公式ドキュメント(https://docs.astral.sh/uv/)

uvが入ったら、ターミナル(Windowsならコマンドプロンプトや PowerShell)で次を実行します。

uv init scraping-practice
cd scraping-practice
uv add requests beautifulsoup4 playwright
uv run playwright install chromium

最後の1行は、Playwrightが動かすブラウザ(Chromium)をダウンロードするコマンドです。

requests で取ってみる

静的版と動的版の両方を requests で取得して、名言(div.quote)がいくつ見つかるか数えてみます。

scraping-practice フォルダに、compare.py を作ります。

import time

import requests
from bs4 import BeautifulSoup

urls = [
    "https://quotes.toscrape.com/",    # 静的ページ
    "https://quotes.toscrape.com/js/", # 動的ページ
]

for url in urls:
    res = requests.get(url, timeout=10)
    soup = BeautifulSoup(res.text, "html.parser")
    quotes = soup.select("div.quote")
    print(f"{url} → {len(quotes)}件")
    time.sleep(1)    # サーバーへの配慮で1秒あける

実行すると、こうなりました。

https://quotes.toscrape.com/ → 10件
https://quotes.toscrape.com/js/ → 0件

ブラウザで見ると同じ画面なのに、動的版は 0件 です。requests はJavaScriptを実行しないので、画面に表示されるはずの名言(div.quote)が、受け取ったHTMLの中にはまだないからです。静的・動的の違いを実感できますね。

やってみよう②:Playwrightで動的ページから取得する

いよいよ本番です。動的版のページから、名言と著者を 全ページ分 取得して、JSONファイルに保存します。

取り出す場所を開発者ツールで探す

コードを書く前に、データがHTMLのどこにあるかを調べます。ブラウザで https://quotes.toscrape.com/js/ を開き、名言の上で右クリック →「検証」を押すと、開発者ツールが開きます。

見てみると、こんな構造になっていました。

  • 名言1つ分のまとまり:div.quote
  • 名言の本文:span.text
  • 著者名:small.author
  • 「Next →」ボタン:li.next > a

コードを書く

scraping-practice フォルダに、scrape_quotes.py を作ります。

import json
import time
from urllib.parse import urljoin

from playwright.sync_api import sync_playwright

START_URL = "https://quotes.toscrape.com/js/"

def main():
    results = []

    with sync_playwright() as p:
        # ブラウザを画面なし(ヘッドレス)で起動
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        page.goto(START_URL)

        while True:
            # JavaScriptで名言が表示されるまで待つ
            page.wait_for_selector("div.quote")

            for quote in page.locator("div.quote").all():
                text = quote.locator("span.text").inner_text()
                author = quote.locator("small.author").inner_text()
                results.append({"text": text, "author": author})

            print(f"{page.url} まで取得(合計 {len(results)}件)")

            # 「Next」ボタンがなければ最後のページ
            next_link = page.locator("li.next > a")
            if next_link.count() == 0:
                break

            time.sleep(1) # サーバーへの配慮で1秒あける
            next_url = urljoin(page.url, next_link.get_attribute("href"))
            page.goto(next_url)

        browser.close()

    with open("quotes.json", "w", encoding="utf-8") as f:
        json.dump(results, f, ensure_ascii=False, indent=2)

    print(f"完了:{len(results)}件を quotes.json に保存しました")

if __name__ == "__main__":
    main()

書けたら次のコマンドを実行します。

uv run python scrape_quotes.py

ポイント

  • wait_for_selector:動的ページでは、ページを開いた瞬間にはまだデータがないことがあります。「quote が表示されるまで待つ」と書くことで、取りこぼしを防げます。requests にはなかった、動的ページならではの考え方です。
  • headless=True:ブラウザの画面を出さずに動かす設定です。False にすると、ブラウザが実際にページをめくっていく様子が見られるので、最初は一度見てみるのがおすすめです。
  • sleep(1):ページをめくるたびに1秒待っています。なお、1秒という数字に決まりはないので、実際のサイトでは利用規約や robots.txt の指定に合わせて調整しましょう。

結果

実行すると、ページをめくりながら取得が進みました。

https://quotes.toscrape.com/js/ まで取得(合計 10件)
https://quotes.toscrape.com/js/page/2/ まで取得(合計 20件)
(中略)
https://quotes.toscrape.com/js/page/10/ まで取得(合計 100件)
完了:100件を quotes.json に保存しました

最後に quotes.json というファイルができました。中身はこんな形です。(一部省略)

[
  {
    "text": "“The world as we have created it is a process of our thinking. ...”",
    "author": "Albert Einstein"
  },
  ...
]

名言の本文(text)と著者名(author)が、1件ずつまとまって保存されています。requests では0件だったページから、きちんとデータが取れました!

まとめ

今回学んだことを振り返ります。

  • スクレイピングは、Webページから必要な情報をプログラムで自動的に取り出す技術
  • 始める前に、利用規約と robots.txt を確認し、サーバーに負荷をかけない
  • 動的ページは、requests では表示されるデータが取れないことがある
  • Playwright を使えば、ブラウザを動かして表示後のデータを取り出せる

ここまで読んでいただき、ありがとうございました!

参考:

・Playwright for Python 公式ドキュメント(https://playwright.dev/python/)

・uv 公式ドキュメント(https://docs.astral.sh/uv/)

・Quotes to Scrape(https://quotes.toscrape.com/)

・toscrape.com(https://toscrape.com/)

この記事がお役に立てば【 いいね 】のご協力をお願いいたします!
1
1
33
X facebook はてなブックマーク pocket

この記事をかいた人

About the author