2025, Oct 17 04:17

Selenium и cross-origin iframe: почему performance-лог не видит все запросы и как собрать полный список доменов

Встраиваете Google Sheets через iframe и не видите запросы в логах Selenium? Из‑за OOPIF часть трафика теряется. Показываем, как собрать домены с Playwright.

Когда вы встраиваете документ Google Sheets через iframe и пытаетесь учесть все сетевые запросы страницы, легко положиться на журналы производительности Selenium. Неожиданность в том, что в собранном списке доменов оказывается только верхнеуровневый хост, хотя в Chrome DevTools явно видно множество запросов к другим источникам. Ниже — короткое объяснение, почему так происходит, и как собрать полный набор доменов в такой ситуации.

Окружение

ChromeDriver 138.0.7204.168, Chrome 138.0.7204.184, Selenium 4.34.2, Windows 11.

Воспроизведение проблемы

Страница встраивает опубликованную таблицу через iframe:

<html>
  <head>
  </head>
  <body>
    <iframe src="https://docs.google.com/spreadsheets/d/e/2PACX-1vQaJwXqci0KQzDjzs8kvy--p80OZY1n30t4NWRh2qkU3pJqAdB4ZJEc79ohh4OkuifHWOHBRi0Z0yKS/pubhtml?gid=0&single=true&widget=true&headers=false"></iframe>
  </body>
</html>

Сценарий Selenium пытается собрать каждый домен, к которому обращается страница, используя журнал «performance»:

from urllib.parse import urlparse
import json
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
import time

opt = Options()
opt.set_capability('goog:loggingPrefs', {'performance': 'ALL'})

svc = Service(executable_path='C:\\Users\\qi\\PycharmProjects\\PythonLearn\\DomainCollector\\chromedriver.exe')
browser = webdriver.Chrome(service=svc, options=opt)

local_url = "file:///C:/Users/qi/Desktop/a.html"
browser.get(local_url)
time.sleep(5)

hosts = set()
perf_entries = browser.get_log('performance')

for evt in perf_entries:
    raw = evt['message']
    try:
        payload = json.loads(raw)
        evt_type = payload['message']['method']
        if evt_type == 'Network.requestWillBeSent':
            req_url = payload['message']['params']['request']['url']
            host = urlparse(req_url).netloc
            if host:
                hosts.add(host)
    except Exception:
        continue

print(f"domains:{hosts}")

Результат содержит только домен верхнего уровня:

domains:{'docs.google.com'}

При этом в DevTools браузера виден дополнительный трафик к другим источникам Google и хостам статических ресурсов.

Что на самом деле происходит

Журнал «performance» ChromeDriver ненадёжно фиксирует сетевой трафик, исходящий из cross‑origin iframe. В современных версиях Chrome такие фреймы работают вне основного процесса (OOPIF). Параметр goog:loggingPrefs с performance=ALL влияет на уровень логирования, а не на охват целей, с которых собираются события. Даже при включённом perfLoggingPrefs.enableNetwork журнал производительности остаётся в основном привязан к верхнеуровневой цели и пропускает запросы, отправленные кросс‑доменными фреймами. Поэтому приведённый выше скрипт видит docs.google.com, но не дополнительные домены, которые загружает iframe.

Рабочая альтернатива, которая охватывает все запросы

Практичный способ зафиксировать все исходящие запросы в этом случае — использовать подход, отслеживающий сетевые события по всей странице, включая cross‑origin iframe. С помощью Playwright следующий скрипт собирает все домены, замеченные во время загрузки страницы:

import asyncio
from urllib.parse import urlparse
from playwright.async_api import async_playwright

hosts2 = set()

def on_request(req):
    h = urlparse(req.url).netloc
    if h:
        hosts2.add(h)

async def run():
    async with async_playwright() as pw:
        engine = await pw.chromium.launch(executable_path='..\\DomainCollector\\chrome-win64\\chrome.exe', headless=False)
        tab = await engine.new_page()
        tab.on("request", on_request)

        await tab.goto("file:///C:/Users/qi/Desktop/a.html")
        await tab.wait_for_load_state("networkidle")

asyncio.run(run())

print(f"domains:{hosts2}")

Результат включает все обнаруженные хосты, например ssl.gstatic.com, fonts.gstatic.com, fonts.googleapis.com и docs.google.com.

Почему это важно

Если вы создаёте инструменты мониторинга, обхода или безопасности, которые зависят от перечисления внешних ресурсов, пропуск трафика из cross‑origin iframe приводит к «слепым зонам». Встраиваемый контент повсюду, и крупные платформы часто распределяют активы по множеству доменов. Опора только на верхнеуровневые сетевые события искажает метрики, скрывает обращения к сторонним сервисам и ломает правила, основанные на анализе происхождения.

Выводы

Когда на целевой странице есть cross-origin iframe, одного журнала производительности ChromeDriver недостаточно для полной картины сети. Этот механизм ориентирован на основную цель и не обеспечивает стабильного покрытия трафика OOPIF. В задачах, где нужен полный сбор, используйте инструменты, отслеживающие запросы во всех фреймах страницы. В примере выше Playwright даёт такое покрытие «из коробки» и возвращает ожидаемый набор доменов. Учитывайте это при проектировании конвейеров сбора данных вокруг встраиваемого контента, чтобы избежать недоучёта и сохранить точную видимость.

Статья основана на вопросе с StackOverflow от tinyhare и ответе от tinyhare.