Code前端首页关于Code前端联系我们

Scrapy中间件无法采集HTTPS网站的原因

terry 2年前 (2023-09-24) 阅读数 80 #后端开发

Scrapy是一个基于Python的网页抓取框架,可以帮助开发者快速高效地从网站中提取数据。 Scrapy的一个显着优势是可以通过中间件定制和优化抓取过程。中间件是一个在请求和响应之间执行特定功能的插件,例如更改用户代理、管理 cookie 和处理重定向。 Scrapy中间件还允许用户设置代理IP地址,这对于使用反抓取措施从网站抓取大量数据非常有用。使用代理IP可以隐藏用户的真实身份,避免网站访问被禁止。简而言之,Scrapy 中间件提供了一种灵活且可定制的方式来改进网页抓取过程。如果想使用代理IP,可以编写一个中间件组件,在请求对象中设置代理和认证信息,以便Scrapy使用代理和认证信息访问网页。在项目中创建一个新的 middlewares.py 文件(./projectname/middlewares.py)。以下是对应的代码:

import base64            
import sys
import random

PY3 = sys.version_info[0] >= 3

def base64ify(bytes_or_str):
    """
    将输入的字符串或字节数组使用 base64 进行编码,并返回编码后的结果。
    如果输入为字符串,则先将其转换为字节数组。
    """
    if PY3 and isinstance(bytes_or_str, str):
        input_bytes = bytes_or_str.encode('utf8')
    else:
        input_bytes = bytes_or_str

    output_bytes = base64.urlsafe_b64encode(input_bytes)
    if PY3:
        return output_bytes.decode('ascii')
    else:
        return output_bytes

class ProxyMiddleware(object):
    """
    scrapy 的中间件,用于为每个请求添加代理。
    """
    def process_request(self, request, spider):
        #亿牛云爬虫加强版 代理服务器地址和端口号
        proxy_host = "www.16yun.cn"
        proxy_port = "31111"

        #亿牛云爬虫加强版 代理服务器验证信息
        proxy_username = "16YUN"
        proxy_password = "16IP"

        # 将请求的代理设置为指定的代理服务器
        request.meta['proxy'] = "http://{0}:{1}".format(proxy_host, proxy_port)
        # 为请求添加代理服务器验证头
        request.headers['Proxy-Authorization'] = 'Basic ' +  base64ify(proxy_username + ":" + proxy_password)

        # 每次请求后关闭 TCP 连接,以强制切换 IP
        request.headers['Connection'] = "Close"

上面的代码可以直接部署使用,但是有用户发现,一段时间后,目标出现在https网站上。是什么导致服务器拒绝响应?该问题发生在采集https网站时,标识“Proxy-Authorization”的认证信息会被传递到目标网站服务器。当目标服务器识别到这些信息后,就会添加反爬处理,导致爬虫请求失败。如何解决这个问题呢?从 Scrapy 2.6.2 开始,此问题已得到修复。直接设置用户的认证信息时,无需添加认证标识,请求头中自动设置“Proxy-Authorization”。这样,即使是https请求,也不会向目​​的Web服务器发送认证信息,避免反向爬虫。修改如下:

import base64            
import sys
import random

PY3 = sys.version_info[0] >= 3

def base64ify(bytes_or_str):
    """
    将输入的字符串或字节数组使用 base64 进行编码,并返回编码后的结果。
    如果输入为字符串,则先将其转换为字节数组。
    """
    if PY3 and isinstance(bytes_or_str, str):
        input_bytes = bytes_or_str.encode('utf8')
    else:
        input_bytes = bytes_or_str

    output_bytes = base64.urlsafe_b64encode(input_bytes)
    if PY3:
        return output_bytes.decode('ascii')
    else:
        return output_bytes

class ProxyMiddleware(object):
    """
    scrapy 的中间件,用于为每个请求添加代理。
    """
    def process_request(self, request, spider):
        # 亿牛云爬虫加强版 代理服务器地址和端口号
        proxy_host = "www.16yun.cn"
        proxy_port = "31111"

        #亿牛云爬虫加强版 代理服务器验证信息
        proxy_username = "16YUN"
        proxy_password = "16IP"

        # [版本>=2.6.2]直接设置用户认证信息,无需添加验证头,会自动在请求头中设置Proxy-Authorization     
        request.meta['proxy'] = "http://{0}:{1}@{2}:{3}".format(proxyUser,proxyPass,proxyHost,proxyPort)

        # 每次请求后关闭 TCP 连接,以强制切换 IP
        request.headers['Connection'] = "Close"

通过上述修改,可以避免在长期采集过程中被目标网站拒绝服务。您可以使用爬虫访问https://httpbin.org/headers来测试分析用户认证信息是否得到处理。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门