V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Nisenasdf
V2EX  ›  Python

python requests, 记遇到的一个问题: [Errno 104] Connection reset by peer

  •  
  •   Nisenasdf · 2016-11-14 23:03:36 +08:00 · 10126 次点击
    这是一个创建于 2917 天前的主题,其中的信息可能已经有所发展或是发生改变。

    记遇到的一个问题:[Errno 104] Connection reset by peer

    今天工作上有个需求,数据库有个表有将近 3 万条 url 记录,每条记录都是一个图片,我需要请求他们拿到每个图片存到本地。一开始我是这么写的(伪代码):

    import requests
    
    for url in urls:
        try:
            r = requests.get(url).content
            save_image(r)
        except Exception, e:
            print str(e)
    

    然而在服务器上运行时, 会发现每隔一些请求会报类似下面的错误:

    HTTPConnectionPool(host='wx.qlogo.cn', port=80): Max retries exceeded with url: /mmopen/aTVWntpJLCAr2pichIUx8XMevb3SEbktTuLkxJLHWVTwGfkprKZ7rkEYDrKRr5icyDGIvU4iasoyRrqsffbe3UUQXT5EfMEbYKg/0 (Caused by <class 'socket.error'>: [Errno 104] Connection reset by peer)
    

    这让我想起了之前通过hacker news api 在自己电脑上请求一条一条数据时,为了加快处理速度,采用多进程的方式请求接口,也会出现这样的错误。之前我是做了错误记录直接 pass 了,这次情况下因为需要请求所有图片,在 google 查了相关原因,大概是因为我频繁请求,服务器关闭了部门请求连接。参见这里这里这里。 所以我粗暴地这么做,还真解决了:

    import requests
    
    for url in urls:
        for i in range(10):
            try:
                r = requests.get(url).content
            except Exception, e:
                if i >= 9:
                    do_some_log()
                else:
                    time.sleep(0.5)
            else:
                time.sleep(0.1)
                break
    
         save_image(r)
    

    代码很简陋,但可以说明大体解决方案,在每个请求间增加延时可以减少大部分请求拒绝,但还是存在一些请求被拒绝的,所以在那部分请求被拒绝后,发起重试,在被拒 10 次后才善罢甘休(记录到日志)。在实际的请求中,加了 0.1s 的延迟被拒绝的情况明显少了很多,被拒绝重试的次数最多为 3 次,最后成功地取下了全部图片。

    9 条回复    2016-11-18 00:18:32 +08:00
    hastelloy
        1
    hastelloy  
       2016-11-15 07:37:14 +08:00 via Android
    除了睡觉还有什么不简单的解决方式呢?楼下的说说?
    Nisenasdf
        2
    Nisenasdf  
    OP
       2016-11-15 09:01:01 +08:00
    @hastelloy 没有什么是睡一觉不能解决的,如果有,那就睡两觉
    kevin8096
        3
    kevin8096  
       2016-11-15 11:08:47 +08:00
    。。。。。
    mayne95
        4
    mayne95  
       2016-11-15 14:10:46 +08:00 via Android
    整个 ip 池,头部也多整几个。换来换去应该就可以了。
    sakwu
        5
    sakwu  
       2016-11-16 00:18:15 +08:00
    最近在做一个类似的爬虫,遇到一个问题就系假若数据库里面有个图片 url 被屏蔽了, 404 ,怎么跳过这条 URL 或者重新下载这个图片。

    我目前状况是要么卡死,设置 timeout 也是抛出异常然后就中断了,没法进去进行下载
    Nisenasdf
        6
    Nisenasdf  
    OP
       2016-11-16 10:36:52 +08:00
    @mayne95 有道理啊,改天找机会试试
    Nisenasdf
        7
    Nisenasdf  
    OP
       2016-11-16 10:38:25 +08:00
    @sakwu 不太明白你遇到的问题,既然知道 404 了,是没做相应的异常处理?
    sakwu
        8
    sakwu  
       2016-11-16 22:30:00 +08:00
    @Nisenasdf 额我是新手, try.except 了,但是依然中止了。

    for img in range(len(img_name)):
    try:
    img_data = request.urlopen(img_add[img], timeout=5).read()
    except Exception as e:
    print(img_name[img] + '下载失败' + e)
    fout_img = open('images/' + img_name[img] + '.jpg', 'wb')
    fout_img.write(img_data)

    fout_img.close()
    print(img_name[img] + '下载成功')


    如果 img_add 里有一个 URL 是错误的,下载就会中断,不懂为啥
    期待是这样的输出的:
    img_name1 下载成功
    img_name1 下载成功
    img_name1 下载失败: time out
    img_name1 下载成功
    img_name1 下载成功
    Nisenasdf
        9
    Nisenasdf  
    OP
       2016-11-18 00:18:32 +08:00   ❤️ 1
    @sakwu 代码没锁紧看起来--!, 你可以 debug 看一下, 404 能不能走到 exception 的异常处理里面, 404 是直接 exception 还是 直接 timeout 5 秒继续后面的, 调试看一下应该不难解决;)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2828 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 09:13 · PVG 17:13 · LAX 01:13 · JFK 04:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.