使用Python和asyncio进行网络爬虫

8

我用Python写了一个脚本,从网页中获取一些信息。如果脚本不在异步IO中运行,代码本身是完美的。然而,由于我的脚本是同步运行的,我希望将其转换为异步过程,以便在最短时间内完成任务,提供最佳性能并且不会阻塞。由于我从未使用过异步IO库,我非常困惑如何使它正常工作。我试图将我的脚本嵌入到异步IO过程中,但似乎行不通。如果有人能帮助我完成这个问题,我将非常感激。提前致谢。这是我错误的代码:

import requests ; from lxml import html
import asyncio

link = "http://quotes.toscrape.com/"

async def quotes_scraper(base_link):
        response = requests.get(base_link)
        tree = html.fromstring(response.text)
        for titles in tree.cssselect("span.tag-item a.tag"):
            processing_docs(base_link + titles.attrib['href'])

async def processing_docs(base_link):
        response = requests.get(base_link).text
        root = html.fromstring(response)
        for soups in root.cssselect("div.quote"):
            quote = soups.cssselect("span.text")[0].text
            author = soups.cssselect("small.author")[0].text
            print(quote, author)


        next_page = root.cssselect("li.next a")[0].attrib['href'] if root.cssselect("li.next a") else ""
        if next_page:
            page_link = link + next_page
            processing_docs(page_link)

loop = asyncio.get_event_loop()
loop.run_until_complete(quotes_scraper(link))
loop.close()

执行后,在控制台上看到的是:

RuntimeWarning: coroutine 'processing_docs' was never awaited
  processing_docs(base_link + titles.attrib['href'])

1
在你的程序中使用asyncio的目的是什么?requests无论如何都会同步执行HTTP查询。你需要通过loop.run_in_executor()来运行requests代码或者替换成aiohttp - Andrew Svetlov
@Andrew Svetlov,看到您的评论我有些困惑。我对此并不了解。那么我是在白费时间吗?我原以为程序会异步运行——更具体地说:请求将同时处理而不是排队等待一个请求完成。 - SIM
1
不,requests 是一个同步库。 你可以通过在 requests.get() 调用之前缺少 await 来确定它。 - Andrew Svetlov
3
顺便提一下,https://github.com/aosabook/500lines/tree/master/crawler 是一个异步爬虫的示例。它由Guido van Rossum和A. Jesse Jiryu Davis编写,底层使用aiohttp。明确一点:我是aiohttp维护者之一,编写了大约四分之一的asyncio源代码。我非常清楚我在说什么。 - Andrew Svetlov
感谢Andrew Svetlov的建议和链接。我一定会仔细阅读。 - SIM
1个回答

5
你需要使用await调用processing_docs()
替换为:
processing_docs(base_link + titles.attrib['href'])

使用:

await processing_docs(base_link + titles.attrib['href'])

并替换为:

processing_docs(page_link)

使用:

await processing_docs(page_link)

否则,它会试图同步运行异步函数并变得不开心!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接