在循环中单线程请求多个url导致请求超时 例如:
这是一个网站里面的20个子页面,我需要从每个子页面里面拿目标数据,第一个想到的就是for循环
import requests
for i in range(2, 20):
url_resp_list = requests.get(f"http://www.hnuit.edu.cn/p1/mtsj_{i}.html")
print(url_resp_list)
TimeoutError: [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。
**- 但是像这种一个循环里不停的访问url,会让http链接一直存在导致占用过多(从百度查的一个原因之一)出现连接超时的情况
1.ip被封。(能请求就说明ip没被封)
2.http的连接数超过最大限制。headers的Connection参数默认为keep-alive,导致之前所有的链接都一直存在,占用了后续的链接请求。
3.网站服务器太差,爬取请求的速度太快。(它急着响应,而网站的服务器不给力,就直接断掉了)
我可能就是访问的这个网站服务器太差了跟不上爬虫的速度响应太慢(可能),因为我访问豆瓣所有子页面时也用的是for循环,他没有出现这种问题**
**这是在百度上找到的方案,对于我的这个问题好像没什么用,只是增加了几个访问的url链接而已,还是满足不了需求
第二种方案就是自己试出来的,因为刚好学到了多线程,我想单线程压力大,那就把工作量大的任务多开几个线程,结果真的可以,速度比for循环更快,把一个工作单元封装为一个任务,丢到线程池里(资源足够的情况下)在线程池里加个循环,把所有任务都提交到池里,让这些线程去完成**
from concurrent.futures import ThreadPoolExecutor
import requests
def get_data(i):
url_resp_list = requests.get(f"http://www.hnuit.edu.cn/p1/mtsj_{i}.html")
print(url_resp_list)
print(f"线程{i}")
with ThreadPoolExecutor(50) as t2: # 开50个线程去完成这20个任务,也可以开15个,按照理想状态来说每个线程只需要一次url请求就可以了
for i in range(2, 20):
t2.submit(get_data, i)
通过截图就可以看到是很多个线程一起在跑,如果是单线程的话应该是有顺序的打印
总的来说就是把一个重复的操作抽象出来封装程一个任务,通过循环把所有任务都提交到线程池里
最重要的一点就是他不会像单线程一样,要是有一个链接无法响应,就会一直卡在那里,
而多线程不同,不会因为某个链接无法响应就无法运行,最多就是负责那个页面的线程拿不到数据而已