使用 Python 和 asyncio 进行 Web Scraping

Posted

技术标签:

【中文标题】使用 Python 和 asyncio 进行 Web Scraping【英文标题】:Web Scraping with Python in combination with asyncio 【发布时间】:2018-02-13 20:10:24 【问题描述】:

我用 python 编写了一个脚本来从网页获取一些信息。如果将代码从 asyncio 中取出,它本身就可以完美运行。然而,由于我的脚本同步运行,我想让它通过异步进程,以便它在尽可能短的时间内完成任务,提供最佳性能,显然不是以阻塞方式。因为我从来没有使用过这个 asyncio 库,所以我很困惑如何让它成功。我试图让我的脚本适合 asyncio 进程,但它似乎不正确。如果有人伸出援助之手来完成这项工作,我将非常感谢他。谢谢是提前。这是我的错误代码:

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'])

【问题讨论】:

在你的程序中使用 asyncio 有什么意义? requests 无论如何都会同步执行 HTTP 查询。您需要通过loop.run_in_executor() 运行请求代码或将requests 替换为aiohttp @Andrew Svetlov,看到你的评论我很困惑。我真的没有这方面的知识。那我是不是白白浪费时间了?我认为该程序将异步运行 - 更具体地说:请求将同时处理,而不是排队等待一个请求完成。 不,requests 是一个同步库。您可以通过在requests.get() 通话之前缺席await 来弄清楚。 BTW github.com/aosabook/500lines/tree/master/crawler 是一个异步爬虫示例。它由 Guido van Rossum 和 A. Jesse Jiryu Davis 编写,底层使用 aiohttp。明确一点:我是 aiohttp 维护者,编写了大约四分之一的 asyncio 源代码。我很清楚自己在说什么。 感谢 Andrew Svetlov 的建议和链接。我一定会完成的。 【参考方案1】:

您需要使用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)

否则它会尝试同步运行异步函数并感到不安!

【讨论】:

以上是关于使用 Python 和 asyncio 进行 Web Scraping的主要内容,如果未能解决你的问题,请参考以下文章

在Python中使用asyncio进行异步编程

使用 Python 3.7+ 进行 100k API 调用,使用 asyncio 并行进行 100 [重复]

在 Python 中使用 asyncio 并行化 Web 任务

Python学习---Python的异步---asyncio模块(no-http)

如何使用 asyncio 和 aiohttp 异步通过 api 响应进行分页

Python 的 asyncio.Event() 跨不同的类