Python爬虫之线程池的使用
线程池简介
在爬虫过程中,网络请求是一个常见且耗时的操作,每个请求都需要等待服务器的响应,这会导致一些性能过低的爬虫速度非常慢。而多线程编程可以有效地提高爬虫的效率。线程池是一种多线程优化技术,它可以在爬取数据时并行执行多个任务,以节约时间和资源,提高爬虫效率。
线程池通过自动管理工作线程来节约线程创建和销毁的时间和资源。池中的线程在有任务时才会执行任务,如果没有任务则会阻塞等待。这样的好处是可以避免不必要的线程创建和销毁开销,而且能够更好的控制线程资源,优化CPU调度。
Python中有很多线程池模块可以使用,其中标准库 concurrent.futures
是比较常用的一个,它提供了一些非常方便的工具函数,可以帮助我们轻松地实现线程池中任务的执行。
concurrent.futures 模块
在使用 concurrent.futures
模块前,我们需要对其中的两个对象进行了解。
1、ThreadPoolExecutor
ThreadPoolExecutor
是一个线程池执行器,提供了实现任务执行的方法。通过 ThreadPoolExecutor
中的 submit()
函数可以将待执行的任务提交到线程池中。submit()
函数返回一个 Future
对象,该对象代表的是将来可以拿到结果的一个对象。当任务执行完毕,Future
对象的 result()
方法能够获取到任务执行的结果。
2、ProcessPoolExecutor
ProcessPoolExecutor
是一个进程池执行器,与 ThreadPoolExecutor
相似。不同的是,它会使用多进程来执行任务。
使用样例
样例一
任务:爬取多个网页
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
def get_html(url):
response = requests.get(url)
return response.text
urls = [
'https://www.baidu.com',
'https://www.sina.com.cn',
'https://www.qq.com'
]
with ThreadPoolExecutor(max_workers=3) as executor:
# 提交任务
future_to_url = {executor.submit(get_html, url): url for url in urls}
# 结果输出
for future in as_completed(future_to_url):
url = future_to_url[future]
try:
data = future.result()
except Exception as e:
data = f"{url} error: {e}"
print(f"{url} 页面长度为 {len(data)}")
这个样例中,通过 ThreadPoolExecutor
的 submit()
方法,将三个待执行的任务提交到线程池中。as_completed()
函数则按照任务完成的顺序,输出各个页面的长度。
样例二
任务:异步请求线上API,并解析json
import requests
import json
from concurrent.futures import ThreadPoolExecutor, as_completed
def get_data(url):
response = requests.get(url)
return response.json()
urls = [
'http://api.example.com/user/1',
'http://api.example.com/user/2',
'http://api.example.com/user/3'
]
with ThreadPoolExecutor(max_workers=3) as executor:
# 提交任务
future_to_url = {executor.submit(get_data, url): url for url in urls}
# 解析json数据
data_list = []
for future in as_completed(future_to_url):
url = future_to_url[future]
try:
data = future.result()
data_list.append(data)
except Exception as e:
print(f"{url} error: {e}")
# 输出结果
print(json.dumps(data_list, indent=4, ensure_ascii=False))
在这个样例中,我们首先通过 ThreadPoolExecutor
发起了三个并发的get请求,然后将返回的json数据解析后,添加到一个列表中。最终,我们将这个列表输出,其实际数据来源于三个不同的API接口。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python爬虫之线程池的使用 - Python技术站