加速美丽汤(Beautiful Soup)的方法

3

我正在使用BeautifulSoup在一个for循环内解析数千个网站。这是我的代码片段:

def parse_decision(link):
    t1 = time.time()
    decisionpage = urllib.urlopen(link)
    t2 = time.time()
    soup = BeautifulSoup(decisionpage.read(), 'lxml')
    t3 = time.time()
    # ...
    # Parsing happens here and returns a pandas dataframe

由于代码运行时间太长,我开始调查原因,并发现BeautifulSoup读取决策页面所需的时间变化很大。以下是每个步骤完成所需的秒数片段:

    Element | t2-t1  |  t3-t2
    1.      | 0.073  | 60.023
    2.      | 0.096  | 0.005
    3.      | 0.096  | 60.016
    4.      | 0.064  | 0.006

正如你所看到的,大约每两个网站中就有一个需要花费60秒 的时间才能加载出来,尽管这些网站都是相同的格式并且包含着大致相同的信息。这些网站类似于以下这个法院判决的网页: http://www.nycourts.gov/reporter/3dseries/2003/2003_17749.htm 有没有人知道为什么会存在这样的性能差异,并且可能有什么方法可以克服它?非常感谢任何帮助。

1
你确定这与BeautifulSoup有关吗?考虑到60秒的数字,我倾向于认为你正在爬取的网站正在对你进行限制。 - user2357112
3个回答

2

美丽汤不慢,而是决策网页的read()方法慢。

urllib.urlopen返回一个套接字对象,实际的http请求发生在.read()方法中。因此你的瓶颈在于网络:无论是你的互联网连接还是远程网站都很慢(或者两者都是)。

由于I/O受限而且有几千个网站,你可以通过同时运行几个线程解析不同的网站来显著加快速度。


类似于这样的 https://docs.python.org/2/library/thread.html 还是更像 Python 的 multiprocessing 模块? - calpyte

0

在爬取大型网站时,请使用线程:concurrent.futuresthreading。在网络I/O中,线程read()读取网络资源时,大部分时间都是闲置等待的。这是非常适合使用并发的情况。

其次,如果您不是在爬取特定的内容,只是跟随锚点标签,请使用正则表达式。它们比我的机器上的HTMLParser快100倍。速度提升将是显著的。


0

你的问题可能有一个矛盾的解决方案。很明显,你试图抓取的网站正在限制你。

我建议尝试尊重他们的意愿,在你的请求之间添加暂停。如果在循环结尾处添加time.sleep(2)(并且在脚本顶部添加import time),它可能会防止你被限制60秒。

尝试一下,看看哪个数字对你最有效。


我完全没有想到这个可能性。我一定会尝试一下。谢谢你指出来! - calpyte
是的,BeautifulSoup 的性能还算不错。我不建议增加请求速率,这样做不好,如果你一次向法院网站发送太多请求,他们可能会决定邀请你过去;) - Josh Rumbut

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接