【问题标题】:Scraping content using pyppeteer in association with asyncio使用 pyppeteer 与 asyncio 关联来抓取内容
【发布时间】:2019-05-15 02:39:05
【问题描述】:

我用 python 结合pyppeteerasyncio 编写了一个脚本,以从其登录页面抓取不同帖子的链接,并最终通过跟踪通向其内页的 url 来获取每个帖子的标题.我这里解析的内容不是动态的。但是,我使用了pyppeteerasyncio 来查看它的效率如何asynchronously

以下脚本运行了一段时间,但随后出现错误:

File "C:\Users\asyncio\tasks.py", line 526, in ensure_future
raise TypeError('An asyncio.Future, a coroutine or an awaitable is '
TypeError: An asyncio.Future, a coroutine or an awaitable is required

这是我到目前为止所写的:

import asyncio
from pyppeteer import launch

link = "https://stackoverflow.com/questions/tagged/web-scraping"

async def fetch(page,url):
    await page.goto(url)
    linkstorage = []
    elements = await page.querySelectorAll('.summary .question-hyperlink')
    for element in elements:
        linkstorage.append(await page.evaluate('(element) => element.href', element))
    tasks = [await browse_all_links(link, page) for link in linkstorage]
    results = await asyncio.gather(*tasks)
    return results

async def browse_all_links(link, page):
    await page.goto(link)
    title = await page.querySelectorEval('.question-hyperlink','(e => e.innerText)')
    print(title)

async def main(url):
    browser = await launch(headless=True,autoClose=False)
    page = await browser.newPage()
    await fetch(page,url)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    future = asyncio.ensure_future(main(link))
    loop.run_until_complete(future)
    loop.close()

我的问题:我怎样才能摆脱该错误并异步执行操作?

【问题讨论】:

    标签: python python-3.x web-scraping python-asyncio pyppeteer


    【解决方案1】:

    问题出在以下几行:

    tasks = [await browse_all_links(link, page) for link in linkstorage]
    results = await asyncio.gather(*tasks)
    

    目的是让tasks 成为等待对象的列表,例如协程对象或期货。该列表将传递给gather,以便等待对象可以并行运行,直到它们全部完成。但是,列表推导包含一个 await,这意味着它:

    • 串行而不是并行执行每个browser_all_links以完成;
    • browse_all_links 调用的返回值放入列表中。

    由于browse_all_links 没有返回值,因此您将None 对象列表传递给asyncio.gather,它抱怨它没有得到等待对象。

    要解决此问题,只需从列表推导中删除 await

    【讨论】:

    • 我听从了你的建议并运行了代码@user4815162342。这次它给了我另一个错误。问题是它收集一个标题 15 次,而它应该产生 15 个不同的标题。 Full traceback can be found here。谢谢。
    • @robots.txt 也许问题是你也向所有协程发送相同的page,所以他们互相踩到了对方的脚趾?您可能需要在 browse_all_links 而不是 main 中创建 page
    • 这一次我尝试完全按照您的建议修改我的脚本,但仍然获得了 15 次我之前提到的单个链接。 Check out my current script here。非常感谢@user4815162342。
    • @robots.txt 您仍在向所有browse_all_links 发送相同的page 对象。您需要将页面创建,即page = await browser.newPage(),移动到browse_all_links
    • 现在,@user4815162342 似乎工作正常。请check out this link看看我最后做了什么。我仍然不确定我能否正确地遵循您的指示。从一开始,我就试图不为新的 url 创建新的浏览器,因为它们会给计算机带来巨大的负担。然而,这就是你的意思。非常感谢到目前为止与我在一起。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-14
    • 2019-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多