ProxyPool 代理校验器扩展指南:读懂内置三类校验,十分钟写出自己的代理验证器
2026/9/20 23:31:19 网站建设 项目流程

ProxyPool 代理校验器扩展指南:读懂内置三类校验,十分钟写出自己的代理验证器

【免费下载链接】proxy_poolPython ProxyPool for web spider项目地址: https://gitcode.com/gh_mirrors/pr/proxy_pool

ProxyPool 项目(Python ProxyPool for web spider)使用helper/validator.py集中管理代理校验逻辑,通过装饰器将校验方法分为预校验、HTTP 可用性校验与 HTTPS 支持校验三类。本文以 validator.md 为主干,结合 helper/validator.py、helper/check.py、helper/fetch.py 等源码与 tests/unit/test_validator.py 测试用例,完整讲解内置校验的注册机制、执行顺序与判定规则,并给出可直接落地的自定义校验器写法。读完本文,你将掌握"校验器如何被调度、如何被判定、如何自定义"的完整链路,能够针对自己的业务场景(如校验匿名度、验证指定站点可达性、识别透明代理等)快速扩展 ProxyPool 的代理校验能力。

一、校验器整体设计:装饰器注册,集中管理

代理校验方法全部定义在helper/validator.py中,核心是ProxyValidator类(继承自withMetaclass(Singleton),即单例模式),它维护三个类级列表并对外暴露三个装饰器:

校验类型装饰器存储列表说明
preValidator@ProxyValidator.addPreValidatorpre_validator预校验,在代理抓取后、可用性校验前调用
httpValidator@ProxyValidator.addHttpValidatorhttp_validator代理可用性校验,通过则认为代理可用
httpsValidator@ProxyValidator.addHttpsValidatorhttps_validator校验代理是否支持 HTTPS

从 helper/validator.py 的源码可以看到,装饰器本身只是简单的注册动作:

class ProxyValidator(withMetaclass(Singleton)): pre_validator = [] http_validator = [] https_validator = [] @classmethod def addPreValidator(cls, func): cls.pre_validator.append(func) return func @classmethod def addHttpValidator(cls, func): cls.http_validator.append(func) return func @classmethod def addHttpsValidator(cls, func): cls.https_validator.append(func) return func

三个装饰器做的事情完全对称:把被装饰的函数追加到对应列表,并原样返回该函数。因此:

  • 每种校验可以定义任意多个方法;
  • 只有所有方法都返回True,该校验类型才算通过("与"逻辑,任一返回False即失败);
  • 由于是类属性列表,所有装饰在模块加载期执行,且单例保证全项目共享同一份注册表。

1.1 内置校验实现一览

helper/validator.py 内置了四个校验器,覆盖"格式 → 可用性 → HTTPS 支持"三阶段:

@ProxyValidator.addPreValidator def formatValidator(proxy): """检查代理格式""" return True if IP_REGEX.fullmatch(proxy) else False @ProxyValidator.addHttpValidator def httpTimeOutValidator(proxy): """ http检测超时 """ proxies = {"http": "http://{proxy}".format(proxy=proxy), "https": "https://{proxy}".format(proxy=proxy)} try: r = head(conf.httpUrl, headers=HEADER, proxies=proxies, timeout=conf.verifyTimeout) return True if r.status_code == 200 else False except Exception as e: return False @ProxyValidator.addHttpsValidator def httpsTimeOutValidator(proxy): """https检测超时""" proxies = {"http": "http://{proxy}".format(proxy=proxy), "https": "https://{proxy}".format(proxy=proxy)} try: r = head(conf.httpsUrl, headers=HEADER, proxies=proxies, timeout=conf.verifyTimeout, verify=False) return True if r.status_code == 200 else False except Exception as e: return False @ProxyValidator.addHttpValidator def customValidatorExample(proxy): """自定义validator函数,校验代理是否可用, 返回True/False""" return True
  • formatValidator使用正则IP_REGEX = re.compile(r"(.*:.*@)?\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}")fullmatch全匹配,(.*:.*@)?前缀意味着它支持username:password@ip:port这类带认证信息的代理格式(见 helper/validator.py 与文件头部的变更记录)。注意正则并不校验 IP/端口数值范围的合法性,999.1.1.1:80也会匹配通过,这一点在 tests/unit/test_validator.py 的参数化用例中有明确体现。
  • httpTimeOutValidator/httpsTimeOutValidator使用requests.head()发探测请求,超时时间与探测 URL 都来自配置(详见下文"与配置项的联动"),任何异常(超时、连接失败、SSL 错误)一律返回False
  • customValidatorExample是一个恒返回True的占位示例,是官方留作扩展参考的模板(对应 tests/unit/test_validator.py 中的test_always_returns_true用例),实际生产使用时应替换为真实校验逻辑。

1.2 与配置项的联动

两个 HTTP 探测校验器直接读取ConfigHandler(见 handler/configHandler.py),对应 setting.py 中的配置:

配置项环境变量默认值作用
HTTP_URLHTTP_URLhttp://httpbin.orgHTTP 可用性校验的探测目标网站
HTTPS_URLHTTPS_URLhttps://www.qq.comHTTPS 支持校验的探测目标网站
VERIFY_TIMEOUTVERIFY_TIMEOUT10(秒)探测请求的超时时间,同时被httpTimeOutValidatorhttpsTimeOutValidator使用

配置读取支持环境变量覆盖,优先级为os.environ>setting.py默认值。另外 setting.py 中的MAX_FAIL_COUNT(默认0)与POOL_SIZE_MIN(默认20)虽不直接出现在校验函数中,但会在下文"校验结果如何流入代理池"部分与校验结果协同工作。

二、校验执行顺序与完整调用链

2.1 执行顺序图

校验按"预校验 → HTTP 可用性 → HTTPS 支持"三级串行执行:

  • preValidator校验通过的代理才会进入可用性校验;
  • httpValidator校验通过后认为代理可用,更新入代理池;
  • httpsValidator校验通过后视为代理支持 HTTPS,更新代理的https属性为True

2.2 源码级调用链

校验的实际执行并不在validator.py内部,而是由 helper/check.py 中的DoValidator类驱动。它定义了三个与注册列表一一对应的遍历方法:

@classmethod def httpValidator(cls, proxy): for func in ProxyValidator.http_validator: if not func(proxy.proxy): return False return True @classmethod def httpsValidator(cls, proxy): for func in ProxyValidator.https_validator: if not func(proxy.proxy): return False return True @classmethod def preValidator(cls, proxy): for func in ProxyValidator.pre_validator: if not func(proxy): return False return True

注意一个细节:preValidator传入的是整个proxy对象(func(proxy)),而httpValidator/httpsValidator传入的是proxy.proxy字符串(func(proxy.proxy))。也就是说,自定义预校验函数接收Proxy对象,可以访问sourceregion等元数据;而可用性/HTTPS 校验函数接收"ip:port"形式的字符串,便于直接拼接到proxies参数中。

DoValidator.validator()是统一入口,串起三个阶段的判定并更新代理状态(helper/check.py):

@classmethod def validator(cls, proxy, work_type): http_r = cls.httpValidator(proxy) https_r = False if not http_r else cls.httpsValidator(proxy) proxy.check_count += 1 proxy.last_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") proxy.last_status = True if http_r else False if http_r: if proxy.fail_count > 0: proxy.fail_count -= 1 proxy.https = True if https_r else False if work_type == "raw": proxy.region = cls.regionGetter(proxy) if cls.conf.proxyRegion else "" else: proxy.fail_count += 1 return proxy

这里有三点值得注意:

  1. 短路语义https_r = False if not http_r else cls.httpsValidator(proxy),即 HTTP 校验不通过时根本不会执行HTTPS 校验;
  2. 状态维护https属性只有在 HTTP 通过时才更新(True/False),HTTP 失败时保持原值;fail_count在失败时 +1、成功时 -1(不低于 0);check_countlast_timelast_status每次校验都会刷新;
  3. 地域属性work_type == "raw"(原始代理阶段)且开启PROXY_REGION时,会调用regionGetter通过https://api.ip.sb/geoip/{ip}查询代理的国家代码,结果写入region字段。

Proxy对象的字段定义见 helper/proxy.py,其中https属性(self._https,默认False)就是 HTTPS 校验结果的落点,最终会通过to_dict/to_json序列化并存入代理池。

2.3 两个触发场景:raw 与 use

DoValidator.validatorwork_type参数区分两个执行场景(见 helper/check.py):

  • raw(原始校验):代理刚从抓取器产出时执行。入口在 helper/fetch.py,Fetcher.run()对每个抓取结果先执行DoValidator.preValidator(_.proxy),格式合法的代理才 yield 给Checker("raw", proxy_queue)_ThreadChecker.__ifRaw中,校验通过的代理若不存在则put入池,失败则丢弃;
  • use(使用中校验):对池内既有代理的周期性复核。__ifUse中,校验失败且fail_count > conf.maxFailCount时删除,否则保留并重新入池——这正对应 setting.py 的MAX_FAIL_COUNT(默认0,即一次失败即剔除)。

调度节奏由 helper/scheduler.py 控制:proxy_fetch(采集+原始校验)每 5 分钟执行一次,proxy_check(池内复核)每 2 分钟执行一次,且当池内代理数低于POOL_SIZE_MIN时会先触发抓取。校验本身采用 20 个线程并行消费队列(Checkerrange(20)),高吞吐地处理代理队列。

三、扩展校验:从模板到实战

原文档明确指出:helper/validator.py 中已内置自定义校验的示例,扩展方式为——自定义函数返回TrueFalse,用ProxyValidator的装饰器区分校验类型,然后把函数定义在helper/validator.py中(或任何会被导入的位置)即可自动注册,无需修改调度器或检查器代码。

3.1 示例 1:自定义代理可用性校验

@ProxyValidator.addHttpValidator def customValidatorExample01(proxy): """自定义代理可用性校验函数""" proxies = {"http": "http://{proxy}".format(proxy=proxy)} try: r = requests.get("http://www.baidu.com/", headers=HEADER, proxies=proxies, timeout=5) return True if r.status_code == 200 and len(r.content) > 200 else False except Exception as e: return False

相比内置的httpTimeOutValidator(仅用head()检查状态码 200),这个自定义版本改用requests.get()并追加了len(r.content) > 200的内容长度条件,能过滤掉"能连接但响应体异常"的代理。HEADER是 helper/validator.py 中定义的全局请求头(含 User-Agent、Accept 等),自定义函数可直接复用。

3.2 示例 2:自定义 HTTPS 校验

@ProxyValidator.addHttpsValidator def customValidatorExample02(proxy): """自定义代理是否支持 HTTPS 校验函数""" proxies = {"https": "https://{proxy}".format(proxy=proxy)} try: r = requests.get("https://www.baidu.com/", headers=HEADER, proxies=proxies, timeout=5, verify=False) return True if r.status_code == 200 and len(r.content) > 200 else False except Exception as e: return False

HTTPS 校验与 HTTP 校验的差别集中在三点:proxies字典用https协议前缀、探测目标是https://地址、verify=False关闭 SSL 证书验证(避免因目标站点证书链问题误判代理不可用)。原文档也特别提醒:运行代理可用性校验时,所有被ProxyValidator.addHttpValidator装饰的函数会依次按定义顺序执行,只有当所有函数都返回True时才判断代理可用;HttpsValidator的运行机制完全相同。

3.3 扩展校验的生效与验证

  • 自动注册,无需配置:装饰器在模块导入时即把函数追加到ProxyValidator的注册列表,运行python proxyPool.py(调度器启动)后即对每轮校验生效;
  • 按定义顺序执行DoValidator直接遍历列表,后定义的函数排在后面,因此先定义、先执行,可通过调整定义顺序控制校验优先级;
  • 单例共享ProxyValidator是单例,Web API、调度器、检查器线程访问的是同一份注册表,不存在多实例不一致问题。

四、校验器正确性如何被保障:测试用例解读

tests/unit/test_validator.py 为内置校验器提供了完整的单元测试,是理解校验语义的最佳辅助材料:

  • IP_REGEX格式匹配TestIPRegex):合法的"1.2.3.4:8080"、带认证的"user:pass@1.2.3.4:8080"均匹配;空串、"abc"、缺端口的"1.2.3.4"":8080"、端口含字母的"1.2.3.4:abc"等多段冒号的"1.2.3.4:8080:extra"均不匹配。测试同时注明"999.1.1.1:80"这类越界 IP 也会匹配——正则只做格式约束,不做数值范围校验;
  • formatValidatorTestFormatValidator):与正则测试结论一致,合法格式返回True,非法格式返回False
  • httpTimeOutValidatorTestHttpTimeOutValidator):通过mockhelper.validator.head,验证status_code=200 → Truestatus_code=502 → False、抛TimeoutError → False三条路径,覆盖了"成功/失败/异常"全部分支;
  • httpsTimeOutValidatorTestHttpsTimeOutValidator):除上述三条分支外,还断言调用时传入了verify=False,印证 HTTPS 校验关闭证书验证的实现细节;
  • customValidatorExampleTestCustomValidatorExample):确认占位示例恒返回True,即不干预默认校验结果。

这些测试可以直接运行验证:

pytest tests/unit/test_validator.py -v

五、实战建议:自定义校验器的设计要点

结合源码调用链,编写高质量自定义校验器时有几个关键取舍:

  1. HEAD还是GET:内置校验用head()轻量快速;需要校验响应体内容(如防空白页、防跳转)时改用get()并检查len(r.content),代价是带宽和延迟更高。若代理数量大,建议保持 HEAD + 状态码的轻量策略。
  2. 控制超时与重试:校验器跑在 20 线程的检查池里,每个校验器的timeout会直接叠加到整体校验耗时上。内置版本统一用配置项VERIFY_TIMEOUT(默认 10 秒),自定义版本应设置合理超时并try/except兜底,任何异常都必须返回False
  3. 注意proxies字典的协议前缀:HTTP 校验传"http://{proxy}",HTTPS 校验传"https://{proxy}";如需两者同时验证,可像内置实现那样同时放入两个键。
  4. 预校验的特殊入参preValidator系列函数接收的是Proxy对象而非字符串(见 helper/check.py),可用于基于来源、地域等元数据做前置过滤,例如"只允许指定来源的代理进入可用性校验"。
  5. 返回值必须严格是布尔语义:装饰器注册不强制校验返回类型,但DoValidatorif not func(...)判定,任何非真值(None0、空串)都会被当作校验失败。

六、小结

ProxyPool 的校验器体系是一个"装饰器注册 + 集中遍历执行"的插件式设计:ProxyValidator用三个装饰器把校验逻辑挂载到三类列表中,DoValidator按"预校验 → HTTP → HTTPS"的顺序全量遍历并执行与逻辑,Checker的 raw/use 双场景把判定结果转化为入池、保留或剔除动作。理解这条链路后,扩展一个自定义校验器只需三步:写一个返回True/False的函数 → 选择合适的装饰器 → 放入 helper/validator.py 中导入生效,无需改动调度、检查或存储的任何代码。相关源码入口:helper/validator.py、helper/check.py、helper/fetch.py、tests/unit/test_validator.py、setting.py、handler/configHandler.py。

【免费下载链接】proxy_poolPython ProxyPool for web spider项目地址: https://gitcode.com/gh_mirrors/pr/proxy_pool

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询