【发布时间】:2019-02-02 19:56:46
【问题描述】:
我正在使用 asyncio/aiohttp 编写一个网络爬虫。我希望爬虫只想下载 HTML 内容,而跳过其他所有内容。我编写了一个简单的函数来根据扩展名过滤 URL,但这并不可靠,因为许多下载链接中不包含文件名/扩展名。
我可以使用 aiohttp.ClientSession.head() 发送 HEAD 请求,检查 Content-Type 字段以确保它是 HTML,然后发送单独的 GET 请求。但这会增加延迟,因为每页需要两个单独的请求(一个 HEAD,一个 GET),如果可能的话,我想避免这种情况。
是否可以只发送一个常规的 GET 请求,并将 aiohttp 设置为“流”模式以仅下载标头,然后仅在 MIME 类型正确的情况下继续下载正文?或者是否有一些(快速)替代方法可以过滤掉我应该考虑的非 HTML 内容?
更新
根据 cmets 中的要求,我包含了一些示例代码,说明我的意思是发出两个单独的 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))
【问题讨论】:
-
这是一个(我认为)做我想做的事的例子,但它使用的是 Requests 库,我需要使用
aiohttp因为 Requests 与 asyncio 不兼容:stackoverflow.com/a/13198035/176410 -
添加发送两个单独请求的代码示例。
-
我添加了代码来说明我的意思 这会发送第一个 HEAD 请求,检查响应头,然后如果
Content-Type字段为'text/html',则发送另一个 GET 请求。我想知道是否有某种方法可以在继续下载响应正文之前使用单个 GET 请求并检查其标头。我知道 aiohttp 可以对响应进行流式读取,但我不知道如何使用StreamReaderAPI 来完成我所描述的操作。
标签: python http-headers web-crawler mime-types aiohttp