【问题标题】:Parsing large number of HTML files with asyncio aiofiles and parsing them in pandas DataFrame使用 asyncio aiofiles 解析大量 HTML 文件并在 pandas DataFrame 中解析它们
【发布时间】:2019-12-19 08:32:51
【问题描述】:

我在磁盘上有大约 40 000 个 HTML 文件,并使用 Beautiful Soup 解析 HTML 并返回每个 HTML 的字典。 在读取/解析期间,我将所有字典附加到列表中,并在最后创建 pandas DataFrame。

在同步模式下一切正常,但运行需要很长时间,所以我想用aiofiles 运行

目前我的代码如下所示:

# Function for fetching all ad info from single page
async def getFullAdSoup(soup):
     ...
     adFullFInfo = {} # dictionary parsed from Beautifoul soup object
    return await adFullFInfo


async def main():
    adExtendedDF = pd.DataFrame()
    adExtendednfo = {}
    htmls = glob.glob("HTML_directory" + "/*.html") # Get all HTML files from directory

    htmlTasks = [] # Holds list of returned dictionaries
    for html in natsorted(htmls):
        async with aiofiles.open(html, mode='r', encoding='UTF-8', errors='strict', buffering=1) as f:
            contents = await f.read()
            htmlTasks.append(getFullAdSoup(BeautifulSoup(contents, features="lxml")))
        htmlDicts = await asyncio.gather(*htmlTasks)
    adExtendedDF = pd.DataFrame(data=htmlDicts, ignore_index=True)


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

我得到的错误是:

文件“C:/Users/.../test.py”,第 208 行,在 getFullAdSoup 中 return await adFullFInfo TypeError: object dict can't be used in 'await' expression

我发现了类似的问题here,但我无法解决。 我不知道如何将解析函数转换为异步模式以及如何迭代调用该函数的文件。

【问题讨论】:

  • 你的错误显然是因为 await adFullFInfo 这是一个字典,为什么会这样?
  • asyncio 也适用于繁重的 IO 和 Web 请求,读取和处理多个文件最好使用多处理
  • 我知道。想法是将其转换为可在 asyncio 中使用的东西。

标签: python pandas asynchronous python-asyncio python-aiofiles


【解决方案1】:

您的错误发生是因为您等待一个 dict,我猜您误解了,您不需要在 return 语句中等待它是异步的。我会这样重构它

# Function for fetching all ad info from single page
async def getFullAdSoup(soup):
     ...
     adFullFInfo = {} # dictionary parsed from Beautifoul soup object
    return adFullFInfo #*****1****


async def main():
    adExtendedDF = pd.DataFrame()
    adExtendednfo = {}
    htmls = glob.glob("HTML_directory" + "/*.html") # Get all HTML files from directory

    htmlTasks = [] # Holds list of returned dictionaries
    for html in natsorted(htmls):
        async with aiofiles.open(html, mode='r', encoding='UTF-8', errors='strict', buffering=1) as f:
            contents = await f.read()
            htmlTasks.append(asyncio.create_task( #****2****
                getFullAdSoup(BeautifulSoup(contents, features="lxml"))))
        await asyncio.sleep(0) #****3****
    htmlDicts = await asyncio.gather(*htmlTasks) #****4****
    adExtendedDF = pd.DataFrame(data=htmlDicts, ignore_index=True)


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

4 个变化:

  1. 无需等待字典
  2. 使用 asyncio.create_task 安排任务尽快运行
  3. sleep(0) 释放事件循环,让任务开始运行
  4. 将收集方法移到循环之外,这样您就可以一次收集所有任务,而不是一次收集一个。

2 和 3 是可选的,但我发现它会产生很大的速度差异,具体取决于您在做什么

【讨论】:

  • 应用了更改,缩短了 5 个文件的文件列表。脚本没有结束..几分钟后仍然没有任何内容写入 adExtendedDF。
猜你喜欢
  • 2021-03-07
  • 1970-01-01
  • 2016-09-23
  • 1970-01-01
  • 1970-01-01
  • 2014-09-02
  • 2022-01-02
  • 2014-01-29
  • 1970-01-01
相关资源
最近更新 更多