python - 如何解决ConnectionError?

查看:526
本文介绍了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. 等待重试
    可以设置等待时间重试或者用队列将失败的请求放置到队列尾部,这种可以解决类似网络不稳定以及网站服务拥塞的情况。

  2. 设置代理池
    在代理池中抽取(可用)代理,然后分配给每一个请求。这种可以(一定程度上)解决网站部署的一些策略,当然有些比较强的反爬虫策略不一定起作用的,这里就不展开了。当然,这个一般结合方案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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆