架构学习(五):scrapy实现自定义代理中间件

scrapy实现自定义代理中间件

前言

ip检测是比较常规的反爬手段,一般站点会限制ip的访问频率,或者根据ip的访问规律和频率来识别异常访问,从而点对点封ip。相信大家对代理ip并不陌生,这是ip反爬的绕过方式,且进一步衍生出代理池。

按笔者过往经验来看:

  1. 站点限制ip但不会绑定其他信息,这种情况下我们只要每次请求都切换ip即可(短效ip)
  2. 站点限制ip且绑定cookie等信息,可以每次切换ip时生成一次cookie;或者一个ip直接采集完(长效ip)

各站点的风控机制不同,大家以后遇到的话需要研究它的风控机制并设计突破方案,这个过程需要不断试错,控制变量并找出规律,而这种攻坚过程对逆向思维的训练是很有帮助的。

关卡:实现自定义代理中间件

代理中间件源码解析

进入scrapy->downloadermiddlewares->httpproxy.pyHttpProxyMiddleware便是原生的代理中间件,主要功能逻辑是process_request方法,我们研究它干了什么

从源码中我们可以知道配置代理的方式

  1. 通过配置request.meta["proxy"]来实现代理切换,它的样式是{protocol}://{username}:{password}@{host}:{port}
  2. 利用requests库的getproxies()函数,它返回当前环境变量中配置的代理设置,也就是self.proxies,在HttpProxyMiddleware初始化时实现

代理池

市面上有很多代理ip厂商,他们的产品有很多种,如隧道代理、短效代理等,有兴趣或者有需求的可以去咨询了解。但是这些代理商是服务众多用户的,他提供的代理池质量不一定能满足我们的需求,最好的选择就是维护一套属于自己的高质量代理池。

有兴趣可以看看这篇博客 高效代理池的维护

自定义代理中间件

笔者这里使用的是自己的代理池,通过接口拿到代理字典,需要使用时随机取值即可

powershell 复制代码
{
    "status":1,
    "data":[
        {
            "host":host,
            "port":port,
            "create_time":create_time,
            "expired_time":expired_time,
            "priority":priority,
            "protocol":protocol,
            "source":"source"
        }
    ]
}

主要功能逻辑

python 复制代码
def process_request(self, request, spider):
    """ 默认代理会一直使用,可以使用下面的参数实现动态使用
    meta auto_change_proxy change_proxy _proxy
    1. auto_change_proxy:程序自动指定代理
    2. change_proxy:更新代理(单次)
    3. _proxy:存储上一次代理
    """
    meta = request.meta
    add_proxy_meta = False

    if spider.proxy:  # 使用代理
        if meta.get('auto_change_proxy', None) or meta.get('change_proxy', None):
            add_proxy_meta = True
        elif not meta.get('proxy'):
            add_proxy_meta = True

    # 白名单处理
    if add_proxy_meta:
        for pattern in spider.custom_settings.get('whitelist_pattern', []) + \
                       meta.get('proxy_whitelist_pattern', []):
            if re.search(pattern, request.url):
                add_proxy_meta = False
                if meta.get('proxy'):
                    request.meta['_proxy'] = meta['proxy']
                    del meta['proxy']
                break

    if add_proxy_meta:
        get_suc, get_proxy = self.get_random_proxy(spider.crawler.settings.attributes['PROXY_POOL_URL'].value)
        if not get_suc:
            spider.print_log(get_proxy, log_type='error')
            # todo: 代理异常处理
        else:
            spider.print_log(f'随机代理: {get_proxy}')
            request.meta['proxy'] = get_proxy

设计逻辑如下:

  1. 脚本全局增加proxy参数,集中控制代理使用与否
  2. request.meta增加auto_change_proxychange_proxy_proxy参数来实现动态切换和固定使用
  3. 增加白名单机制,对指定站点采集不使用代理
  4. 日志记录与异常提醒

结束

这个关卡的设计方案是笔者根据自己业务场景实现的,大家如果有同样的需求,需要结合自己的业务场景来思考、设计与实现。

好了,分享就到这了,有啥错误的地方请指正~

相关推荐
盐焗西兰花9 小时前
鸿蒙学习实战之路-Reader Kit修改翻页方式字体大小及行间距最佳实践
学习·华为·harmonyos
QiZhang | UESTC9 小时前
学习日记day76
学习
久邦科技9 小时前
20个免费电子书下载网站,实现电子书自由(2025持续更新)
学习
Gain_chance9 小时前
34-学习笔记尚硅谷数仓搭建-DWS层最近一日汇总表建表语句汇总
数据仓库·hive·笔记·学习·datagrip
啊森要自信9 小时前
CANN ops-cv:面向计算机视觉的 AI 硬件端高效算子库核心架构与开发逻辑
人工智能·计算机视觉·架构·cann
2的n次方_11 小时前
CANN ascend-transformer-boost 架构解析:融合注意力算子管线、长序列分块策略与图引擎协同机制
深度学习·架构·transformer
Gain_chance11 小时前
36-学习笔记尚硅谷数仓搭建-DWS层数据装载脚本
大数据·数据仓库·笔记·学习
XH华11 小时前
备战蓝桥杯,第九章:结构体和类
学习·蓝桥杯
Gain_chance12 小时前
35-学习笔记尚硅谷数仓搭建-DWS层最近n日汇总表及历史至今汇总表建表语句
数据库·数据仓库·hive·笔记·学习
Fushize12 小时前
多模块架构下的依赖治理:如何避免 Gradle 依赖地狱
android·架构·kotlin