JavaScript で描画されるウェブサイトのスクレイピング方法
多くの最新サイトは、ほとんど空の HTML 文書を送り、ブラウザ内の JavaScript でコンテンツを組み立てます。スクレイパーがページを取得して、商品も価格も記事本文も見つからないなら、コンテンツはそこにありますが、後から届くのです。このガイドでは、どの種類のページかを見分ける方法、ブラウザより速い経路があればそれを見つける方法、Python の Playwright で描画済みのページをスクレイピングする方法を示します。最後に、描画されたページにキャプチャが表示された場合の対処についても扱います。
ステップ 1: コンテンツが HTML にあるかを確認する
view-source: を使ってブラウザでページを開くか、素の HTTP リクエストで取得し、画面に見えているテキストの一部をソースから検索してください。よくある結果は三つです。
- テキストがある。 ページはサーバー側で描画されています。素の HTTP クライアントと HTML パーサーで十分です。それらのほうが速く、単純なので、使ってください。
- テキストはないが、JSON の塊がある。 多くのサイトは
__NEXT_DATA__のようなスクリプトタグに状態を埋め込んでいます。その JSON を直接解析してください。 - テキストもなく、JSON の塊もない。 ページは追加のリクエストでコンテンツを読み込んでいます。ページの読み込み中に、DevTools の Network タブを Fetch/XHR で絞り込んで確認してください。
ステップ 2: JSON エンドポイントがあればそれを呼ぶ
ページがデータを特定のエンドポイントから取得している場合、そのエンドポイントを直接呼ぶのが、たいてい最良の選択です。描画されたページよりも小さく、速く、安定しています。リクエストの URL をコピーし、サイトが必要とするヘッダーを確認して、スクリプトから試してください。これはサイトの利用規約が許す場合にのみ行い、サイトが期待するレート制限や認証を尊重してください。文書化されていないエンドポイントは予告なく変わることがあるため、レスポンスの形が変わったときに大きく失敗するように、パーサーを書いてください。
ステップ 3: 必要なときはページを描画する
コンテンツが本当にブラウザを必要とする場合は、ヘッドレスブラウザを動かします。Python では Playwright が良い選択です。次の例は、商品一覧を開き、コンテンツが表示されるのを待ち、各カードのテキストを読み取ります。
from playwright.sync_api import sync_playwright
URL = "https://example.com/products" # スクレイピングを許可されているページ
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(URL, wait_until="domcontentloaded", timeout=60_000)
# データが届いたことを示す要素を待つ。
page.wait_for_selector(".product-card", timeout=30_000)
titles = page.locator(".product-card h2").all_inner_texts()
browser.close()
for title in titles:
print(title)
データが届いたことを示す特定のセレクタを待つほうが、固定の sleep よりはるかに信頼できます。固定の待ち時間は、遅い日には短すぎ、速い日には時間を無駄にします。データが読み込まれた後にだけ現れる要素を選んでください。
ステップ 4: 無限スクロールとページ送りを扱う
一部のページは、スクロールするたびに項目を追加で読み込みます。最下部までスクロールし、項目数が増えるのを待ち、増えなくなったら止めてください。番号付きのページ送りは単純です。次のページのリンクを見つけて、たどり、最後のページで止めます。いつも最大のページ数やスクロール回数を設定し、バグでクローラーが永遠に動き続けないようにしてください。
def scroll_until_done(page, selector: str, max_rounds: int = 20) -> int:
previous = -1
for _ in range(max_rounds):
count = page.locator(selector).count()
if count == previous:
break
previous = count
page.mouse.wheel(0, 4000)
page.wait_for_timeout(1500) # 次のまとまりが読み込まれる時間を与える
return previous
ステップ 5: ブラウザを経済的に使う
描画にはコストがかかります。必要のない画像、フォント、メディアはブロックし、多くのページに一つのブラウザを再利用してください。ページごとに新しいブラウザを起動しないでください。使い終わったページやコンテキストは閉じ、長い実行の間にメモリが増えないようにしてください。
def block_heavy_assets(route):
if route.request.resource_type in ("image", "font", "media"):
route.abort()
else:
route.continue_()
page.route("**/*", block_heavy_assets)
ステップ 6: 描画されたページにキャプチャが出た場合
描画されたページが、コンテンツを表示する前にキャプチャを出すことがあります。そのキャプチャが Scarnox で現在ライブの PopularCaptcha なら、ページから sitekey を読み取り、トークンを要求して、サイトが期待するフォームフィールドにトークンを入れます。その手順は PopularCaptcha の Python ガイドで順に説明しています。他のウィジェットはまだライブではないため、計画を立てる前にキャプチャの種類の解説を確認してください。
ブラウザ自体にも注意してください。明らかに自動化されているヘッドレスブラウザは、少なくなるどころか、より多くのチェックを引き起こすことがあります。注目すべき信号はヘッドレスブラウザの検出を参照し、ページ読み込みは遅く、少なくしてください。
責任を持ったスクレイピング
- 描画したり、そのエンドポイントを呼んだりする前に、サイトの
robots.txtと利用規約を確認してください。 - レート制限は低く保ち、各ページを一度だけ取得するようにキャッシュしてください。
- 適法な根拠がない限り、個人データはスクレイピングしないでください。
- サイトがアクセスを制限している場合は、止まってください。制限を越えようとしないでください。
次のステップ
無料トライアルクレジットから始められ、クレジットカードは不要です。アカウントを作成して、自分が所有するページで PopularCaptcha のフローをテストしてください。現在の料金は料金ページをご覧ください。