asyncio.gather等待的时间不够长,无法完成所有任务

问题描述

我正在编写代码,以使用asyncio,aiohttp和BeautifulSoup从输入网址列表中获取一些链接

以下是相关代码的片段:

def async_get_jpg_links(links):
    def extractLinks(ep_num,html):
        soup = bs4.BeautifulSoup(html,'lxml',parse_only = bs4.soupStrainer('article'))
        main = soup.findChildren('img')
        return ep_num,[img_link.get('data-src') for img_link in main]

    async def get_htmllinks(session,ep_num,ep_link):
        async with session.get(ep_link) as response:
            html_txt = await response.text()
        return extractLinks(ep_num,html_txt)

    async def get_jpg_links(ep_links):
        async with aiohttp.ClientSession() as session:
            tasks = [get_htmllinks(session,num,link) 
                    for num,link in enumerate(ep_links,1)]
            return await asyncio.gather(*tasks)

    loop = asyncio.get_event_loop()
    return loop.run_until_complete(get_jpg_links(links))

然后我再调用jpgs_links = dict(async_get_jpg_links(hrefs)),其中hrefs是一堆链接(〜170个链接)。

jpgs_links应该是带有数字键和一堆列表作为值的字典。一些值作为空列表返回(应该用数据填充)。当我减少hrefs中的链接数量时,更多列表又变满了。

对于下面的照片,我在两分钟之间重新运行了相同的代码,如您所见,我得到了不同的列表,这些列表返回为空,而不同的列表恢复为满。

是不是asyncio.gather没有等待所有任务完成?

如何使asyncio使我不返回任何空列表,同时又保持hrefs中的链接数量很高?

result of the code

解决方法

因此,事实证明,我发送的某些网址引发了错误:

raise ClientResponseError(
aiohttp.client_exceptions.ClientResponseError: 504,message='Gateway Time-out',...

所以我改变了

async def get_htmllinks(session,ep_num,ep_link):
        async with session.get(ep_link) as response:
            html_txt = await response.text()
        return extractLinks(ep_num,html_txt)

async def get_htmllinks(session,ep_link):
    html_txt = None
    while not html_txt:
        try:
            async with session.get(ep_link) as response:
                response.raise_for_status()
                html_txt = await response.text()
        except aiohttp.ClientResponseError:
            await asyncio.sleep(1)
    return extractLinks(ep_num,html_txt)

这是在睡眠一秒钟后重试连接(await asyncio.sleep(1)会这样做)。

与asyncio或BeautifulSoup毫无关系。