python - 如何解决ConnectionError?
问题描述
Python中用requests模块抓取资料,可以出现我想要的资料,但是资料并不完整,后面会出现ConnectionError,可以怎么解决?我已经设置了Timeout。
我的代码如下:
from pprint import pprint
import requests
import json
dict_num = dict()
for num in range(1,1771):
url_api = "http://api.jisuapi.com/bencao/detail?appkey=bdc8ee0bb0227112&detailid={n}&isdetailed={n}".format(n=num)
r = requests.get (url_api,timeout=60)
data = r.json()
pprint (data)
detail2 = data
pprint (detail2)
with open ("bencao_detail2", mode="w", encoding="utf8") as file:
json.dump(detail2, file)
说明
其实这是爬虫的常见状况之一,即我们所要爬取的链接集合不可能都在第一次请求就成功爬取。
这里面的情况很多,比如网络不稳定,网站部署的策略(流量、反爬虫...)以及网站服务的拥塞情况等等。对于这种情况的解决我所知道的一般有如下几种常见方案:
等待重试
可以设置等待时间重试或者用队列将失败的请求放置到队列尾部,这种可以解决类似网络不稳定以及网站服务拥塞的情况。设置代理池
在代理池中抽取(可用)代理,然后分配给每一个请求。这种可以(一定程度上)解决网站部署的一些策略,当然有些比较强的反爬虫策略不一定起作用的,这里就不展开了。当然,这个一般结合方案1来使用,因为还是会出现网络不稳定以及网站服务拥塞的情况嘛。
上面所述的方案是建立在你的爬虫逻辑/策略是没有问题的。如果你的Error是404
(找不到文件或目录)或者500
(内部服务器错误)这种情况,显然你得修改你的爬取逻辑/策略了。所以这个地方是有必要获取HTTP状态码的。不过你这种爬取api的情况错误信息是会体现在返回json里面的。
鉴于你的情况我的建议是方案1:等待重试
解决
首先说一个误区,你将timeout
设成60s意义不大。设成60s几乎不能解决任何一种情况,而且也不需要这么高。timeout
大部分使用场景反而是不希望链接保持太长而迟迟没有结果,这种timeout
值也不会那么高。加上你每次请求的数据量不大,不如设低一点让他超时重试。
再具体到你的代码:
from pprint import pprint
import requests
import json
dict_num = dict() #这个没有用到啊?
for num in range(1,1771):
url_api = "http://api.jisuapi.com/bencao/detail?appkey=bdc8ee0bb0227112&detailid={n}&isdetailed={n}".format(n=num)
r = requests.get (url_api,timeout=60)
data = r.json()
pprint (data)
detail2 = data
pprint (detail2) #这个地方也甚是奇怪,details2 = data = r.json()这不都一样么?
with open ("bencao_detail2", mode="w", encoding="utf8") as file:
# 这个地方多说几句,首先'w'这种模式对于你这种上千个的请求不太合适
# 程序(因为错误)中断了,中间结果都没保存,又得重头来...
# 而且往往输出就是不一定就是对的或想要的,这又得重头来...
# 实际上我试了一下,你这个地方代码有问题,输出不是中文
json.dump(detail2, file)
我的方案,供参考
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 上面两行建议加上的,python3也应该如此吧
from pprint import pprint
import requests
import json
import time
def output(data):
# 这里有三个注意的点:
# 1. mode="a"
# 2. "{}\n" 一条结果一行
# 3. ensure_ascii=False
# 我没怎么在python3下处理编码的问题,我试了一下你的代码不能正确输出中文
# 得加上ensure_ascii=False
with open ("bencao_detail2", mode="a", encoding='utf8') as file:
file.write("{}\n".format(json.dumps(data, ensure_ascii=False)))
q = list(range(1, 1771)) #构造一个简单的队列,起始是1
while len(q): # 队列还有就执行
n = q.pop(0) # 取出队列的第一个
print("Fetching No.{}".format(n)) # 这里输出到哪一步了,可以帮助你从断点处重来
url_api = "http://api.jisuapi.com/bencao/detail?appkey=bdc8ee0bb0227112&detailid={n}&isdetailed={n}".format(n=n)
try:
r = requests.get (url_api,timeout=3.05)
except Exception as e:
print("Exception: {}".format(e))
q.append(n) # 出错放回到队列尾部
else:
data = r.json()
pprint(data)
output(data)
time.sleep(2) # 还是设置一个等待吧,太快的访问容易被屏蔽。可以自己改
这里再说明一下,我这里用的是队列的方法,构建了很简单一个队列。
也可以用等待的方式time.sleep(x)
,但我觉得没必要,不如直接处理下一个任务。
失败的任务放到队列尾部,最后再试。
我初步试了一下,好像没啥问题。
如果你的程序中断了,记下到了哪一步,然后更改队列起始。
这篇关于python - 如何解决ConnectionError?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!