【问题标题】:Optimal way to parallel scraping into a dataframe/csv file并行抓取数据帧/csv文件的最佳方法
【发布时间】:2021-10-04 22:32:42
【问题描述】:

假设我有一个充满数据的数据框,一列包含不同的 url,我想在数据框的每个 url 的页面上抓取价格(非常大,超过 15k 行)。而且我希望这种抓取连续运行(当它到达网址的末尾时,它会一次又一次地开始)。每次抓取价格时都会更新数据框的最后一列(价格)。

这是一个玩具数据框的可视化示例:

Col 1 ... Col N  URL                             Price
XXXX  ... XXXXX  http://www.some-website1.com/   23,5$
XXXX  ... XXXXX  http://www.some-website2.com/   233,5$
XXXX  ... XXXXX  http://www.some-website3.com/   5$
XXXX  ... XXXXX  http://www.some-website4.com/   2$
.
.
.

我的问题是:知道我可以使用 request/selenium/bs4 实现解决方案,使用并行方法(多线程......)抓取这些 URL 的最有效方法是什么......(我可以学得很漂亮很多东西)所以我想要一个理论答案而不是一些代码行,但如果你有一个块要发送,不要犹豫:)

谢谢

【问题讨论】:

  • 我认为您在这里针对问题的错误部分。你真的不需要多线程来进行网络抓取——这是一个 IO 绑定任务。相反,您应该看看 pythons async/await (asyncio) 功能,它允许您在不需要线程的情况下同时抓取许多目标。

标签: python pandas web-scraping parallel-processing


【解决方案1】:

您可以使用下一个示例来定期检查 URL。它使用itertools.cycledf.iterrows。然后在Pool.imap_unordered 中使用这个生成器来获取数据:

import requests
from time import sleep
from itertools import cycle
from bs4 import BeautifulSoup
from multiprocessing import Pool

headers = {
    "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:92.0) Gecko/20100101 Firefox/92.0"
}


def get_data(tpl):
    idx, row = tpl

    r = requests.get(row["url"], headers=headers)
    soup = BeautifulSoup(r.content, "html.parser")

    sleep(1)

    return (
        idx,
        soup.find(class_="Trsdu(0.3s) Fw(b) Fz(36px) Mb(-4px) D(ib)").text,
    )


if __name__ == "__main__":

    c = cycle(df.iterrows())

    with Pool(processes=2) as p:
        for i, (idx, new_price) in enumerate(p.imap_unordered(get_data, c)):
            df.loc[idx, "Price"] = new_price

            # print the dataframe only every 10th iteration:
            if i % 10 == 0:
                print()
                print(df)
            else:
                print(".", end="")

打印:

...

                                     url   Price
0  https://finance.yahoo.com/quote/AAPL/  139.14
1  https://finance.yahoo.com/quote/INTC/   53.47
.........

...and so on

df 已使用:

                                     url
0  https://finance.yahoo.com/quote/AAPL/
1  https://finance.yahoo.com/quote/INTC/

【讨论】:

  • 感谢您的回答。我也有这个想法,但我在这篇文章 (stackoverflow.com/questions/16476924/…) 上看到所有“iter”-ish pandas 函数根本不是最优的。我总是尝试使用“.apply”或列表理解来矢量化我的操作。我已经尝试使用 pandas apply 实现多线程,但没有成功。
  • @Jinter 好吧,您正在发出 HTTP 请求,因此不能“矢量化”(在 数字 意义上)。只需遍历每一行,发出请求并存储新数据。 multiprocessing.Pool 将并行化它。
  • 我在晚上考虑过,是的,你是对的。由于每个请求的持续时间,如果我设法使用 pandas apply 来填写 df,所获得的时间将非常低。我会使用你的解决方案谢谢你,祝你有美好的一天
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
  • 2017-12-25
  • 1970-01-01
  • 2010-09-24
相关资源
最近更新 更多