问题描述
我正在编写代码,以使用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
中的链接数量很高?
解决方法
因此,事实证明,我发送的某些网址引发了错误:
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毫无关系。