Web scraping APIは、ウェブページ収集の面倒な部分を代わりに行ってくれます。プロキシを選び、必要に応じてブラウザを実行し、失敗をリトライし、要求したHTMLやデータを返してくれます。URLを添えて1回リクエストを送るだけで、サイトとの間のすべてをサービスが処理します。
このウォークスルーでは、最初のリクエストから小規模で信頼性の高いスクレイパーまでを、ShifterのWeb Scraping APIを例に説明します。手順やパターンは、この種のほとんどのサービスで共通です。リクエストの裏側で何が起きているかを先に知りたい場合は、web scraping APIの仕組みについての解説記事をご覧ください。
ステップ1: APIキーを取得する
すべてのリクエストはAPIキーで認証されます。ShifterのパネルでWeb Scraping APIを開き、次にAPI Keysを開いて、有効なキーをコピーします。
キーはコードの外に保管してください。環境変数に格納することで、リポジトリやスクリーンショットに紛れ込むことがなくなります。
export SHIFTER_SCRAPER_KEY="your-key-here"
ステップ2: 最初のリクエストを送る
APIは単一のエンドポイント https://scrape.shifter.io/v1 です。キーと取得したいページをクエリパラメータとして渡します。
curl "https://scrape.shifter.io/v1?api_key=$SHIFTER_SCRAPER_KEY&url=https://example.com"
レスポンスは、APIのプロキシ経由で取得されたページのHTMLです。基本的なリクエストに必要なのはこれだけです。
ステップ3: ページが必要とする場合はJavaScriptレンダリングを有効にする
多くの現代的なサイトは、ほぼ空のページを送り、コンテンツはJavaScriptでブラウザ内に構築します。取得したHTMLに、ブラウザで見えるはずのデータが含まれていない場合は、render_js=1 を追加してください。するとAPIはヘッドレスブラウザでページを読み込み、レンダリング済みの結果を返します。Shifterでは、レンダリングされたリクエストの料金は通常のリクエストと同じです。
読み込みが遅いページに役立つ、関連する2つの設定があります。
wait_for_cssは、特定の要素が表示されるまで待ってから結果を返すため、データが読み込まれる前のページを受け取ることがなくなります。timeoutは、読み込みが遅いサイトのために時間を長く確保します。
レンダリングは通常の取得より遅いため、必要なページにのみ使用してください。JavaScriptの多いサイトのスクレイピングについてのガイドで、その見分け方を説明しています。
ステップ4: HTMLではなくJSONを取得する
HTMLを自分でパースすることは、多くのスクレイパーが壊れる原因になります。代わりに、extract_rules で欲しいフィールドを記述します。これは、各フィールド名をCSSセレクタとそこから何を返すかにマッピングするJSONオブジェクトです。
output | 返されるもの |
|---|---|
text | 要素のテキスト |
html | 要素の内部HTML |
@href、@src など | 属性の値 |
例えば、{"title": {"selector": "h1", "output": "text"}} は、example.comに対して {"title": "Example Domain"} を返します。多くのページはすでにデータを構造化JSONとして埋め込んでいます。HTMLをパースする代わりにJSON-LDを抽出するについてのガイドで、その活用方法を紹介しています。
ステップ5: エラーを適切に処理する
どんなスクレイパーも、読み込みが遅いサイト、レンダリングされないページ、同時リクエストが多すぎるといった失敗に直面します。APIはステータスコードで何が起きたかを伝えますが、適切な対応はそのコードによって異なります。
| ステータス | 意味 | 対応 |
|---|---|---|
200 | 成功 | レスポンスを使用する |
400、401、403 | リクエスト、キー、またはプラン機能の問題 | 修正する。リトライしても解決しない |
408 | 対象サイトがタイムアウトした | リトライする。必要なら timeout を上げる |
422 | ページのレンダリングに失敗した | リトライする。通常のブラウザでサイトが動作するか確認する |
429 | プランに対して同時リクエストが多すぎる | 待ってからリトライする |
500 | 内部エラー | 短い遅延の後にリトライする |
Shifterでは、失敗したリクエストには課金されません。成功したレスポンス1件につき1クレジットを支払います。APIは回答前に内部的に一部の失敗をリトライすることもありますが、それらは1回の呼び出しとしてカウントされます。
まとめて組み立てる
以下は、上記の5つのステップすべてをラップする小さなPythonヘルパーです。環境変数からキーを読み込み、要求に応じてレンダリングと抽出を追加し、リトライする価値のあるエラーを増加する待機時間とともにリトライし、修正が必要なエラーでは即座に停止します。
import json
import os
import time
import requests
API = "https://scrape.shifter.io/v1"
RETRY = {408, 422, 429, 500} # worth another try after a pause
STOP = {400, 401, 403} # fix the request; retrying will not help
def scrape(url, render_js=False, extract_rules=None, attempts=3, session=None, wait=2.0):
"""Fetch one page through the Web Scraping API; returns text, or parsed JSON with extract_rules."""
session = session or requests.Session()
params = {"api_key": os.environ["SHIFTER_SCRAPER_KEY"], "url": url}
if render_js:
params["render_js"] = 1
if extract_rules:
params["extract_rules"] = json.dumps(extract_rules)
for attempt in range(1, attempts + 1):
response = session.get(API, params=params, timeout=120)
if response.status_code == 200:
return response.json() if extract_rules else response.text
if response.status_code in STOP or attempt == attempts or response.status_code not in RETRY:
raise RuntimeError(f"{url}: HTTP {response.status_code} {response.text[:200]}")
time.sleep(wait * attempt) # back off a little more each time
使い方:
from scrape_api import scrape
html = scrape("https://example.com")
data = scrape("https://example.com", extract_rules={"title": {"selector": "h1", "output": "text"}})
print(data["title"])
このヘルパーのリクエスト構築、リトライ、停止条件については、上記の各ステータスコードに対するシミュレートされたレスポンスを使ってテスト済みです。
リトライロジックに馴染みがない場合は、web scraper向けのリトライとバックオフについてのガイドで、試行ごとに待機時間が増えていく理由を説明しています。
ステップ6: スケールアップする
単一のリクエストが機能するようになったら、規模を拡大するにつれて重要になる3つの要素があります。
- 並行性。 スレッドプールや非同期クライアントを使って、複数のリクエストを同時に送ります。各プランには並行性の上限があります(Shifterではプランに応じて同時20〜500リクエスト)。その範囲内に収め、
429を速度を落とすべき合図として扱ってください。 - ロケーションとプロキシタイプ。
countryパラメータを使うと、特定の国で表示されるとおりにページを取得できます。Growthプラン以上では、premium_proxyが、データセンタートラフィックをブロックするサイト向けに、レジデンシャルIP経由でリクエストをルーティングします。 - セッション。 複数ステップのフローでは、
session_idによってリクエスト間で同じIPとクッキーを維持できます。
データが流れ始めたら、クエリ可能な場所に保存してください。web scraping APIのデータをSQLに移行するについてのガイドで、レスポンスからテーブルまでのクリーンなパイプラインを解説しています。
初心者によくある間違い
- APIキーのハードコーディング。 環境変数またはシークレットマネージャーを使用してください。
- すべてをレンダリングする。 まず通常のリクエストを試し、必要なページのみレンダリングしてください。
- すべてをリトライする。
401は何度試しても失敗し続けます。後で成功する可能性のあるエラーのみリトライしてください。 - HTMLを手動でパースする。 可能な限り、抽出ルールまたは埋め込みJSONを使用してください。
- 並行性の上限を無視する。 並列リクエストが多すぎると、速度が上がるのではなく
429が発生します。
FAQ
web scraping APIとは何ですか?
独自のプロキシとブラウザを通じてウェブページを取得し、リトライやブロックを処理し、1回のリクエストに対してHTMLまたは抽出されたデータを返すサービスです。
web scraping APIを使うにはコーディングの知識が必要ですか?
多少は必要です。1回のリクエストであればcurlを使ってコマンドラインから実行できますが、実際のほとんどのプロジェクトでは、リクエストの送信、エラー処理、結果の保存のために、Pythonなどの言語で書かれた短いスクリプトを使用します。
JavaScriptレンダリングはいつ有効にすべきですか?
レンダリングなしで返されたHTMLに、ブラウザで見えるコンテンツが欠けている場合です。多くのサイトはJavaScriptでページを構築しており、レンダリングを行うとブラウザが表示するとおりのページが返されます。
失敗したリクエストにはクレジットがかかりますか?
Shifterではかかりません。成功したレスポンス1件につき1クレジットが課金され、対象サイトからのエラーを含む失敗したリクエストは無料です。
結論
web scraping APIを使いこなすには、いくつかの習慣に尽きます。キーは環境変数に保管し、まず通常のリクエストから始めて必要な場合のみレンダリングを追加し、HTMLをパースする代わりに抽出ルールでJSONを要求し、後で成功する可能性のあるエラーのみリトライし、プランの並行性を尊重することです。上記のヘルパーは、約20行でこれらすべてをカバーしています。プランと上限については、Web Scraping API料金ページをご覧ください。