aiohttp: Как эффективно проверить заголовки HTTP перед загрузкой тела ответа? - PullRequest
0 голосов
/ 02 февраля 2019

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

Я мог бы использовать aiohttp.ClientSession.head() для отправки запроса HEAD, проверьтеполе Content-Type, чтобы убедиться, что это HTML, а затем отправить отдельный запрос GET.Но это увеличит задержку, требуя два отдельных запроса на страницу (один HEAD, один GET), и я хотел бы избежать этого, если это возможно.

Можно ли просто отправить обычный запрос GET и установить aiohttp в «потоковый» режим для загрузки только заголовка, а затем продолжить загрузку тела, только если тип MIME правильный?Или есть какой-то (быстрый) альтернативный метод фильтрации содержимого, отличного от HTML, который я должен рассмотреть?


ОБНОВЛЕНИЕ

Как и было запрошено в комментариях, яЯ включил пример кода того, что я имею в виду, делая два отдельных HTTP-запроса (один HEAD-запрос и один GET-запрос):

import asyncio
import aiohttp

urls = ['http://www.google.com', 'http://www.yahoo.com']
results = []

async def get_urls_async(urls):
    loop = asyncio.get_running_loop()

    async with aiohttp.ClientSession() as session:
        tasks = []

        for u in urls:
            print(f"This is the first (HEAD) request we send for {u}")
            tasks.append(loop.create_task(session.get(u)))

        results = []
        for t in asyncio.as_completed(tasks):
            response = await t
            url = response.url

            if "text/html" in response.headers["Content-Type"]:
                print("Sending the 2nd (GET) request to retrive body")
                r = await session.get(url)
                results.append((url, await r.read()))
            else:
                print(f"Not HTML, rejecting: {url}")

        return results

results = asyncio.run(get_urls_async(urls))

1 Ответ

0 голосов
/ 03 февраля 2019

Это проблема протокола, если вы делаете GET, сервер хочет отправить тело.Если вы не извлекаете тело, вам нужно сбросить соединение (это фактически то, что происходит, если вы не выполните read() до __aexit__ ответа).

Так что вышекод должен делать больше, меньше, чем вы хотите.ПРИМЕЧАНИЕ Сервер может отправлять в первый блок уже больше, чем просто заголовки

...