本文针对动态代理池myProxyPool(GitHub)源码进行系统分析与代码解读,提供完整源码共大家一同交流学习,也欢迎对该项目多多指正,提出宝贵的意见~
本文涉及环境/模块/服务:
- Python3,MacOS(本机),Linux OS(阿里云服务器/Ubuntu),Redis数据库(代理队列),Flask(API接口)
文章目录
文章目录
0 效果呈现
- 远程连接阿里云服务器,运行myProxyPool目录下的
run.py
文件,如图:



1 前提
1.1 项目结构
- 通过
tree -CF
命令查看目录文件结构

- 由图可见,除了
__pycache__
目录(内含缓存文件),项目的主要文件放在proxypool
目录中,共包含六个模块,分别为:- api.py
- db.py
- err_raise.py
- getter.py
- scheduler.py
- settings.py
1.2 Redis服务
1.2.1 启动Redis服务
# Step 1: 安装Redis服务
sudo apt-get install redis-server
# Step 2: 配置文件redis.conf
sudo vim /etc/redis/redis.conf
# Step 3: 读取配置文件,启动Redis服务
redis-server /etc/redis/redis.conf
# Step 4: 查看Redis服务进程
ps aux | grep "redis"
1.2.2 配置文件
- 设置为守护进程:后台运行Redis服务
################################ GENERAL #####################################
# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize yes
- 不绑定IP地址:任何IP均可访问
# By default Redis listens for connections from all the network interfaces
# available on the server. It is possible to listen to just one or multiple
# interfaces using the "bind" configuration directive, followed by one or
# more IP addresses.
#
# Examples:
#
# bind 127.0.0.1
2 系统要求与模块间关系
2.1 动态代理池需具有的功能
- 目前网上获取代理的方式主要分为两种——付费/免费:
- 付费途径可以通过各家网站的api接口,获取质量较高的可用ip。但是获得ip的数量和速度与付费金额紧紧挂钩。
- 免费途径通过网上的免费ip网站获取代理地址。但是直接从免费网站获取的ip地址往往十有八九无法使用或者已经过期,难以直接使用。
- 本文动态代理池通过对各大免费ip网站进行代理抓取,存入Redis数据库,同时通过调度器
Scheduler
以多进程的方式,实时监控代理池中ip的数量和质量,从而保证代理池内的ip 维持一定的数量并且可用 。通过Flask
构建API接口,使得有效的ip随取随用,并能够实时监控代理池内ip的数量。
2.2 模块间的关系
前文所述六个模块中,
settings.py
和err_raise.py
主要负责各服务的连接设置和异常定义,并不属于功能模块,故不在下述讨论之列。如需查看完整代码,可访问GitHub源码一起交流学习。剩下的四个模块(scheduler.py/db.py/getter.py/api.py
)关系如下,结合Redis服务
和Flask服务
,就构成了能够动态更新的ip代理池,结构图如下:

2.3 四大主要模块的功能分析
a. Redis队列的"机械手臂" – db.py

- db.py模块处在整个系统的中心位置,与其它的任意模块都有着紧密的联系。该模块仅定义了一个
RedisClient()
类,该类定义了对Redis队列进行操作的几个通用方法(put()/get_for_test()/pop_for_use()等),并在其它模块当中实例化为conn
对象,用于充当数据库"机械手"的角色。
b. 用户获取有效ip的"窗口" – api.py
- api.py模块身处db.py和Flask接口之间,发挥通过python语言调用Flask服务的作用。而可用的ip代理就通过Flask服务对应的网址页面呈现出来,方便用户读取和使用。该模块比较简单,任务也比较明确直接,且没有重新定义新的class,因此代码部分在将在后文详述。
c. 批量获取待测ip的"挖掘机" – getter.py

- 上图为getter.py模块中定义的两个class的类关系图。事实上,
ProxyMetaclass
作为FreeProxyGetter
的元类,仅仅是为了能够动态地生成两个和爬取免费ip的方法有关(后文会有详细代码分析)的两个属性。简单地看,此模块中也仅有FreeProxyGetter
一个功能类。 FreeProxyGetter
类主要定义了一组以crawl_
打头的爬取方法,并通过调用主方法get_raw_proxies()
遍历上述爬取方法,批量爬取一系列raw_proxies
,即所谓的未经有效性检测的ip代理。这些待测ip若通过下文所说的Scheduler.ValidityTester
的检测,就会经由RedisClient().put()
方法一次放入Redis队列当中。
d. 动态平衡的"维护者" – scheduler.py

ValidityTester
– ip有效性测试器类,实例化为**tester
对象**。PoolAdder
– ip池数量维护器类,实例化为**adder
对象**Scheduler
– 调度器类,拥有两个静态方法(主体分别为tester
和adder
),和一个run()
方法开启两个并行进程,进行有效性和数量的动态维护。
3 代码解析
3.1 Redis队列的"机械手臂" – db.py
import redis
from proxypool.err_raise import PoolEmptyError
from proxypool.settings import REDIS__LIST_NAME, REDIS_HOST, REDIS_PASSWORD, REDIS_PORT
class RedisClient(object):
"""
Redis连接类,用于连接Redis数据库并操纵其中的代理数据列表
"""
def __init__(self, host=REDIS_HOST, port=REDIS_PORT):
"""
连接Redis数据库
:param host: 数据库ip地址
:param port: 数据库端口
"""
if REDIS_PASSWORD:
self._db = redis.Redis(host=host, port=port, password=REDIS_PASSWORD)
else:
self._db = redis.Redis(host=host, port=port)
@property
def list_len(self):
"""
获取队列长度
:return: 返回队列长度
"""
return self._db.llen(REDIS__LIST_NAME)
def flush(self):
"""
清空队列
"""
self._db.flushall()