PlaywrightとScrapelessを使用してiframeをスクレイピングする方法
Senior Web Scraping Engineer
TL;DR:
- iframeは親ページのセレクタでは検索できない別のドキュメントを含んでいます。 要素を見つけたり抽出したりする前に、子フレームを選択してください。
- Playwrightは
page.framesを通じてすべてのブラウジングコンテキストを公開します。 配列の位置に頼るのではなく、安定した名前、URLパターン、または所有するiframe要素で意図する子フレームを特定してください。 FrameとFrameLocatorは異なる抽出ニーズに応じています。 メタデータとライフサイクル制御にはFrameを使用し、簡潔な要素アクションにはFrameLocatorを使用してください。- Playwrightはブラウザプロトコルを通じてクロスオリジンのiframeコンテンツを自動化できます。 インページのJavaScriptはブラウザの同一オリジンポリシーの制約を受けます。
- 同じiframe抽出ロジックはローカルでもScrapelessを通じても機能します。 Scrapeless Scraping Browserに移動することは、ブラウザ作成を変更しますが、フレーム選択やロケータコードは変更しません。
- 無料で始められます。 新しいScrapelessアカウントには無料のScraping Browserランタイムが含まれています—app.scrapeless.comでサインアップしてください。
はじめに: 正しいドキュメントから始める
iframeは独自のURL、ライフサイクル、およびDOMを持つ別のドキュメントです。このガイドでは、Playwrightを使用して実際のページ上のブラウジングコンテキストを列挙し、名前とURLで意図する子を特定し、親ページのセレクタでは見えないフォームを抽出します。同じフレームロジックは、PlaywrightをScrapeless Scraping Browserに接続した後も動作します。
iframeが異なる抽出経路を必要とする理由
<iframe>は親ページ内に別のブラウジングコンテキストを埋め込みます。要素は親DOMに属し、読み込まれたドキュメントは子フレームに属します。親ページに対して評価されたセレクタは、その子ドキュメントを検索しません。
HTML iframeリファレンスでは、そのネストされたコンテキストと独自のセッション履歴が説明されています。Playwrightは各コンテキストをFrameとして公開し、FrameLocatorを使用することで<iframe>要素を通じて要素を簡潔に特定できます。
ScrapelessでPlaywrightを使用する理由
Playwrightはフレームメタデータを検査し、子ドキュメントと対話することができます。たとえiframeがクロスオリジンであっても、ブラウザーレベルのアクセスは、親ページ内で実行されているJavaScriptとは異なり、同一オリジンポリシーによって制約されます。
Scrapeless Scraping Browserは、PlaywrightのフレームAPIを保持しながら、Chromiumをホストされた対検出環境に移動します。その接続にはconnect_over_cdpが使用されます。ブラウザ作成後のすべての抽出行は標準のPlaywrightのままです。
必要な前提条件
- Python 3.10以降。
playwright1.59.0または現在の互換バージョン。- 完全な実行可能なフォールバック用のローカルChrome/Chromium。
- クラウドブラウザ接続のための資金提供されたScrapelessアカウントと
SCRAPELESS_API_KEY。検証アカウントでの新しいセッションはコード14500を返したため、クラウド接続はラベル付けされた前提条件のギャップです。
インストール
bash
python -m pip install "playwright==1.59.0"
動作例ではホストの/usr/bin/google-chromeを使用します。プロジェクトがブラウザをプロビジョニングする方法によっては、Playwright管理のChromiumを使用してください。
Scrapeless Scraping Browserに接続する
注意: この接続には資金提供されたScraping Browserの残高が必要です。最終的な検証アカウントは
残高不足、最初に再充電してくださいと返しました。独自の資金提供されたキーを使用してください。以下のフレーム列挙と抽出は完全にローカルChromeで実行されました。
python
import os
from urllib.parse import urlencode
from playwright.sync_api import sync_playwright
params = urlencode({
"token": os.environ["SCRAPELESS_API_KEY"],
"sessionTTL": 120,
"proxyCountry": "US",
})
cdp_url = f"wss://browser.scrapeless.com/api/v2/browser?{params}"
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(cdp_url)
page = browser.contexts[0].pages[0]
# 以下のフレームステップを続ける。
browser.close()
現在の接続パラメーターについてはScrapeless開発者ドキュメントを参照してください。
ステップ1 — 知っている子フレームを持つページを開く
Seleniumは小さな公開テストフィクスチャを維持しています。その親ページにはiframe1-nameという名前の1つのiframeがあり、そのsrcはformPage.htmlを読み込みます。
python
TARGET_URL = "https://www.selenium.dev/selenium/web/iframes.html"
page.goto(TARGET_URL, wait_until="domcontentloaded")
page.wait_for_selector("#iframe1")
page.wait_for_timeout(500)
print("親のタイトル:", page.title())
print("親のメールマッチ数:", page.locator("#email").count())
text
親のタイトル: このページにはiframeがあります
親のメールマッチ数: 0
メール入力が存在しますが、親ではなく埋め込まれたフォームドキュメントに属しています。
ステップ2 — フレームを列挙してから1つを選択
page.frames はメインフレームとすべての添付された子フレームおよびその子孫を含みます:
python
print("フレーム数:", len(page.frames))
for index, frame in enumerate(page.frames):
print(index, repr(frame.name), frame.url, frame.title())
text
フレーム数: 2
0 '' https://www.selenium.dev/selenium/web/iframes.html このページにはiframeがあります
1 'iframe1-name' https://www.selenium.dev/selenium/web/formPage.html ここから出発します
インデックス0はメインドキュメントです。インデックス1を永続的な契約に変えないでください:別の広告、同意ウィジェット、または分析用フレームが順序を変更する可能性があります。名前とURLはより確かな証拠です。
ステップ3 — 名前またはURLでフレームを選択
フィクスチャは両方の安定した信号を提供します:
python
named_frame = page.frame(name="iframe1-name")
url_frame = next(
frame for frame in page.frames
if frame.url.endswith("/formPage.html")
)
assert named_frame is url_frame
print("選択したフレーム:", url_frame.name)
print("選択したタイトル:", url_frame.title())
名前が生成されている場合は、制限されたURLパターンに一致させるか、所有しているiframe要素を見つけて content_frame() を呼び出します。候補が複数一致した場合は失敗します;最初の重複を黙って選ぶことは、誤ったウィジェットから適切と思われるデータを生成します。
ステップ4 — 子ドキュメントからデータを抽出
Frame を保持していると、そのロケーターAPIはページと同様に機能します:
python
email = url_frame.locator("#email")
selected = url_frame.locator("#multi option:checked").evaluate_all(
"options => options.map(option => option.value)"
)
record = {
"frame_name": url_frame.name,
"frame_url": url_frame.url,
"frame_title": url_frame.title(),
"email_inputs": email.count(),
"selected_values": selected,
}
print("メール入力数:", record["email_inputs"])
print("選択した値:", record["selected_values"])
text
メール入力数: 1
選択した値: ['eggs', 'sausages']
子ページには、その2つのオプションが選択された複数選択フィールドがあります。これは、見出しだけを読むよりも強力な確認です:Playwrightがフォームドキュメントに到達し、その内部の状態を評価したことを証明します。
ステップ5 — 直接アクションのためにFrameLocatorを使用
フレームのメタデータが不要な場合、FrameLocator は短くなります:
python
frame_ui = page.frame_locator("#iframe1")
print("FrameLocatorによるメール数:", frame_ui.locator("#email").count())
公式Playwrightフレームガイドは、同じ2つのレベルを示しています:iframe要素を介してコンテンツを見つけるか、URL/名前で Frame オブジェクトを取得します。
ホスティングされたブラウザでそのロケーターを実行する準備はできましたか? 無料のScrapelessアカウントを作成し、ブラウザの作成だけを置き換えます。
完全なローカル検証スクリプト
python
from playwright.sync_api import sync_playwright
TARGET_URL = "https://www.selenium.dev/selenium/web/iframes.html"
with sync_playwright() as p:
browser = p.chromium.launch(
executable_path="/usr/bin/google-chrome",
headless=True,
)
page = browser.new_page()
page.goto(TARGET_URL, wait_until="domcontentloaded")
page.wait_for_selector("#iframe1")
page.wait_for_timeout(500)
child = next(
frame for frame in page.frames
if frame.url.endswith("/formPage.html")
)
selected = child.locator("#multi option:checked").evaluate_all(
"options => options.map(option => option.value)"
)
frame_locator_count = page.frame_locator("#iframe1").locator("#email").count()
assert page.locator("#email").count() == 0
assert child.name == "iframe1-name"
assert child.locator("#email").count() == 1
assert selected == ["eggs", "sausages"]
assert frame_locator_count == 1
print("親のタイトル:", page.title())
print("親のメール一致:", page.locator("#email").count())
print("フレーム数:", len(page.frames))
print("子の名前:", child.name)
print("子のURL:", child.url)
print("子のタイトル:", child.title())
print("子のメール一致:", child.locator("#email").count())
print("選択した値:", selected)
print("FrameLocatorのメール一致:", frame_locator_count)
browser.close()
完全な実行は、2つのフレーム、親のメール一致0、子のメール一致1、期待されるフレーム名/タイトル/URL、および子フォームからの ['eggs', 'sausages'] を返します。
取得内容
検証されたワークフローは、抽出されたフォームの状態とそのソースを識別するのに十分なフレームメタデータの両方を返します:
json
{
"parent_email_matches": 0,
"frame_count": 2,
"frame_name": "iframe1-name",
"frame_url": "https://www.selenium.dev/selenium/web/formPage.html",
"frame_title": "ここから出発します",
"child_email_matches": 1,
"選択された値": ["卵", "ソーセージ"]
}
出力は四つの事実を確立します:親ドキュメントはメールフィールドを見ることができず、意図された子は名前とURLで特定でき、子のロケーターは一致する入力を一つ見つけ、選択されたフォーム値はそのフレームの内部から来ています。ページに複数の組み込み文書が含まれている場合は、抽出した各レコードと共にフレーム名とURLを保持してください。
## クロスオリジン iframe と同一オリジンポリシー
`document.querySelector("iframe").contentDocument`のようなブラウザのJavaScriptは、親と子のオリジンが異なるとブロックされることがあります。Playwrightはブラウザ自動化プロトコルと通信し、子をフレームとして公開するため、クロスオリジンドキュメント内の要素を見つけて操作することができます。
それはすべての境界を取り除くわけではありません。サンドボックス属性はスクリプトを制限することがあり、ナビゲーションは読む際にフレームを置換することがあります。また、ブラウザ拡張やPDFビューワは通常のHTMLドキュメントを公開しない場合があります。抽出契約を記述する前に、実際のフレームツリーを調査してください。
## 動的およびネストされたフレーム
### 添付とナビゲーションを待つ
iframe要素は、その子が最終URLに到達する前に現れることがあります。子のロケーターを待つか、フレームナビゲーションイベントを調査してください。有用な準備マーカーはデータを持つ要素であり、単に親の`<iframe>`タグではありません。
### デタッチを期待する
シングルページアプリは時々iframeを削除して再作成します。保存されたフレームオブジェクトはデタッチされることがあります。UIトランジション後に古いオブジェクトが生き残ると仮定するのではなく、その安定した名前、URL、またはオーナー要素から再度フレームを解決してください。
### 意図的にネストされたフレームを横断する
ネストされたコンテキストでは、`frame.child_frames`を調査するか、FrameLocatorsをチェーンします。同じ名前のウィジェットが混同されないように、出力の由来に親子のパスを保持してください。
## 結論
iframeスクレイピングは適切なドキュメントを選択することから始まります。フレームツリーを列挙し、安定した名前またはURLで子を選択し、その内部の要素を待ち、抽出したレコードと共にフレームメタデータを保持します。検索を簡潔にするためにFrameLocatorを使用し、アイデンティティ、ナビゲーション、またはネストされたフレーム制御が必要な場合にはFrameオブジェクトを使用します。ワークフローをScrapelessに移行することで、ブラウザの作成が変わりますが、フレームのロジックは変わりません。
## iframeからデータを抽出する準備はできましたか?
Scrapelessコミュニティのブラウザベースの抽出ワークフローを構築している開発者に参加してください:[Discord](https://discord.gg/VU2vtbq7Q2) · [Telegram](https://t.me/scrapeless)。
[Scrapelessから始める](https://app.scrapeless.com/passport/login/?utm_source=website&utm_medium=blog&utm_campaign=scrapingbrowser&utm_term=iframe-web-scraping-scraping-browser)、[Scrapelessの価格を確認する](https://www.scrapeless.com/ja/pricing?utm_source=website&utm_medium=blog&utm_campaign=scrapingbrowser&utm_term=iframe-web-scraping-scraping-browser)、そして[CDPが公開する内容を読む](https://www.scrapeless.com/ja/blog/what-is-chrome-devtools-protocol?utm_source=website&utm_medium=blog&utm_campaign=scrapingbrowser&utm_term=iframe-web-scraping-scraping-browser)前に、同じフレームワークフローをホスティングされたブラウザに移行してください。
## FAQ
**Q: なぜ親ページがiframe内の要素を見つけられないのですか?**
iframeは別のドキュメントを所有しています。親ページのロケーターは親のブラウジングコンテキストを検索します。子のフレームを選択するか、最初にFrameLocatorを使用してください。
**Q: 配列インデックスでフレームを選択すべきですか?**
いいえ。ページがウィジェットや広告を追加すると、フレームの順序が変わります。安定した名前、URLパターン、または所有するiframe要素を優先し、あいまいな一致では失敗してください。
**Q: FrameとFrameLocatorの違いは何ですか?**
Frameはドキュメントのアイデンティティ、URL、名前、ライフサイクル、および子フレームを公開します。FrameLocatorは特定のiframe要素を介して簡潔なロケーター操作を提供します。
**Q: Playwrightはクロスオリジンのiframeにアクセスできますか?**
はい、Playwrightは同一オリジンポリシーのためにページ内のJavaScriptが`contentDocument`を読み取れない場合でも、ブラウザプロトコルを介してクロスオリジンの子フレームを自動化できます。
**Q: 動的に読み込まれたiframeを待つにはどうすればいいですか?**
フレーム内のデータを持つロケーターや知られた最終フレームのURLを待ってください。iframe要素の存在のみでは、その子ドキュメントがナビゲーションを完了したことを証明しません。
**Q: フレームがデタッチされたらどうなりますか?**
保存されたフレームはもはやライブドキュメントを表しません。ページトランジション後に安定した証拠から交換フレームを再度解決してください。
**Q: iframeスクレイピングは合法ですか?**
埋め込みはターゲットのデータ権利や条件を変更しません。サイトと埋め込まれたプロバイダーのポリシーを確認し、適用される場合は<a href="https://datatracker.ietf.org/doc/html/rfc9309" rel="nofollow"><strong>ロボット指令</strong></a>を尊重し、ボリュームを制限し、敏感または商業的な収集の場合は法的アドバイスを求めてください。
Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。



