Как получить поле «Инициатор» из панели «Сеть» devtools с помощью Selenium?

Я пытаюсь извлечь все сетевые запросы URL-адресов с веб-сайта и установить между ними иерархическую связь, т.е. если один запрос URL-адреса генерирует другой запрос. Что-то вроде цепочки запросов.

Как вы знаете, на панели «Сеть» в таблице «Запросы» есть поле «Инициатор», в котором указывается источник или родитель конкретного запроса (если он есть). Вручную я могу использовать браузер, перейти на панель «Сеть» в инструментах разработчика, загрузить веб-сайт и загрузить полученный файл HAR. Например:

{
        "startedDateTime": "2019-11-05T17:38:46.775Z",
        "time": 15.676000155508518,
        "request": {
          "method": "POST",
          "url": "https://www.google.com/gen_204?oq=&gs_l=psy-ab.22...0.0..847450...0.0..0.0.0.......0......gws-wiz.",
          "httpVersion": "http/2.0",
          "headers": [
            {
              "name": ":path",
              "value": "/gen_204?oq=&gs_l=psy-ab.22...0.0..847450...0.0..0.0.0.......0......gws-wiz."
            },
            {
              "name": "sec-fetch-mode",
              "value": "no-cors"
            },
            {
              "name": "origin",
              "value": "https://www.google.com"
            },
            {
              "name": "accept-encoding",
              "value": "gzip, deflate, br"
            },
            {
              "name": "accept-language",
              "value": "en-GB,en;q=0.9,en-US;q=0.8,es-US;q=0.7,es;q=0.6"
            },
            {
              "name": "user-agent",
              "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/76.0.3809.100 Chrome/76.0.3809.100 Safari/537.36"
            },
            {
              "name": "content-type",
              "value": "text/plain;charset=UTF-8"
            },
            {
              "name": "accept",
              "value": "*/*"
            },
            {
              "name": "referer",
              "value": "https://www.google.com/"
            },
            {
              "name": ":authority",
              "value": "www.google.com"
            },
            {
              "name": "cookie",
              "value": "CONSENT=YES+GB.en+20160414-00-0; SEARCH_SAMESITE=CgQIg44B; ANID=AHWqTUlE3OPRfM5R1dtW0XvyIu2NOdLWoSHEgFemsFslXQTIzFKFCL-7kTtDZAr_; NID=190=Ezp7tXRaU_Rs2BS9RprlsS9QN9-PcwpYNSLwaOVGVFFp6pWepIjDqsYlgyLqb2eATn6HwUNs-SmgzAmtEm63fgX-YWVgbOyX7GU1esPamrN-GWXfwmXyrsqsTBOOQTzsHB3Q89tATDNQE_OKGd0YgCxMp9m9QXke2BJANdKdBYujl-g5tS8ZXcq0pw; 1P_JAR=2019-11-05-17; DV=o32RqCcqMlgsAJonGalrPPWlv0DK4xZ24gV5ztaaewMAAAA"
            },
            {
              "name": ":scheme",
              "value": "https"
            },
            {
              "name": "sec-fetch-site",
              "value": "same-origin"
            },
            {
              "name": "content-length",
              "value": "0"
            },
            {
              "name": ":method",
              "value": "POST"
            }
          ],
          "queryString": [
            {
              "name": "oq",
              "value": ""
            },
            {
              "name": "gs_l",
              "value": "psy-ab.22...0.0..847450...0.0..0.0.0.......0......gws-wiz."
            }
          ],
          "cookies": [
            {
              "name": "CONSENT",
              "value": "YES+GB.en+20160414-00-0",
              "expires": null,
              "httpOnly": false,
              "secure": false
            },
            {
              "name": "SEARCH_SAMESITE",
              "value": "CgQIg44B",
              "expires": null,
              "httpOnly": false,
              "secure": false
            },
            {
              "name": "ANID",
              "value": "AHWqTUlE3OPRfM5R1dtW0XvyIu2NOdLWoSHEgFemsFslXQTIzFKFCL-7kTtDZAr_",
              "expires": null,
              "httpOnly": false,
              "secure": false
            },
            {
              "name": "NID",
              "value": "190=Ezp7tXRaU_Rs2BS9RprlsS9QN9-PcwpYNSLwaOVGVFFp6pWepIjDqsYlgyLqb2eATn6HwUNs-SmgzAmtEm63fgX-YWVgbOyX7GU1esPamrN-GWXfwmXyrsqsTBOOQTzsHB3Q89tATDNQE_OKGd0YgCxMp9m9QXke2BJANdKdBYujl-g5tS8ZXcq0pw",
              "expires": null,
              "httpOnly": false,
              "secure": false
            },
            {
              "name": "1P_JAR",
              "value": "2019-11-05-17",
              "expires": null,
              "httpOnly": false,
              "secure": false
            },
            {
              "name": "DV",
              "value": "o32RqCcqMlgsAJonGalrPPWlv0DK4xZ24gV5ztaaewMAAAA",
              "expires": null,
              "httpOnly": false,
              "secure": false
            }
          ],
          "headersSize": -1,
          "bodySize": 0
        },
        "response": {
          "status": 204,
          "statusText": "",
          "httpVersion": "http/2.0",
          "headers": [
            {
              "name": "date",
              "value": "Tue, 05 Nov 2019 17:38:46 GMT"
            },
            {
              "name": "server",
              "value": "gws"
            },
            {
              "name": "x-frame-options",
              "value": "SAMEORIGIN"
            },
            {
              "name": "content-type",
              "value": "text/html; charset=UTF-8"
            },
            {
              "name": "status",
              "value": "204"
            },
            {
              "name": "alt-svc",
              "value": "quic=\":443\"; ma=2592000; v=\"46,43\",h3-Q050=\":443\"; ma=2592000,h3-Q049=\":443\"; ma=2592000,h3-Q048=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000"
            },
            {
              "name": "content-length",
              "value": "0"
            },
            {
              "name": "x-xss-protection",
              "value": "0"
            }
          ],
          "cookies": [],
          "content": {
            "size": 0,
            "mimeType": "text/html"
          },
          "redirectURL": "",
          "headersSize": -1,
          "bodySize": -1,
          "_transferSize": 54
        },
        "cache": {},
        "timings": {
          "blocked": 1.1320006029605865,
          "dns": -1,
          "ssl": -1,
          "connect": -1,
          "send": 0.16199999999999992,
          "wait": 14.122000366747379,
          "receive": 0.25999918580055237,
          "_blocked_queueing": 0.5990006029605865
        },
        "serverIPAddress": "216.58.204.68",
        "_initiator": {
          "type": "script",
          "stack": {
            "callFrames": [
              {
                "functionName": "s_1pb",
                "scriptId": "129",
                "url": "https://www.google.com/xjs/_/js/k=xjs.s.en_GB.UISl_YucLj8.O/ck=xjs.s.or8k_ixGu54.L.W.O/m=Fkg7bd,HcFEGb,IvlUe,MC8mtf,OF7gzc,RMhBfe,T4BAC,TJw5qb,TbaHGc,Y33vzc,cdos,hsm,iDPoPb,jsa,mvYTse,tg8oTe,uz938c,vWNDde,ws9Tlc,yQ43ff,d,csi/am=BAAAsAjYuwOC_L8VAAQAfAYAAAFuwQYLhCGhYqwOEAE/d=1/dg=2/br=1/ct=zgms/rs=ACT90oGdwE1ooFdbHyz-Vk2BhYjwAv-QDQ",
                "lineNumber": 2323,
                "columnNumber": 376
              },

В этом случае URL-адрес https://www.google.com/gen_204?oq=&gs_l=psy-ab.22... инициируется URL-адресом https://www.google.com/xjs/_/js/k=xjs.s.en_GB.UISl.... Посмотреть эту информацию можно в ключе "Инициатор" -> "callFrames" -> "url".

Идея состоит в том, чтобы получить эту информацию (URL-адреса, которые вызывают других) или автоматически загрузить файл HAR с помощью Selenium. Я пробовал это:

<сильный>1. Selenium + browsermob proxy Проблема: в результирующих HAR-файлах нет поля «Инициатор» и нет возможности связать запросы инициаторов и их зависимости.

<сильный>2. Журналы производительности Selenium Я использую этот код для получения журналов производительности от Selenium:

caps = DesiredCapabilities.CHROME
caps['loggingPrefs'] = {'performance': 'ALL'}

chrome_options = webdriver.ChromeOptions()
driver = webdriver.Chrome(driver_path,desired_capabilities=caps)
driver.get("http://google.com")

browser_log = driver.get_log('performance')

Здесь единственный метод, в котором можно найти поле «инициатор», — это метод «Network.requestWillBeSent», который имеет URL-адрес, но не связан с другим. Кажется, что каждое поле «сообщение» независимо, и опять же, нет возможности связать запросы инициатора и их зависимости.

  1. driver.execute_script Я видел этот код в этом вопросе: Как получить доступ к панели "Сеть" в инструментах разработчика Google Chrome с помощью селена?
driver = webdriver.Chrome('/path/to/chromedriver)
driver.get('https://www.google.com');
log = driver.execute_script("return window.performance.getEntries();")
#ANOTHER WAY
#log = driver.execute_script("var performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {}; var network = performance.getEntries() || {}; return network;")

Полученный журнал полностью отличается от файла HAR или журнала производительности и не содержит никакой информации, которую можно использовать для сопоставления запросов. Пример:

{
    "startTime": 0,
    "initiatorType": "navigation",
    "unloadEventStart": 0,
    "fetchStart": 69.29999962449074,
    "duration": 1311.3000001758337,
    "responseStart": 172.89999965578318,
    "nextHopProtocol": "h2",
    "transferSize": 68052,
    "connectStart": 70.19999995827675,
    "domainLookupStart": 70.19999995827675,
    "redirectStart": 0,
    "domContentLoadedEventEnd": 504.90000005811453,
    "responseEnd": 190.7999999821186,
    "requestStart": 100.49999970942736,
    "type": "navigate",
    "secureConnectionStart": 80.40000032633543,
    "connectEnd": 99.99999962747097,
    "redirectCount": 0,
    "workerStart": 0,
    "decodedBodySize": 233300,
    "loadEventStart": 1304.8000000417233,
    "encodedBodySize": 67329,
    "serverTiming": [],
    "entryType": "navigation",
    "domInteractive": 487.699999473989,
    "domContentLoadedEventStart": 487.80000023543835,
    "redirectEnd": 0,
    "name": "https://www.google.com/?gws_rd=ssl",
    "domainLookupEnd": 70.19999995827675,
    "unloadEventEnd": 0,
    "loadEventEnd": 1311.3000001758337,
    "domComplete": 1303.3999996259809,
    "toJSON": {}
  },
  {
    "initiatorType": "img",
    "fetchStart": 298.20000007748604,
    "duration": 14.100000262260437,
    "responseStart": 310.70000026375055,
    "responseEnd": 312.3000003397465,
    "transferSize": 6146,
    "connectStart": 298.20000007748604,
    "domainLookupStart": 298.20000007748604,
    "redirectStart": 0,
    "toJSON": {},
    "requestStart": 299.80000015348196,
    "secureConnectionStart": 0,
    "connectEnd": 298.20000007748604,
    "workerStart": 0,
    "decodedBodySize": 5969,
    "startTime": 298.20000007748604,
    "encodedBodySize": 5969,
    "serverTiming": [],
    "entryType": "resource",
    "redirectEnd": 0,
    "name": "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png",
    "domainLookupEnd": 298.20000007748604,
    "nextHopProtocol": "h2"
  },

Поэтому я думаю, что файл HAR, загруженный из панели инструментов разработчика «Сеть», является единственным источником информации, позволяющим установить отношения между URL-запросами. Поскольку я просматриваю множество веб-сайтов, мне нужно автоматизировать процесс, но я не могу найти способ сделать это.

Любые идеи об автоматической загрузке файлов HAR для извлечения информации, которая мне нужна, напрямую с помощью Selenium, будут оценены.


person Adrian    schedule 07.11.2019    source источник
comment
Попробуйте улучшить второй метод, потому что devtools использует Network.requestWillBeSent внутри для извлечения инициатора. Devtools явно создает HAR, поэтому он может легко сопоставлять события с использованием поля requestId, это не функция протокола отладки, поэтому вам придется либо найти существующую библиотеку, которая делает то же самое через веб-драйвер, либо написать ее самостоятельно.   -  person wOxxOm    schedule 07.11.2019
comment
Привет. Любое решение для получения сведений об инициаторе? В селене 4 может быть решение, я также ищу информацию об инициаторе.   -  person Engineer    schedule 27.02.2020
comment
Попробуйте свой второй метод (журналы производительности Selenium) сейчас, он уже достигнут.   -  person xiaopo    schedule 24.02.2021


Ответы (1)


Вы можете получить _initiator данные со страницы raw_entry.

with open('at.har', 'r') as f:
    har_parser = HarParser(json.loads(f.read()))
pages_root = har_parser.pages[0]
initiator_dict = {}
for page in pages_root:
    if "url" in initiator:
        initiator_dict[page.request.url] = initiator['url']
res = defaultdict(list)
for key, val in sorted(initiator_dict.items()):
    res[val].append(key)
person feedthemachine    schedule 26.05.2021