Запросы - html могу ли я получить коды состояния всех запросов (или альтернативу селену) - PullRequest
1 голос
/ 28 мая 2020

У меня есть следующий код:

from requests_html import HTMLSession

ses = HTMLSession()
r = ses.get(MYURL)  # start a headless chrome browser and load MYURL
r.render(keep_page=True)  # This will now 'render' the html page
                          # which means like in a real browser trigger
                          # all requests for dependent links. 
                          # like .css, .js, .jpg, .gif

Вызов render() запускает загрузку запросов для Javascript, растровых изображений и т.д. c. Есть ли способ получить отслеживание кодов состояния для каждого запроса. Меня в основном интересуют ошибки 404, но также могут быть интересны ошибки 403 и 5xx.

Например, один вариант использования:

• Go to страница или последовательность страниц

• Затем сообщите, сколько запросов не удалось выполнить и какие URL-адреса были получены.

Если это невозможно с запросами - html но достаточно просто с селеном, я могу переключиться на селен

Дополнение: уродливая работа вокруг 1:

Я могу настроить ведение журнала для входа в файл и установить уровень журнала для отладки. Затем я могу попытаться проанализировать журналы websockets.protocol: который содержит такие строки, как {\\"url\\":\\"https://my.server/example.gif\\",\\"status\\":404,\\"statusText\\":\\"...

Проблемы:

Активация DEBUG уровня журнала в файл, похоже, активирует что-то еще, потому что внезапно множество информация об отладке также записывается в stdout.

Например:

[I:pyppeteer.launcher] Browser listening on: ws://127.0.0.1:45945/devtools/browser/bc5ce097-e67d-455e-8a59-9a4c213263c1
[D:pyppeteer.connection.Connection] SEND: {"id": 1, "method": "Target.setDiscoverTargets", "params": {"discover": true}}

Также не очень весело анализировать это в реальном времени и соотносить его с URL-адресом, который я использовал в моем code.

Дополнение: уродливая работа вокруг 2:

Еще хуже для корреляции, но лучше для синтаксического анализа и простого определения 404 s и работает, только если под контролем http-сервер.

Анализ журналов http-сервера журналов с помощью nginx Я даже могу настроить собственный регистратор в формате csv только с интересующими меня данными.

Приложение: уродливая работа вокруг 3:

Используя python ведение журнала (специальный обработчик и фильтр для pyppeteer), я могу перехватить строку json, описывающую ответы от pyppeteer.connection.CDPSession регистратора без имея stderr загрязняются.

Фильтр позволяет мне получать данные в реальном времени.

Это все еще довольно хакерский sh. Итак, ищем лучшее решение.

1 Ответ

1 голос
/ 30 мая 2020

Попробуйте следующее и посмотрите, что вам нужно. Это строго версия pyppeteer (а не request_ html) и полагается на неэкспонированные частные переменные, поэтому она довольно подвержена сбоям при обновлении версии.

import asyncio
from pyppeteer import launch
from pyppeteer.network_manager import NetworkManager

def logit(event):
    req = event._request
    print("{0} - {1}".format(req.url, event._status))

async def main():
    browser = await launch({"headless": False})
    page = await browser.newPage()
    page._networkManager.on(NetworkManager.Events.Response, logit)
    await page.goto('https://www.google.com')
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())

Проверка источника запросов_ html объект страницы браузера, кажется, похоронен довольно глубоко, поэтому добраться до NetworkManager не так-то просто. Если вы действительно хотите, чтобы он работал из request_ html, вероятно, проще всего использовать monkeypatch. Вот пример:

import asyncio
from requests_html import HTMLSession, TimeoutError, HTML
from pyppeteer.network_manager import NetworkManager
from typing import Optional, Union

def logit(event):
    req = event._request
    print("{0} - {1}".format(req.url, event._status))

async def _async_render(self, *, url: str, script: str = None, scrolldown, sleep: int, wait: float, reload, content: Optional[str], timeout: Union[float, int], keep_page: bool, cookies: list = [{}]):
    """ Handle page creation and js rendering. Internal use for render/arender methods. """
    try:
        page = await self.browser.newPage()
        page._networkManager.on(NetworkManager.Events.Response, logit)

        # Wait before rendering the page, to prevent timeouts.
        await asyncio.sleep(wait)

        if cookies:
            for cookie in cookies:
                if cookie:
                    await page.setCookie(cookie)

        # Load the given page (GET request, obviously.)
        if reload:
            await page.goto(url, options={'timeout': int(timeout * 1000)})
        else:
            await page.goto(f'data:text/html,{self.html}', options={'timeout': int(timeout * 1000)})

        result = None
        if script:
            result = await page.evaluate(script)

        if scrolldown:
            for _ in range(scrolldown):
                await page._keyboard.down('PageDown')
                await asyncio.sleep(sleep)
        else:
            await asyncio.sleep(sleep)

        if scrolldown:
            await page._keyboard.up('PageDown')

        # Return the content of the page, JavaScript evaluated.
        content = await page.content()
        if not keep_page:
            await page.close()
            page = None
        return content, result, page
    except TimeoutError:
        await page.close()
        page = None
        return None


ses = HTMLSession()
r = ses.get('https://www.google.com')  # start a headless chrome browser and load MYURL
html =  r.html
html._async_render = _async_render.__get__(html, HTML)
html.render()
...