【发布时间】:2018-12-12 16:06:03
【问题描述】:
我在 python 中编写了一个脚本,使用asyncio 与aiohttp 库的关联来解析从this website 的表格中单击联系信息按钮时启动的弹出框中的名称异步。该网页显示了 513 个页面的表格内容。
我在尝试使用asyncio.get_event_loop() 时遇到了此错误too many file descriptors in select(),但是当我遇到this thread 时,我可以看到有人建议使用asyncio.ProactorEventLoop() 来避免此类错误,所以我使用了后者但注意到,即使我遵守了建议,脚本也只会从几页中收集名称,直到它引发以下错误。我该如何解决这个问题?
raise client_error(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host www.tursab.org.tr:443 ssl:None [The semaphore timeout period has expired]
这是我迄今为止的尝试:
import asyncio
import aiohttp
from bs4 import BeautifulSoup
links = ["https://www.tursab.org.tr/en/travel-agencies/search-travel-agency?sayfa={}".format(page) for page in range(1,514)]
lead_link = "https://www.tursab.org.tr/en/displayAcenta?AID={}"
async def get_links(url):
async with asyncio.Semaphore(10):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
text = await response.text()
result = await process_docs(text)
return result
async def process_docs(html):
coros = []
soup = BeautifulSoup(html,"lxml")
items = [itemnum.get("data-id") for itemnum in soup.select("#acentaTbl tr[data-id]")]
for item in items:
coros.append(fetch_again(lead_link.format(item)))
await asyncio.gather(*coros)
async def fetch_again(link):
async with asyncio.Semaphore(10):
async with aiohttp.ClientSession() as session:
async with session.get(link) as response:
text = await response.text()
sauce = BeautifulSoup(text,"lxml")
try:
name = sauce.select_one("p > b").text
except Exception: name = ""
print(name)
if __name__ == '__main__':
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
loop.run_until_complete(asyncio.gather(*(get_links(link) for link in links)))
简而言之,process_docs() 函数所做的就是从每个页面收集data-id 数字,然后将它们重新用作此https://www.tursab.org.tr/en/displayAcenta?AID={} 链接的前缀,以从弹出框中收集名称。一个这样的 id 是8757,一个这样的合格链接因此是https://www.tursab.org.tr/en/displayAcenta?AID=8757。
顺便说一句,如果我将 links 变量中使用的最高数字更改为 20 或 30 左右,它会顺利进行。
【问题讨论】:
-
您确定这是使用
asyncio.Semaphore的正确方法吗?您的代码创建了一个值为 10 的Semaphore,并且只获取了一次,因此它基本上什么都不做。您可能希望在这些函数之外创建Semaphore并将其传递给所有get_links调用... -
感谢您的评论@Bakuriu。我从this post 发现了这个想法(以这种方式使用信号量)。
-
仔细检查您在上一条评论中链接的代码!你没有做同样的事情
标签: python python-3.x web-scraping python-asyncio aiohttp