セレンウェブスクレイピング:実践的なPythonガイド
Lead Scraping Automation Engineer
TL;DR:
- SeleniumはWebDriverプロトコルを通じて実際のChromeを操作するため、JavaScriptで構築されたページのDOMを見ることができる。これは通常のHTTPリクエストでは受け取れない内容である。
- 以下のライブ実行では、空のコンテナを持つデモページから10の引用をすべて読み取る。この同じページは、
requests.getだけではゼロ行を返す。 - 現代のSeleniumは自動的にドライバーを解決する。Selenium ManagerがChromeDriverをインストールされているChromeにマッチさせるため、
webdriver.Chrome(options=...)は手動でのダウンロードなしで動作する。 - Seleniumの実際のコストは運用に関するものであり、すべてのワーカーは自身のIPから退出する完全なブラウザであるため、スケールするのが難しく、アンチボットシステムによるレート制限が簡単に働く。
- Honest-limitsのピボットは同じURLをScrapeless Universal Scraping APIに送り、サーバーサイドでページをレンダリングし、ブラウザを実行したりスケールさせたりする必要なく完成したHTMLを返す。
- 無料プランでScrapeless APIキーを取得し、自分で両方の部分を実行する。
Seleniumがスクレイピングのためにすること
Seleniumは実際のブラウザを自動化する。あなたのPythonコードはWebDriverプロトコルを使ってChromeDriverに話し、ChromeDriverはChromeを操作し、Chromeはブラウザがするべきことを行う:ページを要求し、スクリプトを実行し、DOMを構築する。最後の部分がスクレイパーがそれを使う理由である。クライアント側でコンテンツを構成するページ—フレームワークによってレンダリングされたプロダクトグリッド、バックグラウンドリクエストを通じて届くフィード—は生のHTMLでは空であり、スクリプトが実行された後にのみ完全となる。Seleniumはその実行を待機し、完成したページを返す。
トレードオフは重さである。Seleniumはセッションごとに実際のChromeを実行し、メモリと起動時間を消費し、リクエストはあなたのマシンのIPから出る。少数のページに対しては問題ない。 このガイドではまず動作するSeleniumスクレイパーを構築し、その後、独自のブラウザを実行することが無駄になるポイントとそれについてどう対処すべきかを説明する。ここにあるすべてのコードパスはライブページに対して実行される。
インストール
SeleniumのPythonバインディングをインストールする:
bash
pip install selenium
手動でChromeDriverをインストールする必要はない。バージョン4.6以降、SeleniumはSelenium WebDriverツールをSelenium Managerと共に提供しており、これがあなたのChromeを検出し、最初の使用時に一致するドライバーを解決する。最近のGoogle Chromeがインストールされている必要があり、バインディングが残りを処理する。
設定
このガイドの後のピボットのために、環境にあなたのScrapeless APIキーを配置し、それがソースコードに残らないようにする:
bash
export SCRAPELESS_API_KEY="your_scrapeless_api_key"
基本的な実装:JavaScriptページをレンダリングする
Seleniumをクライアント内で行を構築するページに向け、その要素はナビゲーションが戻ってきたときに存在する。以下のデモは空のコンテナを持ち、それをJavaScriptでポピュレートする;生のマークアップは.quoteノードを持たず、ブラウザがレンダリングしたDOMは十のノードを持っているのは、Chromeが最初にスクリプトを実行したためであり、HTMLの解析とスクリプトモデルに従っているからである。
python
import tempfile
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
opts = Options()
opts.add_argument("--headless=new")
opts.add_argument("--no-sandbox")
opts.add_argument("--disable-dev-shm-usage")
opts.add_argument(f"--user-data-dir={tempfile.mkdtemp()}")
driver = webdriver.Chrome(options=opts) # Selenium Managerがドライバーを解決する
try:
driver.get("https://quotes.toscrape.com/js/")
quotes = driver.find_elements(By.CSS_SELECTOR, ".quote")
print("JSページ上の引用ブロックの数:", len(quotes))
print("最初の著者:", quotes[0].find_element(By.CSS_SELECTOR, ".author").text)
finally:
driver.quit()
この実行はカウントと最初のレコードを出力する:
text
JSページ上の引用ブロックの数: 10
最初の著者: アルバート・アインシュタイン
--headless=newフラグはChromeを可視ウィンドウなしで実行し、これはサーバー上で求められるものである。--no-sandboxと--disable-dev-shm-usageはChromeをコンテナや制約のある環境内で安定させ、使い捨ての--user-data-dirが各実行に独自のプロファイルを与えるため、並行セッションが衝突しないようにする。
高度なパターン:待機と選択
driver.getはドキュメントが読み込まれた時点で戻るが、スクリプトで構築された要素は少し後に現れるかもしれない。固定間隔でスリープするのではなく、特定の条件を待機する。WebDriverWaitをexpected_conditionsと組み合わせることで、指定した要素が存在するまでブロックされるため、データが存在する瞬間にスクレイプが開始され、それより早くは始まらない:
python
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".quote"))
)
安定したセレクタをハッシュ化されたCSSクラスよりも好む: id、data-* 属性、またはセマンティックタグは、スタイリングクラスの名前変更を伴うデザインの再構築に耐えます。ページをページングする場合は、「次へ」リンクの href を読み取り、それに従ってページ番号を推測するのではなく、実際のリンクを辿ります。
無料プランでAPIキーを取得: app.scrapeless.com
正直な限界とピボット
SeleniumはJavaScriptをうまくレンダリングしますが、ブラウザを安価に実行したり、あなたのトラフィックが目立たなくすることはできません。各SeleniumワーカーはフルChromeであり、多くのページにスケールするということは、ブラウザとそれに必要なメモリをスケールすることを意味し、すべてのリクエストはあなた自身のIPから出ます。これは、混雑しているサイトがレート制限やチャレンジを行う可能性があります。Seleniumには管理されたボット対策チャレンジに対する組み込みの回答はなく、与えられたページをレンダリングし、決して到達しないページは何もレンダリングされません。
Scrapeless Universal Scraping APIは、その運用の半分をあなたのマシンから取り除きます。js_render を有効にしたURLを送り、管理されたボット対策処理と回転住宅出口の背後でサーバーサイドにページをレンダリングし、完成したHTMLをdataフィールドに返します。ブラウザを立ち上げる必要はなく、リクエストはあなたのIPからではありません。返されたHTMLは、Seleniumのページソースを解析するのと同じように解析します:
python
import os, re, json, requests
resp = requests.post(
"https://api.scrapeless.com/api/v2/unlocker/request",
headers={"x-api-token": os.environ["SCRAPELESS_API_KEY"], "Content-Type": "application/json"},
json={"actor": "unlocker.webunlocker", "input": {"url": "https://quotes.toscrape.com/js/", "js_render": True}},
timeout=120,
)
resp.raise_for_status()
html = resp.json()["data"]
authors = re.findall(r'<small class="author">(.*?)</small>', html)
print("Universal Scraping API経由でレンダリングされた引用ブロック:", html.count('class="quote"'))
print("抽出された著者:", len(authors))
print("最初の著者:", authors[0])
単一のリクエストは、サーバーサイドで同じレンダリングされたページを返します:
text
Universal Scraping API経由でレンダリングされた引用ブロック: 10
抽出された著者: 10
最初の著者: アルバート・アインシュタイン
経験則: ターゲットを制御し、ボリュームが小さい場合はSeleniumを保持し、作業が操作であるときにAPIにフェッチを移動します — 多くのページ、ブロックされたIP、またはSeleniumがクリアできないチャレンジ。解析コードは変更されず、HTMLのソースだけが変更されます。
トラブルシューティング
ドライバーのバージョンエラーは、ほぼ常にChromeが更新されて古いドライバーが残っていることを意味します; Selenium 4.6以降では、Selenium Managerが現在のドライバーを自動的に解決するので、PATHから手動でピン留めされたChromeDriverを削除することで通常は解決します。通常のブラウザで表示できるページで空の結果がある場合、それはdriver.getが返された後にコンテンツが到着したことを意味します — 必要なセレクタの上にWebDriverWaitを追加して下さい。ネットワークが静寂になることのないページでハングアップする実行は、間違った条件で待っていたことを意味します; ネットワークのためではなく、要素のために待って下さい。
作業はサイトの明示された境界内で行って下さい。その利用規約とロボット排除プロトコルファイルを読み、公開ページのみをリクエストし、同時実行性を控えめに維持します — 同じ規律がドキュメントオブジェクトモデルに関するガイドで扱われています。発見と抽出のための広範な旅行のために、スクレーパーをゼロから構築するに関するウォークスルーは、これとよく組み合わせられます。
結論
Seleniumは、ページが実際のブラウザを必要とする場合にその地位を確保します: WebDriverプロトコルを通じてChromeを駆動し、スクリプトを実行し、レンダリングされたDOMを手渡します — マークアップに何も含まれていないページからの10の引用。稼働が割に合わなくなるのは、そのブラウザ周辺の操作です: セッションのスケーリングによるメモリ、自身のIPの露出、そしてクリアできないチャレンジ。そこに至るまで、Scrapeless Universal Scraping APIを通じて同じURLが、実行するブラウザなしでレンダリングされたHTMLを返し、解析はそのまま保たれます。スケールする前に、必要なリクエストボリュームを価格ページで確認してください。
私たちのコミュニティに参加して、無料プランを取得し、スクレイパーを構築している他の開発者と情報を交換しましょう: Discord · Telegram。
FAQ
Q: Seleniumを使用するためにChromeDriverをダウンロードする必要がありますか?
いいえ。Selenium 4.6以降はSelenium Managerをバンドルしており、インストールされているChromeを検出し、初回使用時に対応するChromeDriverを解決するので、webdriver.Chrome(options=...)は手動でドライバーをダウンロードしなくても動作します。
Q: Seleniumが見つけられる要素をrequestsが見つけられないのはなぜですか?
Seleniumは実際のブラウザを実行し、ページのJavaScriptを実行してDOMを構築するため、スクリプト生成の要素はクエリを行う時点で存在します。単純なHTTPクライアントは、サーバーの初期マークアップのみを受け取るため、クライアントレンダリングされたページにはその内容が含まれていません。
Q: SeleniumからUniversal Scraping APIに切り替えるべきタイミングはいつですか?
運用上の難易度が高くなったとき、すなわち、多くのページを取得する必要がある、IPがレート制限される、またはSeleniumがクリアできない管理されたアンチボットチャレンジがある場合に切り替えます。APIはサーバー側でレンダリングし、完成したHTMLを返すため、パースを維持しつつブラウザの fleet を不要にできます。
Q: ページの後に読み込まれるコンテンツを待つにはどうすればよいですか?
WebDriverWaitとexpected_conditionsを使用して、特定のセレクターが存在するまでブロックします。固定のtime.sleepではなく、要素が存在する瞬間からスクレイプが開始されるため、推測した遅延よりも速く、信頼性も高いです。
Q: Seleniumを使ったスクレイピングは合法ですか?
公開データのスクレイピングは一般的に許可されていますが、責任はあなたにあります: サイトの利用規約とロボット指令を尊重し、公開ページのみを収集し、処理の根拠がない個人データを避け、リクエストレートを控えめに保ってください。
Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。



