キャプチャを越えて検索結果をスクレイピングする方法(Python ガイド、2026)
検索結果ページは、スクレイパーが最初にキャプチャに遭遇する場所の一つです。サイトは一つのアドレスからのリクエストの集中を見て、チャレンジを返し、そのチャレンジが通過されるまで結果を返しません。キャプチャを越えて検索結果をスクレイピングするには、スクリプトに三つのステップが必要です。解析の前にチャレンジを検出し、1回の API 呼び出しで解決し、トークンを送信してサイトが本物の結果ページを返すようにすることです。
このガイドでは、requests と BeautifulSoup を使った Python でそのフローを示します。Scarnox が今日解決する種別であるプロキシなしの PopularCaptcha ウィジェットを表示するページを扱います。無料トライアルクレジットから始めましょう。クレジットカードは不要です。まずは自分が所有するページでコードを試してください。
チャレンジの見た目
検索ページは通常、ウィジェットをフォームの中に置きます。ウィジェットのコンテナは data-sitekey 属性を持ち、フォームはサイトに向けて送信されます。
<form action="/search/verify" method="post">
<input type="hidden" name="q" value="web scraping">
<input type="hidden" name="lang" value="en">
<div class="h-captcha" data-sitekey="YOUR-SITEKEY-UUID"></div>
<button type="submit">Continue</button>
</form>
このマークアップから必要なものは三つです。sitekey、フォームの action の URL、そしてトークンと一緒に送り返す必要がある隠しフィールドです。以下のヘルパーは三つすべてを読み取るため、値をハードコードしなくても動きます。
ターゲットのウィジェットが別のキャプチャ種別なら、キャプチャの種類を参照してください。reCAPTCHA と Cloudflare Turnstile のサポートは近日公開予定のため、ここのコードは PopularCaptcha だけを扱います。
ソルバーの呼び出し
解決リクエストは、Bearer ヘッダーにあなたのキーを付けて Scarnox API に送られます。呼び出しはトークンの準備ができるまでブロックするため、ポーリングのループはありません。
import time
from urllib.parse import urljoin
import requests
from bs4 import BeautifulSoup
API_KEY = "scarnox_YOURAPIKEY"
SEARCH_URL = "https://search.example.com/search"
session = requests.Session()
session.headers["User-Agent"] = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36"
)
def solve(sitekey: str, page_url: str) -> str:
r = requests.post(
"https://api.scarnox.com/api/tasks/create",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"captcha_type": "PopularCaptchaTaskProxyless",
"site_key": sitekey,
"site_url": page_url,
},
timeout=185, # トークンの準備ができると呼び出しが返る
)
data = r.json()
if data.get("errorId") != 0:
raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
return data["solution"]["token"]
解決に失敗すると errorId が 0 以外になり、その分の課金はありません。リトライについてはキャプチャソルバーのエラー処理で扱っています。
ページを取得してキャプチャを通す
取得関数は、まずウィジェットがあるかを確認します。なければ HTML をそのまま返します。あれば、チャレンジを解決し、同じ隠しフィールドでフォームを組み直して送信します。
def fetch_results(query: str, page: int = 1) -> str:
resp = session.get(SEARCH_URL, params={"q": query, "page": page}, timeout=30)
soup = BeautifulSoup(resp.text, "html.parser")
widget = soup.select_one("[data-sitekey]")
if widget is None:
return resp.text # このページにはチャレンジがない
form = widget.find_parent("form")
if form is None:
raise RuntimeError("Captcha widget is not inside a form")
token = solve(widget["data-sitekey"], resp.url)
payload = {
field["name"]: field.get("value", "")
for field in form.select("input[name]")
}
payload["h-captcha-response"] = token
payload["g-recaptcha-response"] = token
action = urljoin(resp.url, form.get("action") or resp.url)
verified = session.post(action, data=payload, timeout=30)
if "data-sitekey" in verified.text:
raise RuntimeError("Challenge still shown after submit; token may be rejected")
return verified.text
ここで重要な点は二つあります。site_url は、ベアの検索エンドポイントではなく、キャプチャが実際に配信されている URL(リダイレクトを含む resp.url)です。また、セッションは GET と POST の間でクッキーを保持します。多くのサイトはトークンを受け入れるためにこれを必要とします。
トークンの有効期限は約2分なので、解決はフォームを読んだ直後に行い、前には行いません。このウィンドウについての詳細はキャプチャトークンの有効期限を参照してください。
結果を解析する
本物の結果ページが返されたら、解析は通常の HTML 作業です。以下のセレクタはプレースホルダーです。DevTools でページを開き、実際のセレクタに置き換えてください。
def parse_results(html: str) -> list[dict]:
soup = BeautifulSoup(html, "html.parser")
rows = []
for item in soup.select("div.result"):
link = item.select_one("a[href]")
heading = item.select_one("h3")
if link and heading:
rows.append({
"title": heading.get_text(strip=True),
"url": link["href"],
})
return rows
if __name__ == "__main__":
for page in range(1, 4):
html = fetch_results("web scraping", page)
for row in parse_results(html):
print(row)
time.sleep(5) # ページ間のリクエストのペースを守る
各ページの出力は別々に保ってください。ページが0件を返したら、クエリに結果がなかったと考える前に、ウィジェットがあるかを確認してください。
責任を持ったスクレイピング
キャプチャはシグナルであり、抜け道ではありません。どの検索サイトに対してもこれを実行する前に、次を確認してください。
- robots.txt と利用規約を読む。 多くの検索サイトは、自動化されたクエリを禁止しています。規約が禁じている場合は、スクリプトを実行しないでください。
- レートを制限する。 上の
time.sleep(5)は目標ではなく下限です。チャレンジが増えたら、さらに速度を落としてください。 - 保存するものを制限する。 検索結果には、名前、メールアドレス、その他の個人データが含まれることがあります。必要なフィールドだけを保存し、残りは削除してください。
- 可能なら公式 API を優先する。 サイトが提供している場合、それは HTML のスクレイピングより信頼性が高く、通常は安価です。
法的な面についてはウェブスクレイピングは合法か?を、そもそもブロックを避けることについてはブロックされずにスクレイピングするを参照してください。
料金
Scarnox は成功した解決ごとに課金し、失敗した解決は無料です。料金は現在の料金ページをご覧ください。無料トライアルクレジットから始めましょう。クレジットカードは不要です。