前言

我们爬取一个网站需要花费一些时间,其中等待网站响应是比较费时间的,因为网站的响应速度取决与网站的性能,所以我们真正爬取网站的时间是比较少的,于是我们可以利用空闲的时间去执行其他页面的爬取。

并发和多线程

并发

你早上起床先把米放到锅里煮粥,你肯定不会傻傻地一直等着粥煮好。在粥煮的这段时间里,你肯定会去洗漱、打扫房间等。等你洗漱、打扫完毕,粥也煮好了。

多线程

初始化一个线程池:

import time
import requests
# 导入 concurrent.futures 这个包
from concurrent import futures

url = ['https://www.weidaima.net']
# 初始化一个线程池,最大的同时任务数是 5
executor = futures.ThreadPoolExecutor(max_workers=5)
session = requests.Session()

concurrent 是 Python 自带的库,这个库具有线程池和进程池、管理并行编程任务、处理非确定性的执行流程、进程/线程同步等功能。

一台电脑/手机能同时运行多少线程取决于它的处理器、内存的配置。如果运行的线程数太多,操作系统在安排这些线程的执行顺序等事情上要花费很大的代价。

提交任务到线程池:

fs = []
for url in urls:
  # 提交任务到线程池
  f = executor.submit(session.get, url)
  fs.append(f)

executor 就是我们刚刚初始化的线程池,我们调用 executorsubmit() 方法往里面提交任务。第一个参数 session.get 是提交要运行的函数,第二个参数 url 是提交的函数运行时的参数。

executor.submit() 方法会给我们一个返回值,它是一个 future 对象 ,我们把它赋值给变量 f。

future 这个单词的原意是 未来 。在并发编程的领域,future 对象这个东西通常保存着函数调用完成时的结果。

等待任务全部完成:

# 等待这些任务全部完成
futures.wait(fs)

fs 是保存了上面所有任务的 future 对象的列表,futures.wait() 方法可以等待直到 fs 里面所有的 future 对象都有结果为止。

Tips:这一步如果没有执行,去获取某个任务的结果时同样会等待它完成,但是逻辑上可能让人困惑。所以在这里直接等待所有任务都完成,我们再进行下一步。

获取所有任务结果:

# 获取任务的结果
result = [f.result().text for f in fs]

fs 是保存了上面所有任务的 future 对象的列表,我们遍历所有任务的 future 对象,调用 future 对象的 result() 方法,就能得到任务的结果。

最后修改:2022 年 01 月 12 日
如果觉得我的文章对你有用,请随意赞赏