将多线程或异步添加到 Web 抓取

Posted

技术标签:

【中文标题】将多线程或异步添加到 Web 抓取【英文标题】:Add multithreading or asynchronous to web scrape 【发布时间】:2018-09-25 08:59:07 【问题描述】:

实现多线程以加快网页抓取速度的最佳方法是什么? 使用 Pool 会是一个很好的解决方案 - 如果是这样,我将在我的代码中的哪个位置实现它?

import requests
from multiprocessing import Pool

with open('testing.txt', 'w') as outfile:
    results = []
    for number in (4,8,5,7,3,10):
        url = requests.get('https://www.google.com/' + str(number))
        response =(url)
        results.append(response.text)
        print(results)

    outfile.write("\n".join(results))

【问题讨论】:

看看scrapy,这是一个很棒的抓取工具包。 是否需要将每个请求写入单个文件?我认为多线程化会有问题。 如果我不写入文件,我的解释器会在文件太大时切断。 【参考方案1】:

这可以很容易地移到池中。 Python 带有基于进程和线程的池。使用哪个是一个权衡。进程更适合并行化运行代码,但在将结果传递回主程序时成本更高。在您的情况下,您的代码主要在等待 url,并且返回对象相对较大,因此线程池是有意义的。

我根据需要在 Windows 机器上将代码移动到 if __name__ 中。

import requests
from multiprocessing import Pool
from multiprocessing.pool import ThreadPool

def worker(number):
    url = requests.get('https://www.google.com/' + str(number))
    return url.text

# put some sort of cap on outstanding requests...
MAX_URL_REQUESTS = 10

if __name__ == "__main__":
    numbers = (4,8,5,7,3,10)
    with ThreadPool(min(len(numbers), MAX_URL_REQUESTS)) as pool:
        with open('testing.txt', 'w') as outfile:
            for result in pool.map(worker, numbers, chunksize=1):
                outfile.write(result)
                outfile.write('\n')

【讨论】:

现在我明白了(...来自以前删除的 cmets) 我的错,我的意思是min(len(numbers), MAX_URL_REQUESTS)。这是池中使用的线程数。我取了一些任意的“最大线程数”中的最小值和问题实际所需的数量。已在代码中修复。 tdelaney - 太棒了!谢谢,我想使用 tqdm 或某种进度条。我将在哪里实施? 您可以在for result in pool... 循环中更新进度。 map 按照您传入参数的顺序返回结果。使用pool.imap_unordered 可以更快地返回结果(使进度更准确)。如果关联很重要,您甚至可以将原始号码与结果作为tuple 传回。

以上是关于将多线程或异步添加到 Web 抓取的主要内容,如果未能解决你的问题,请参考以下文章

将多线程输出保存到txt文件

将多线程 Delphi 应用程序移植到 Mac:我的选择是啥?

单线程多任务异步抓取(asyncio)

多线程异步操作导致异步线程获取不到主线程的request信息

将多线程与 dlib 的 shape_predictor 一起使用

是否可以将多线程JavaFX AudioClip声音的混合结果记录到磁盘上?