崔庆才python3爬虫-代理的使用


代理的使用

代理的设置

获取代理

1
2
3
4
5
做测试之前,我们需要先获取一个可用代理。搜索引擎搜索“代理”关键字,就可以看到许多代
理服务网站,网站上会有很多免费代理,比如西刺: http://www.xicidaili.eom/o但是这些免费代理大多
数情况下都是不好用的,所以比较靠谱的方法是购买付费代理。付费代理在很多网站上都有售卖,数量不用多,稳定可用即可,我们可以自行选购。
如果本机有相关代理软件的话,软件一般会在本机创建HTTP或 SOCKS代理服务,本机直接使用此代理也可以。
在这里,我的本机安装了一部代理软件,它会在本地9743端口上创建HTTP代理服务,即代理
1
2
3
127.0.0.1:9743,另外还会在9742端口创建SOCKS代理服务,即代理为 127.0.0.1:9742。我只要设置了这个代理,就可以成功将本机IP 切换到代理软件连接的服务器的IP了
本章下面的示例里,我使用上述代理来演示其设置方法,你也可以自行替换成自己的可用代理。
设置代理后测试的网址是: http://httpbin.org/get,我们访问该网址可以得到请求的相关信息,其中 origin字段就是客户端的IP , 我们可以根据它来判断代理是否设置成功,即是否成功伪装了IP

urllib

requests

代理池的维护

1
2
3
在网上有大量公开的免费代理,或者我们也可以购买付费的代理ip, 但是代理不论是免费的还是付费的,都不能保证都是可用的,因为可能此ip被其他人使用来爬取同样的目标站点而被封禁,或者代理服务器突然发生故障或网络繁忙。
一旦我们选用了一个不可用的代理,这势必会影响爬虫的工作效率。
所以,我们需要提前做筛选,将不可用的代理剔除掉,保留可用代理。接下来我们就搭建一个高效易用的代理池

准备工作

1
2
首先需要成功安装Redis数据库并启动服务,另外还需要安装aiohttp、 requests、 redis-py、 pyquery、
Flask库 ,可以参考第1章的安装说明

代理池的目标

存储模块

1
负责存储抓取下来的代理。首先要保证代理不重复,要标识代理的可用情况,还要动态实时处理每个代理,所以一种比较高效和方便的存储方式就是使用R edis的 Sorted Set , 即有序集合

获取模块

1
2
需要定时在各大代理网站抓取代理。代理可以是免费公开代理也可以是付费代
理 ,代理的形式都是IP 加端口,此模块尽量从不同来源获取,尽量抓取高匿代理,抓取成功之后将可用代理保存到数据库中

检测模块

1
需要定时检测数据库中的代理。这里需要设置一个检测链接,最好是爬取哪个网站就检测哪个网站,这样更加有针对性,如果要做一个通用型的代理,那可以设置百度等链接来检测。另外,我们需要标识每一个代理的状态,如设置分数标识, 1 0 0 分代表可用,分数越少代表越不可用。检测一次,如果代理可用,我们可以将分数标识立即设置为100满分,也可以在原基础上加1分 ;如果代理不可用,可以将分数标识减1分,当分数减到一定阈值后,代理就直接从数据库移除。通过这样的标识分数,我们就可以辨别代理的可用情况,选用的时候会更有针对性

接口模块

1
需 要 用 A P I来提供对外服务的接口。其实我们可以直接连接数据库来取对应的数据 ,但是这样就需要知道数据库的连接信息,并且要配置连接,而比较安全和方便的方式就是提供一个Web A P I接口,我们通过访问接口即可拿到可用代理。另外,由于可用代理可能有多个,那么我们可以设置一个随机返回某个可用代理的接口,这样就能保证每个可用代理都可以取到,实现负载均衡

代理池的架构

bDcfAO.png

1
2
3
4
存储模块使用Redis的有序集合,用来做代理的去重和状态标识,同时它也是中心模块和基础模块,将其他模块串联起来。
获取模块定时从代理网站获取代理,将获取的代理传递给存储模块,并保存到数据库。
检测模块定时通过存储模块获取所有代理,并对代理进行检测,根据不同的检测结果对代理设置不同的标识
接口模块通过Web API提供服务接口,接口通过连接数据库并通过Web形式返回可用的代理

代理池的实现

存储模块

1
2
这里我们使用Redis的有序集合,集合的每一个元素都是不重复的,对于代理池来说,集合的元素就变成了一个个代理,也 就 是 IP加端口的形式,如 60.207.237.111:8888,这样的一个代理就是集合的一个元素。 另外,有序集合的每一个元素都有一个分数字段,分数是可以重复的,可以是浮点数类型, 也可以是整数类型。 该集合会根据每一个元素的分数对集合进行排序,数值小的排在前面,数值大的排在后面,这样就可以实现集合元素的排序了。
对于代理池来说,这个分数可以作为判断一个代理是否可用的标志, 100为最高分,代表最可用,0 为最低分,代表最不可用。如果要获取可用代理,可以从代理池中随机获取分数最高的代理,注意是随机, 这样可以保证每个可用代理都会被调用到
1
2
3
分数是我们判断代理稳定性的重要标准, 设置分数规则如下所示。
□ 分 数 100为可用,检测器会定时循环检测每个代理可用情况,一旦检测到有可用的代理就立即置为100 ,检测到不可用就将分数减1 , 分数减至0 后代理移除。
□新获取的代理的分数为1 0 , 如果测试可行,分数立即置为1 0 0 ,不可行则分数减1 , 分数减至0 后代理移除。
1
2
3
4
这只是一种解决方案,当然可能还有更合理的方案。之所以设置此方案有如下几个原因。
□在检测到代理可用时,分 数 立 即 置 为 10 0 ,这样可以保证所有可用代理有更大的机会被获取到。你可能会问,为什么不将分数加1而是直接设为最高100呢?设想一下,有的代理是从各大免费公开代理网站获取的,常常一个代理并没有那么稳定,平 均 5 次请求可能有两次成功 ,3 次失 败 ,如果按照这种方式来设置分数,那么这个代理几乎不可能达到一个高的分数 ,也就是说即便它有时是可用的,但是筛选的分数最高,那这样的代理几乎不可能被取到。如果想追求代理稳定性,可以用上述方法,这种方法可确保分数最高的代理一定是最稳定可用的。所以,这里我们采取“可 用 即 设 置 100” 的方法,确保只要可用的代理都可以被获取到。
□在检测到代理不可用时,分 数 减 1 , 分数减至0 后 ,代理移除。这样一个有效代理如果要被移除需要失败100次 ,也就是说当一个可用代理如果尝试了 100次都失败了,就一直减分直到移除 ,一旦成功就重新置回100。尝试机会越多,则这个代理拯救回来的机会越多,这样就不容易将曾经的一个可用代理丢弃,因为代理不可用的原因很可能是网络繁忙或者其他人用此代理请求太过频繁,所以在这里将分数为100。
口新获取的代理的分数设置为10 , 代理如果不可用,分数就减1 ,分数减到0, 代理就移除,如果代理可用,分 数 就 置 为 100。由于很多代理是从免费网站获取的,所以新获取的代理无效的比例非常高,可能不足10%。所以在这里我们将分数设置为10, 检测的机会没有可用代理的 100次那么多,这也可以适当减少开销。

获取模块

检测模块

接口模块

1
2
3
4
5
6
7
8
9
10
11
12
13
我们怎样方便地获取可用代理呢?可以用 Redis Client类直接连接Redis,然后调用random()
方法。这样做没问题,效率很高,但是会有几个弊端:
如果其他人使用这个代理池,他需要知道Redis连接的用户名和密码信息,这样很不安全。
□ 如果代理池需要部署在远程服务器上运行,而远程服务器的Redis只允许本地连接,那么我
们就不能远程直连Redis来获取代理。
□如果爬虫所在的主机没有连接Redis模块,或者爬虫不是由Python语言编写的,那么我们就
无法使用Redis Client来获取代理。
□ 如果Redis Client类或者数据库结构有更新,那么爬虫端必须同步这些更新,这样非常麻烦。

综上考虑,为了使代理池可以作为一个独立服务运行,我们最好增加一个接口模块,并以Web API
的形式暴露可用代理。
这样一来,获取代理只需要请求接口即可,以上的几个缺点弊端也可以避免。
我们使用一个比较轻量级的库Flask来实现这个接口模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from flask import Flask, g
from db import RedisClient
_ all_ = [ 'app']
app = Flask(_ name_ )
def get_conn():
if not hasattr(g, 'redis'):
g.redis = RedisClient()
return g.redis
@app.route('/')
def index():
return '<h2>Welcome to Proxy Pool System</h2>'
@app.route('/random')
def get_proxy():
获取随机可用代理
:return:随机代理
conn = get_conn()
return conn.random()
@app.route('/count')
def get_counts():
获取代理池总量
:return:代理池总量
conn = get_conn()
return str(conn.count())
if _ name_ == '_ main_ ':
app.run()
1
2
在这里,我们声明了一个Flask对象,定义了3个接口,分别是首页、随机代理页、获取数量页。
运行之后, Flask会启动一个Web服务,我们只需要访问对应的接口即可获取到可用代理

调度模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
TESTER_CYCLE = 20
GETTER5YCLE = 20
TESTERJNABLED = True
GETTERJNABLED = True
API_ENABLED = True
from multiprocessing import Process
from api import app
from getter import Getter
from tester import Tester
class Scheduler():
def schedule_tester(self, cycle=TESTER_CYCLE):
定时测试代理
tester = Tester()
while True:
print ('测 试 器 开 始 运 行 ')
tester.run()
time.sleep(cycle)
def schedule_getter(self, cycle=GETTER_CYCLE):
定时获取代理
getter = Getter()
while True:
print('开 始 抓 取 代 理 ')
getter.run()
time.sleep(cycle)
def schedule_api(self):
开 启 API
app.run(API_HOST, API_PORT)
def run(self):
print ('代 理 池 开 始 运 行 ')
if TESTER_ENABLED:
tester_process = Process(target=self.schedule_teste:r)
tester_process.start()
if GETTER_ENABLED:
getter_process = Process(target=self.schedule_gette:r)
getter_process.start()
if API_ENABLED:
api_process = Process(target=self.schedule_api)
api_process.start()
1
2
3
4
5
6
7
8
9
10
3 个 常 量 TESTER_ENABLED、 GETTER_ENABLED、 API_ENABLED都是布尔类型,表示测试模块、获取模
块 、接口模块的开关,如果都为T r u e ,则代表模块开启。

启动入 口 是run()方法,这个方法分别判断3 个模块的开关。如果开关开启,启动时程序就新建
-个Process进程,设置好启动目标,然后 调 用s ta r t()方法运行,这 样 3 个进程就可以并行执行,互
不干扰。
3 个调度方法结构也非常清晰。比如, schedule_tester()方法用来调度测试模块,首先声明一个
T ester对象,然后进入死循环不断循环调用其run()方 法 ,执行完一轮之后就休眠一段时间,休眠结
束之后重新再执行。在这里,休眠时间也定义为一个常量,如 20秒 ,即每隔20秒进行一次代理检测。
最后,只需要调用Scheduler的 run()方法即可启动整个代理池

本文标题:崔庆才python3爬虫-代理的使用

文章作者:TTYONG

发布时间:2020年06月07日 - 20:06

最后更新:2022年03月22日 - 09:03

原始链接:http://tianyong.fun/%E5%B4%94%E5%BA%86%E6%89%8Dpython3%E7%88%AC%E8%99%AB-9%E7%AB%A0%20%E4%BB%A3%E7%90%86%E7%9A%84%E4%BD%BF%E7%94%A8.html

许可协议: 转载请保留原文链接及作者。

多少都是爱
0%