网站会把它从总池子取到 A 频道的 ip 池,有个别

2020-04-25 15:06 来源:未知

前言

地址:https://github.com/Python3WebSpider/ProxyPool

众所周知代理 ip 因为配置简单而且廉价,经常用来作为反反爬虫的手段,但是稳定性一直是其诟病。筛选出优质的代理 ip 并不简单,即使付费购买的代理 ip 源,卖家也不敢保证 100% 可用;另外代理 ip 的生命周期也无法预知,可能上一秒能用,下一秒就扑街了。基于这些原因,会给使用代理 ip 的爬虫程序带来很多不稳定的因素。要排除代理 ip 的影响,通常的做法是建一个代理 ip 池,每次请求前来池子取一个 ip,用完之后归还,保证池子里的 ip 都是可用的。本文接下来就探讨一下,如何使用 Redis 构建代理 ip 池,实现自动更新,自动择优。

为什么需要代理池

在爬取网站信息的过程中,有些网站为了防止爬虫,可能会限制每个ip的访问速度或访问次数。对于限制访问速度的情况,我们可以通过time.sleep进行短暂休眠后再次爬取。对于限制ip访问次数的时候我们需要通过代理ip轮换去访问目标网址。所以建立并维护好一个有效的代理ip池也是爬虫的一个准备工作。

整体流程

如何构建一个代理池

图片 1

由上图所示,左侧是形成了整个流程的闭环,从爬虫程序以独占的方式拿到一个代理 ip 到爬取完成归还 ip。这个流程其实是不太严谨的,如果爬虫程序异常中断,就会导致 ip 无法归还,就会导致这个 ip 无法循环利用。但是由于代理 ip 本身的特点,量多而且循环利用的价值并不大,所以这种情况就let it go。

安装

上面也提到 ip 是以独占的方式获取,如果是去爬两个毫不相关的网站,本来一个 ip 就可以,可现在需要两个。为了资源最大化使用,这里引入了频道 ip 池和总代理 ip 池。两个网站就当做两个频道,各自独占,互不相关;总池子就是保存所有的 ip,每个频道都共享。假设只有一个 ip:1.1.1.1 在总池子,爬 A 网站会把它从总池子取到 A 频道的 ip 池,然后 A 爬虫程序从 A 频道 ip 池取出 1.1.1.1 进行使用,这时 1.1.1.1 依然在总池子里,但 A 频道的 ip 池已经不包含 1.1.1.1 了;爬 B 网站也是一样的流程拿到 1.1.1.1,只是从 B 自己的频道池获取。下面就详细说说总池子和频道池子。

安装Python

至少Python3.5以上

总代理 ip 池

安装Redis

安装好之后将Redis服务开启

总池子的作用就是共享所有可用的 ip,但是仅作为存储 ip 的池子并不能实现自动择优啊,这里的择优通常是希望延迟低速度快的 ip 更容易被筛选出,所以我们希望池子中的 ip 是根据它们的延时升序排列,借助 Redis 的 Sorted Sets数据结构即可实现,用延时表示 score,ip 表示 member。

配置代理池

cd proxypool
进入proxypool目录,修改settings.py文件

PASSWORD为Redis密码,如果为空,则设置为None

使用 ZADD添加新 ip 或更新 ip 的延迟:

安装依赖

pip3 install -r requirements.txt

 ZADD proxy_global_ips 200 1.1.1.1:8080 100 2.2.2.2:80 300 3.3.3.3:8888(integer) 3
打开代理池和API

python3 run.py

使用 ZRANGE获取 ip,可以指定获取的个数,比如取两个:

获取代理

利用requests获取方法如下

图片 2

 ZRANGE proxy_global_ips 0 1 WITHSCORES1) "2.2.2.2:80" 2) "100" 3) "1.1.1.1:8080" 4) "200" 
各模块功能
  • getter.py

爬虫模块

  • class proxypool.getter.FreeProxyGetter

爬虫类,用于抓取代理源网站的代理,用户可复写和补充抓取规则。

  • schedule.py
    调度器模块

  • class proxypool.schedule.ValidityTester

异步检测类,可以对给定的代理的可用性进行异步检测。

  • class proxypool.schedule.PoolAdder

代理添加器,用来触发爬虫模块,对代理池内的代理进行补充,代理池代理数达到阈值时停止工作。

  • class proxypool.schedule.Schedule

代理池启动类,运行RUN函数时,会创建两个进程,负责对代理池内容的增加和更新。

  • db.py

Redis数据库连接模块

  • class proxypool.db.RedisClient

数据库操作类,维持与Redis的连接和对数据库的增删查该

  • error.py

异常模块

  • class proxypool.error.ResourceDepletionError

资源枯竭异常,如果从所有抓取网站都抓不到可用的代理资源,
则抛出此异常。

  • class proxypool.error.PoolEmptyError

  • 代理池空异常,如果代理池长时间为空,则抛出此异常。

  • api.py

API模块,启动一个Web服务器,使用Flask实现,对外提供代理的获取功能。

  • utils.py

工具箱

  • setting.py

设置

频道 ip 池

项目参考

Python爬虫代理池

图片 3

频道 ip 池的作用是为了最大化使用总池子中的 ip,并且隔离其他频道的 ip 池。由于一个 ip 使用次数过多是有很大的概率被目标网站屏蔽掉,所以这里也需要进行择优,应该优先筛选出使用次数少的 ip,同理也是使用 Sorted Sets,使用次数表示 score,ip 表示 member,这里与总池子明显的不同之处是 key 不是固定的,需要把频道名称组合进去,这样保证频道之间的隔离,如频道 abc 的 key:proxy_channel_abc_ips

由于频道池子中的 ip 是要以独占的方式取出,我们需要一个 ZPOP的方法,奈何 Redis 本身没有,还好可以通过 Lua 模拟,在一个原子操作下取出 ip,然后删除:

 eval "local el = redis.call('zrange', KEYS[1], 0, 0, 'WITHSCORES'); redis.call('zrem', KEYS[1], el[1]); return el;" 1 proxy_channel_abc_ips
TAG标签:
版权声明:本文由www.129028.com-澳门金沙唯一官网www129028com发布于编程新闻,转载请注明出处:网站会把它从总池子取到 A 频道的 ip 池,有个别