代理ip池的实现原理_scrapy爬虫ip代理池

02fb5b12bd5f8c4e9bcf170ac1b211ae.png

最近爬取某个网站的书籍信息,大概请求几百次之后网站就会出现302 跳转提示ip异常需要登录。于是就用挂代理换ip的方法。网上看了下,大部分都是从把从网上爬取到的代理ip写到txt里。然后scrapy 加载这个txt,然后随机获取一个ip爬取数据。这种方式有很多弊端:ip用完了,爬虫就停止了。每个ip用一次就换了,scrapy没多久就会停止。

经过两天的研究,我终于写出了自己满意的代码。这个scrapy 代理中间件可以满足以下要求:

1,从一个ip代理的接口获取ip地址(ip代理池 github上有很多项目)
2,使用这个ip爬取数据,如果没有被网站Ban掉就一直使用这个ip
3,如果这个ip失效了,或者是也被ban了,就在从ip接口里再获取一个ip继续请求

主要就是在中间件里增加一个方法就行

class RandomProxy(object):
    def __init__(self, settings):
        self.PROXY_URL = settings.get('PROXY_URL')
        self.chosen_proxy = ''


        if self.PROXY_URL is None:
                raise KeyError('需要先设置获取代理ip接口的地址')
        #从地址获取一个ip
        self.chosen_proxy =self.getProxy()


    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler.settings)

    def getProxy(self):
        log.msg('get proxy')
        proxy_addr=json.loads(requests.get(self.PROXY_URL).text)['ip']
        log.msg("[+]---get proxy ip is:" + proxy_addr)
        return proxy_addr

    def delip(self, proxy):
        log.msg("要删除的ip:" + proxy)
        sql = 'delete from ip where data =%s' % ''' + proxy + '''
        sta = cursor.execute(sql)
        log.msg(sql)
        log.msg(sta)
        if sta > 0:
            log.msg("del band ip from databases")
            db.connection.commit()
        else:
            log.msg('del ip faile')

    def process_request(self, request, spider):
        if 'proxy' in request.meta:
            if request.meta["exception"] is False:
                return
        request.meta["exception"] = False
        request.meta['proxy'] ="http://" + self.chosen_proxy

    def process_response(self, request, response, spider):

        if response.status in [403, 400,302] and 'proxy' in request.meta:
            log.msg('Response status: {0} using proxy {1} retrying request to {2}'.format(response.status, 
                                                                                          request.meta['proxy'],
                                                                                          request.url))
            proxy = request.meta['proxy']
            del request.meta['proxy']
            proxyip = proxy.split("//")[1]
            try:
                #删除数据库里的ip
                self.delip(proxyip)
                log.msg('deleted banned proxy , proxy %s' % proxyip)
            except KeyError:
                pass
            self.chosen_proxy = self.getProxy()#这个代理被403,302了 重新获取
            return request
        return response

    def process_exception(self, request, exception, spider):
        if 'proxy' not in request.meta:
            log.msg("没代理错了,需要检查")
            return
        else:
            log.msg("有代理也错了,把数据库的ip删掉")
            proxy = request.meta['proxy']
            proxyip = proxy.split("//")[1]
            try:
                # 删除数据库里的ip
                self.delip(proxyip)
            except KeyError:
                pass
            request.meta["exception"] = True
            log.msg("重新获取ip")
            self.chosen_proxy=self.getProxy()
            return  request
       

然后在settings.py 中配置你的获取ip代理接口的地址

PROXY_URL = 'http://xxxx:3000/v2/ip'

需要注意的是 中间件里的 这段代码

proxy_addr=json.loads(requests.get(self.PROXY_URL).text)['ip']

你要根据你的实际情况解析,我这个返回的就是 ip:port 形式

最后在 settings设置DOWNLOADER_MIDDLEWARES

DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.retry.RetryMiddleware': 90,
    'douban.middlewares.RandomProxy': 100,
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110,

}

这个数值和顺序很重要,最后附上截图,已经爬了26个小时

41a3868e736f686cd9d1c876180fd123.png
scrapyd jobs

数据量:

cf94972e47798233e9f459dee05bdbd1.png
总条数

参考资料:

aivarsk/scrapy-proxies​github.com
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值