3

pyppeteer我已经用 python 编写了一个脚本,并结合asyncio从其登录页面抓取不同帖子的链接,并最终通过跟踪通向其内页的 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()

我的问题:我怎样才能摆脱这个错误并异步执行?

4

1 回答 1

4

问题出在以下几行:

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从列表理解中删除。

于 2018-12-13T22:39:21.447 回答