非同期Pythonウェブスクレイピング:aiohttpとScrapelessを使用して10,000以上のURLにスケールアップ
Advanced Bot Mitigation Engineer
主なポイント:
- 非同期はI/Oバウンドのスクレイピングで同期を約10〜100倍上回る。 asyncioのイベントループは1つのPythonスレッドで数百の進行中のHTTPリクエストを同時に処理できる。一方、同期の場合は各ソケット読み込みでブロックし、URLごとにフルレイテンシーがかかる。
- aiohttpは公式の非同期HTTPクライアントである。 単一の
aiohttp.ClientSessionが接続プール、キープアライブ、クッキー、およびタイムアウトを保持する。これをasyncio.gatherと組み合わせてファンアウトすることができ、asyncio.Semaphoreを使用してホストごとの上限を設定できる。 - Scrapelessの住宅プロキシが非同期の取得をルーティングする。 1つのプロキシURLは
aiohttp.ClientSession(... proxy=...)に直接接続し、各リクエストに異なる住宅IPを割り当て、ユーザー名に組み込まれた国コードで出口の地理を特定する。 - ScrapelessスクレイピングブラウザはJSレンダリングされたマイノリティを処理する。 aiohttpがJSアプリシェル(Next.js、React、Vue)として返すページは、Scrapeless Python SDKとPlaywrightの非同期APIを介して非同期Pythonから接続されたクラウドブラウザセッションにエスカレーションされる。
- 失敗はバンド外に留まる。
asyncio.gather(return_exceptions=True)を使用すると、1つの不良URLが他のファンアウトをキャンセルしない。失敗したURLは別途レビューのためにデッドレターリストに送られ、インラインループには入らない。 - 無料で始められる。 新しいScrapelessアカウントには無料のスクレイピングブラウザランタイムが含まれている — Scrapelessでサインアップ。
イントロダクション:なぜ非同期か、シリアルスクレイピングのコスト
srequestsを使用する同期のPythonスクレイパーは、各ソケットの読み込みでスレッドをブロックする。1,000の製品ページを500msごとにスクレイプすると、ウォールクロックコストは約500秒である — レイテンシーはフルで、1つのURLずつ支払われる。
asyncioはこれを逆転させる。イベントループはソケットが進行中の間に制御を放棄し、次のコルーチンが独自のリクエストを開始できるようにし、1つのスレッド上で数百の取得を織り込む。同じ1,000ページ — ホストあたり10の同時リクエストに制限されて — は約50秒でクリアされる。同じハードウェア、同じPython、同じデータ。
注意点:非同期スクレイピングには、同期版では見られない2つの失敗モードがある。パイプラインの失敗、1つのコルーチン内で投げられた例外が全体のgatherをキャンセルする場合、そしてターゲット側の圧力、プロキシレイヤーがIP間で出口を分散できないと、進行中のプールが攻撃と区別できない場合である。
このガイドでは両方について説明する。HTTP層はaiohttpと195か国以上のScrapeless住宅プロキシを使用している。JSレンダリング層は、Scrapeless Python SDKとPlaywrightの非同期APIを使用して非同期Pythonから接続されるScrapelessスクレイピングブラウザにエスカレーションされる。
これでできること
- 静的カタログを大規模にクロールする。 書籍、記事、サイトマップ、レンダリングされたHTMLを提供するすべてのもの — 非同期ファンアウトにより長時間のクロールを短時間に変えることができる。
- 同時フィードを引く。 RSS、JSON API、サイトマップインデックス;限定された同時実行で数百のエンドポイントにファンアウトする。
- 地域ごとの価格監視を行う。 Scrapelessの出口を米国、英国、ドイツ、日本に固定し、同じ製品ページを複数の地域から並行して引き出す。
- 自サイトを監査クロールする。 非同期で10,000のURLを持つサイトマップを数分でクリアし、死リンクや遅いパスをレポートする。
- 下流のパイプラインを充実させる。 非同期層がレンダリングされたHTMLまたはJSONをそのままPostgres、Snowflake、Kafkaに流し込み、スレッドプールのボトルネックなしで行う。
- 選択的にエスカレーションする。 約70%のページがレンダリングされたマークアップを出荷している間、aiohttpを安価なHTTPに保ち、JSが重いマイノリティーのためにのみクラウドブラウザセッションを起動する。
Scrapelessでは、適用される法律、規制、ウェブサイトのプライバシーポリシーを厳格に遵守しながら、公開されたデータにのみアクセスします。この投稿の内容は、デモの目的のみで使用されます。
なぜ非同期スクレイピングにScrapelessを選ぶのか
Scrapelessスクレイピングブラウザは、ウェブクローラーやAIエージェント向けに設計されたカスタマイズ可能で検出防止機能を備えたクラウドブラウザであり、Scrapelessの住宅プロキシがその下にあるプロキシレイヤーである。特に非同期Pythonパイプラインに対して、この組み合わせは次のような利点をもたらす:
- 195か国以上の住宅プロキシが、
aiohttp.ClientSession(... proxy=...)に直接ドロップされる単一のHTTPプロキシURLとして提供される。 - リクエストごとのジオピンニング — プロキシの資格情報に埋め込まれた国コードにより、リクエストごとのハンドシェイクコストやコルーチンセッションの再構築コストは発生しない。
- スティッキーセッションオプション — 複数のステップのログインやページネーションを通じて同じIPが必要なフローのために、他のもののために回転IPを使用する。
- クラウド側のJSレンダリング — ページがReact/Vue/Next.jsに過剰に依存している場合は、Python SDKがPlaywrightの非同期APIで接続するための
browser_ws_endpointを生成する。 - 両方の階層に対して1つのAPIキー — プロキシとスクレイピングブラウザは、同じScrapelessアカウントに対して請求される。
無料プランでAPIキーを取得するには、Scrapelessへどうぞ。
前提条件
- Python 3.10 以上
- Scrapeless アカウントと API キー — app.scrapeless.com でサインアップ
async/awaitとイベントループモデルに慣れていること- ターミナル
ステップ 1 — asyncio、aiohttp、および Scrapeless SDK をインストールする
aiohttp はビルトインの asyncio サポートを提供します。scrapeless SDK はステップ 6 のエスカレーションレベルのためにクラウドブラウザセッションを生成します。Playwright の非同期 API は、Scrapeless スクレイピングブラウザを操作するための公式な非同期 Python の方法です:
bash
pip install aiohttp scrapeless playwright
playwright install chromium
playwright install chromium はローカル CDP クライアントを一度ダウンロードしますが、実際のレンダリングは Scrapeless のクラウドで実行されます — ローカルの Chromium はプロトコルスピーカーとしてのみ機能します。
ステップ 2 — Scrapeless の資格情報を設定する
Scrapeless API キー、チャンネル ID、住宅プロキシチャンネルのパスワードを環境変数としてエクスポートします。これらはすべて、app.scrapeless.com の Scrapeless ダッシュボードの Proxies → Residential セクションに表示されます — Generate をクリックすると、ダッシュボードにコロン区切りの文字列が <GATEWAY>:<PORT>:<CHANNEL_ID>-proxy-country_US-r_10m-s_<SESSION_ID>:<PASSWORD> の形式で印刷されます:
bash
export SCRAPELESS_API_KEY="your_api_token_here"
export SCRAPELESS_CHANNEL_ID="your_channel_id" # ユーザー名の最初に印刷されます
export SCRAPELESS_PROXY_PASS="your_channel_password"
export SCRAPELESS_PROXY_GATEWAY="gw-us.scrapeless.io" # 地域ゲートウェイについては下記を参照
地域ゲートウェイ: gw-us.scrapeless.io(アメリカ)、gw-eu.scrapeless.io(ヨーロッパ)、gw-ap.scrapeless.io(アジア太平洋)。ハンドシェイクのレイテンシーを低く保つために、実行時に最も近いゲートウェイを選択してください; どのゲートウェイを使用しても、出口国は country_<CC> ユーザー名パラメータによって管理されます。ポートはすべて 8789 です。
住宅プロキシのユーザー名は、次の4つのパラメータから構成されています:
<CHANNEL_ID>— あなたのチャンネル識別子(ダッシュボードのユーザー名の最初に印刷されます)。country_<CC>— 2文字形式の国の識別子。Scrapeless ではcountry_US、country_UK、country_DE、country_JPなどが使用されます(注意:UK、ISO のGBではありません)。r_<duration>— スティッキーセッションの回転間隔(例:r_10mは IP を10分間保持します)。s_<SESSION_ID>— スティッキーセッションの識別子; 同じs_<id>をリクエスト間で再利用して、同じ IP を持続時間のウィンドウに保持します。
r_ と s_ を落とすと、回転 IP (リクエストごとに新しい住宅 IP)になります。ログイン後のページネーショントラバースなど、セッションの継続性が必要なフローではそれらを保持してください。
ステップ 3 — 基本:aiohttp + Scrapeless プロキシを使用した単一非同期フェッチ
最小限の機能を持つ非同期スクレイパー。1つの ClientSession、1つの GET、住宅プロキシを介して返される1つの HTML ペイロード:
python
import asyncio
import os
import aiohttp
PROXY = (
f"http://{os.environ['SCRAPELESS_CHANNEL_ID']}-proxy-country_US"
f":{os.environ['SCRAPELESS_PROXY_PASS']}"
f"@{os.environ['SCRAPELESS_PROXY_GATEWAY']}:8789"
)
async def fetch(session: aiohttp.ClientSession, url: str) -> str:
timeout = aiohttp.ClientTimeout(total=30)
async with session.get(url, proxy=PROXY, timeout=timeout) as resp:
resp.raise_for_status()
return await resp.text()
async def main() -> None:
async with aiohttp.ClientSession() as session:
html = await fetch(session, "https://books.toscrape.com/")
print(f"Fetched {len(html):,} chars via US residential egress")
if __name__ == "__main__":
asyncio.run(main())
このスニペットが早い段階で固定する 3 つのこと:
ClientSessionは一度作成され、再利用されます。 各session.get(...)は同じ接続プールを共有します — リクエストごとにセッションを再作成すると、非同期の目的が失われます。- プロキシ URL はリクエストごとに渡されます、セッションごとではありません。 それにより、同じ
ClientSessionが異なる国を通じて異なるリクエストをルーティングできるようになります。 ClientTimeout(total=30)が各リクエストの制限を設定します。単一のハング接続が残りの処理をブロックすることはできません。
ステップ 4 — 高度:asyncio.gather とセマフォのキャップでの同時フェッチのスケール
同時性の制限なしに 100 の URL にファンアウトすることは、スクレイパーが 10 秒以内にブロックされる方法です。公式なパターンは、ホストごとの飛行中のリクエストを制限するための asyncio.Semaphore です:
python
import asyncio
import os
import aiohttp
PROXY = (
f"http://{os.environ['SCRAPELESS_CHANNEL_ID']}-proxy-country_US"
f":{os.environ['SCRAPELESS_PROXY_PASS']}"
f"@{os.environ['SCRAPELESS_PROXY_GATEWAY']}:8789"
)
# ホストごとの同時リクエストを 5 に制限します。ターゲットによって調整可能です — 公共カタログは
# より高い処理を許容し、ボット対策が施されたソースはより低くした方がよいです。
PER_HOST = asyncio.Semaphore(5)
async def fetch(session: aiohttp.ClientSession, url: str) -> str:
async with PER_HOST:
timeout = aiohttp.ClientTimeout(total=30)
async with session.get(url, proxy=PROXY, timeout=timeout) as resp:
plaintext
resp.raise_for_status()
return await resp.text()
async def main() -> None:
urls = [
f"https://books.toscrape.com/catalogue/page-{n}.html"
for n in range(1, 51) # 50 カタログページ
]
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
pages = await asyncio.gather(*tasks)
print(f"取得したページ数: {len(pages)}、合計 {sum(len(p) for p in pages):,} 文字")
if __name__ == "__main__":
asyncio.run(main())
asyncio.Semaphore(5) は、負荷を支える行です。これがないと、asyncio.gather は50のコルーチンを同時に起動し、ゲートウェイはそれらの半分をレート制限または拒否します。これを使うと、同時に5つだけが進行中になり、残りはスロットが空くまでイベントループで待機します。
マルチホストのファンアウトには、オリジンごとに1つのセマフォを作成し、ホスト名でキー付けします—これにより、1つのオリジンでのスタールは他のオリジンに対する取得を妨げません。
APIキーを取得するには:
ステップ5 — パイプラインをブロックせずに失敗を処理する
コルーチン内の raise_for_status() は、全体の gather をキャンセルし、他の進行中の結果を失わせます。2つの防御策:
防御策1: return_exceptions=True。 gather に例外を値としてキャプチャするように指示し、伝播させません。パイプラインはどちらにしても終了します; 呼び出し元は後でどのURLに対処するかを決定します。
防御策2: デッドレターリスト。 失敗したURLを別の構造に収集して別途レビューします。失敗処理はオフバンドで行い—成功と失敗のパスが交差しない場合、非同期パイプラインは清潔に保たれます。
python
import asyncio
import json
import aiohttp
async def fetch_safe(session, url):
try:
async with session.get(
url, timeout=aiohttp.ClientTimeout(total=30)
) as resp:
resp.raise_for_status()
return {"url": url, "html": await resp.text()}
except (aiohttp.ClientError, asyncio.TimeoutError) as exc:
return {"url": url, "error": repr(exc)}
async def main(urls):
async with aiohttp.ClientSession() as session:
results = await asyncio.gather(
*(fetch_safe(session, u) for u in urls)
)
ok = [r for r in results if "html" in r]
failed = [r for r in results if "error" in r]
print(f"成功: {len(ok)} 失敗: {len(failed)}")
# 別途レビューのためのデッドレターファイル — パイプラインは失敗でブロックしない
with open("dead_letter.jsonl", "w", encoding="utf-8") as f:
for r in failed:
f.write(json.dumps(r) + "\n")
注目すべき点:
- エラーのエンベロープ(
{"url": ..., "error": ...})は、成功のエンベロープと同じ形をしており、異なるキーだけが異なる。下流の消費者は、例外テキストを解析することなく、どのキーが存在するかに基づいて分岐します。 aiohttp.ClientErrorは一般的な失敗面(接続のドロップ、形式が不正なレスポンス、DNSの問題)をカバーします;asyncio.TimeoutErrorはClientTimeoutによって発生します。両方をキャッチすることで、実世界の非同期スクレイピングの約95%をカバーできます。
このコードが意図的に行わないこと: 成功のパスの中で失敗したURLを再発行することはありません。デッドレター処理は別の実行に属し—異なるプロキシ国、異なる同時実行制限、またはステップ6のクラウドブラウザ階層で行われます。これをインラインで混ぜると、1つの非同期スクレイパーが2つの交差する制御フローに変わり、バグはその交差に生じます。
ステップ6 — JSレンダリングされたページを Scrapeless Scraping Browser にエスカレートする
aiohttp は、オリジンが送信するバイトを返します。Next.js、React、および Vue アプリの場合、これらのバイトは空の <div id="root"> とスクリプトタグで構成され—実際のコンテンツはクライアントサイドで描画されます。プレーンHTTPではそれをレンダリングできませんが、クラウドブラウザでは可能です。
最もクリーンなエスカレーションパターン: aiohttp をレンダリングされたHTMLを返すページの約70%に保持し、JSレンダリングされた少数を Scrapeless Scraping Browser にエスカレートします。Python SDKはクラウドブラウザセッションを作成し、browser_ws_endpoint を公開します; Playwright の非同期APIは、Chrome DevToolsプロトコルを介してこれに接続します。
python
import asyncio
from scrapeless import Scrapeless
from scrapeless.types import ICreateBrowser
from playwright.async_api import async_playwright
async def render_via_cloud_browser(url: str, country: str = "US") -> str:
client = Scrapeless() # 環境変数から SCRAPELESS_API_KEY を読み取ります
session = client.browser.create(
ICreateBrowser(proxy_country=country, session_ttl=240)
)
async with async_playwright() as p:
browser = await p.chromium.connect_over_cdp(session.browser_ws_endpoint)
context = browser.contexts[0] if browser.contexts else await browser.new_context()
page = context.pages[0] if context.pages else await context.new_page()
await page.goto(url, wait_until="networkidle", timeout=60_000)
html = await page.content()
await browser.close()
return html
非同期のメイン関数を定義します:
python
async def main():
# quotes.toscrape.com/js/ は「JSが必要な」サンドボックスの基準です。
# プレーンHTTPでは0の引用要素が返され、クラウドレンダリングでは10が返されます。
html = await render_via_cloud_browser("https://quotes.toscrape.com/js/")
print(f"描画された文字数: {len(html):,} 文字(ポストペイントDOMを含む)")
if __name__ == "__main__":
asyncio.run(main())
session.browser_ws_endpoint は wss://browser.scrapeless.com/...?token=... のURLです。Playwrightの connect_over_cdp はそのエンドポイントにCDPを話しかけ、レンダリングはローカルマシンではなくScrapelessのクラウドで行われます。ローカルの playwright install chromium ステップはプロトコルクライアントだけです。
session_ttl=240 はセッションを4分間生かし続けます — 単一ページでのマルチステップトラバーサルには十分です。長時間のクローリングの場合は、URLごとまたは論理作業単位ごとに新しいセッションを生成します;クラウドセッションは作成が安価です。
ステップ 7 — すべてを統合する:階層化された非同期スクレイパー
現実的な非同期スクレイピングパイプラインの形は HTTP優先、ブラウザ二次 です:aiohttpを試し、空の応答やブロックされた応答をScrapeless Scraping Browserにエスカレートします。二つの層は同じ同時実行制限を共有しますが、別々のセマフォで生きています — クラウドブラウザセッションはHTTPリクエストよりも少ないです。
python
import asyncio
import os
import aiohttp
from scrapeless import Scrapeless
from scrapeless.types import ICreateBrowser
from playwright.async_api import async_playwright
PROXY = (
f"http://{os.environ['SCRAPELESS_CHANNEL_ID']}-proxy-country_US"
f":{os.environ['SCRAPELESS_PROXY_PASS']}"
f"@{os.environ['SCRAPELESS_PROXY_GATEWAY']}:8789"
)
HTTP_LIMIT = asyncio.Semaphore(10) # aiohttp層
BROWSER_LIMIT = asyncio.Semaphore(3) # クラウドブラウザ層
async def http_fetch(session: aiohttp.ClientSession, url: str) -> str | None:
async with HTTP_LIMIT:
try:
async with session.get(
url, proxy=PROXY,
timeout=aiohttp.ClientTimeout(total=30),
) as resp:
resp.raise_for_status()
return await resp.text()
except (aiohttp.ClientError, asyncio.TimeoutError):
return None
async def browser_fetch(client: Scrapeless, url: str) -> str:
async with BROWSER_LIMIT:
session = client.browser.create(
ICreateBrowser(proxy_country="US", session_ttl=240)
)
async with async_playwright() as p:
browser = await p.chromium.connect_over_cdp(session.browser_ws_endpoint)
context = (
browser.contexts[0] if browser.contexts
else await browser.new_context()
)
page = await context.new_page()
await page.goto(url, wait_until="networkidle", timeout=60_000)
html = await page.content()
await browser.close()
return html
from urllib.parse import urlparse
# (a) JSが強いホストは常にエスカレートする — 最も信頼性の高いシグナル。
JS_HEAVY_HOSTS = {"quotes.toscrape.com"}
def should_escalate(url: str, html: str | None) -> bool:
# (a) アロウリストヒット — 明示的なJSが強いホスト。
if urlparse(url).hostname in JS_HEAVY_HOSTS:
return True
# (b) ポストパースシグナル — 空のボディまたは認識可能なアプリシェル。
if html is None or len(html) < 2000 or '<div id="root"></div>' in html:
return True
return False
async def scrape_one(http_session, client, url):
html = await http_fetch(http_session, url)
tier = "http"
if should_escalate(url, html):
tier = "browser"
html = await browser_fetch(client, url)
return {"url": url, "tier": tier, "html_len": len(html) if html else 0}
async def main(urls):
client = Scrapeless()
async with aiohttp.ClientSession() as http_session:
results = await asyncio.gather(
*(scrape_one(http_session, client, u) for u in urls)
)
return results
if __name__ == "__main__":
urls = [
"https://books.toscrape.com/", # 静的 — aiohttp層
"https://quotes.toscrape.com/js/", # JS — エスカレート
]
print(asyncio.run(main(urls)))
should_escalate は、プローズで言及されている両方のシグナルを結合します:(a)「既知のJSが強い」ホストの明示的なアロウリスト、そして(b)ポストパースシグナル(空のボディ / アプリシェル)。アロウリストはより信頼性の高いレバーです — Next.jsまたはReactシェルは、ボディが空であっても2,000バイトのしきい値を越えることが多いため、<div id="root"></div> のチェックだけでは見逃されます。ホスト名チェックはバイトカウントの前に行われます。
返されるもの
パイプラインは以下のような辞書のリストを出力します:
json
[
{
"url": "https://books.toscrape.com/",
"tier": "http",
"html_len": 51274
},
{
"url": "https://quotes.toscrape.com/js/",
"tier": "browser",
"html_len": 9246
}
]
このパターンを実行した際の正直な観察:
- コールドコネクションコストはリアルです。 新しい
ClientSessionの最初のリクエストでは TLS と DNS を支払います; 同じセッションでの後続のリクエストは接続を再利用します。リクエストごとにセッションを再作成しないでください。 - 同時実行制限はターゲットに依存し、aiohttp には依存しません。 公共のカタログの場合、ホストあたり 5 リクエストは安全な出発点です; ボット保護されたオリジンの場合は 3 の方が安全です; フレンドリーな API には 10 が現実的です。
- クラウドブラウザセッションは単一ページの読み込みよりも長く持続します。 パイプラインがログイン、移動、抽出を必要とする場合は、論理的な作業単位ごとに 1 つのセッションを作成し、その単位内のページで再利用します —
context.new_page()は同じセッション内では安価です。 - DNS 解決は aiohttp 内に留まります。 コネクタは
ClientSessionのライフタイム中に解決された IP をキャッシュします。長時間実行されるクローラーの場合、DNS が古くならないように数時間ごとにセッションを再利用してください。 ClientTimeout(total=30)はリクエストごとのものです、gatherごとではありません。 1,000 URL のファンアウトは 30 秒でタイムアウトしません — 各リクエストには独自の 30 秒の予算があります。
結論: あなたの非同期 Python スクレイパーをスケールアップしましょう
非同期パターンは 4 つの操作に縮小されます: 1 つの ClientSession を立ち上げ、Semaphore で同時実行を制限し、スクリプトレスの住宅プロキシを経由してファンアウトをルーティングし、Python SDK と Playwright の非同期 API を介して JS レンダリングされたマイノリティをスクリプトレスのスクレイピングブラウザにエスカレートします。
すべての非同期フェッチをルーティングする住宅プロキシレイヤーについてより深く知りたい場合は、SSL プロキシとは?をご覧ください。
出口をプロキシユーザー名の国のサフィックスで固定し、ホストごとのセマフォをきつく保ちながら、例外をインラインで捕捉するのではなく、成功対失敗のエンベロープ形状に基づいて分岐し、空の HTTP 応答をエスカレートの信号として扱います — 答えではありません。
AI駆動のデータパイプライン構築の準備はできましたか?
私たちのコミュニティに参加して無料プランを請求し、非同期スクレイピングパイプラインを構築している開発者と繋がりましょう: Discord · Telegram。
Scrapeless に登録して、無料のスクレイピングブラウザランタイムを入手し、上記のパターンをパイプラインが必要とするカタログ、フィード、地域に適応してください。価格の詳細は scrapeless.com/en/pricing; 住宅プロキシは scrapeless.com/en/product/proxy-solutions に文書化されています; 完全な SDK リファレンスは docs.scrapeless.com にあります。
FAQ
Q1: ホストごとにどれくらいの同時リクエストを実行すべきですか?
アンチボットスタックがない公共のカタログ向けで、ホストごとに 10 のインフライトリクエストは安全な上限です。アンチボット保護されたオリジンでは、3 の方が現実的です。セマフォはレバーです; 低く始め、429 応答を監視し、そこから調整します。
Q2: ターゲットが私のデータセンターからブロックされていない場合、Scrapelessの住宅プロキシが必要ですか?
ブロックされていない HTTP ターゲットの場合、必要ありません — aiohttp はプロキシなしで機能します。ターゲットが地理的に制限されている場合(アメリカ/イギリス/日本への出口が必要)、データセンターIPがレート制限されているかブロックされている場合、またはリクエストごとに新しい住宅IPが必要で、インフライトプールを多くのオリジンに広げる必要がある場合に、Scrapelessプロキシレイヤーがその必要性を満たします。
Q3: aiohttp から Scrapeless スクレイピングブラウザにエスカレートすべきときは?
aiohttp が返す HTML がコンテンツなしの JS アプリシェルのときです。ヒューリスティック: 一次フェッチ後に気にする要素の数をカウントします; 数がゼロまたは期待値よりもずっと少ない場合、そのページはクライアント側でレンダリングされます。クラウドブラウザ層がそれを処理します。
Q4: 非同期スクレイピングは合法ですか?
非同期は輸送パターンです; 合法性は何をスクレイピングするか、どこから、どの条件下で行うかによります。一般に公開されたデータはアクセス可能です; 法域によって異なります; サイト利用規約が適用されます; 高リスクの使用ケースについては法律相談を受けてください。Scrapeless は公開情報にのみアクセスします。
Q5: Scrapeless スクレイピングブラウザなしで aiohttp を使用できますか?
はい。aiohttp 層(ステップ 3-5)は、レンダリングされた HTML を送信する任意のターゲットに対する完全な非同期スクレイパーとして機能します。Scrapeless スクレイピングブラウザはエスカレーション層であり、HTTP 層が空で返されたときのみ呼び出されます。
Q6: 特定の国への出口を固定するにはどうすればよいですか?
国は country_<CC> という形式で Scrapeless の住宅プロキシユーザー名に入ります(大文字の 2 文字コード、アンダースコア区切り):country_US、country_UK、country_DE、country_JP。ユーザー名文字列内のセグメントを置き換えると、ゲートウェイはその国の住宅 IP を使ってすべてのリクエストをルーティングします。ブラウザ層のリクエストの場合、クラウドブラウザセッションを作成するときに ICreateBrowser(...) に proxy_country="US" を渡します。
Q7: なぜ Playwright の非同期 API を使用するのか、同期ブラウザクライアントを使用しないのか?
同期ブラウザクライアントはイベントループをブロックします。asyncioの全体の目的は、ループを自由に保つことです。コルーチンの内部から同期的にpage.goto(...)を呼び出すと、他のすべての進行中のタスクが停止します。Playwrightのasync_playwrightは、クラウドブラウザ層をコルーチンに優しい状態に保つ唯一の公式なPythonオプションです。Scrapeless SDKはセッションを発行しますが、Playwrightはbrowser_ws_endpointに対してのみCDPと通信します。
Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。



