爬虫系列:反爬的几种措施

一些大型的网站(亚马逊、沃尔玛、淘宝、京东等)会对 selenium 控制的浏览器暴露特征进行监控,如果不做任何处理直接进行爬取,就很被限制。

一、隐藏浏览器指纹特征

方法一:加载浏览器内容前,先执行 stealth.min.js,去除部分特征

有高人已经介绍过了:https://mp.weixin.qq.com/s/Bge-_yiatSq4CQq7fRvjdQ

2023-2-10尝试后发现,对于我爬取的网站,此方法已经时效,可能很久没更新。也行其他的网站可用(只做备用,不做首选)

stealth.min.js 文件获取: https://github.com/kingname/stealth.min.js


from selenium import webdriver
driver = webdriver.Chrome()


with open('js/stealth.min.js') as ff:
	print('执行反爬js')
	js = ff.read()
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
	"source": js
})

方法二:undetected_chromedriver

官网:https://github.com/ultrafunkamsterdam/undetected-chromedriver

专门针对浏览器识别做出来的第三方库。

import undetected_chromedriver as uc
driver = uc.Chrome(version_main=91)

这里建议

undetected_chromedriver如果要使用无头模式,设置headless 为 True 即可。

image-20230210142323438

image-20230210142809335

但是有可能遇到 无法自动识别到Chrome浏览器的版本号,self.patcher.version_main返回为None,就会报错image-20230210143552457

所有最好的设定以下参数

  1. browser_executable_path : 浏览器的 启动文件(chrome.exe)路径

  2. driver_executable_path: 对应浏览器的驱动(chromedriver.exe)路径

  3. version_main: 浏览器版本号(整数)

  4. headless: True 或者uc.ChromeOptions()类里面设置 options.add_argument('--headless')

  5. keep_user_data_dir: 除此之外 最好也设置一下 用户的缓存数据目录。有些网站会判断用户是不是有缓存,没缓存大概率就是机器了

# chrome_option.py

import undetected_chromedriver as uc
from fake_useragent import UserAgent


# ChromeOptions类是一个配置 chrome 启动是属性的类。通过这个类,可以为chrome配置参数
class Options:
    # ua = UserAgent()  # 创建User-Agent对象
    # useragent = ua.random

    def conf_options(self):

        # 配置ChromeOptions
        options = uc.ChromeOptions()

        # 页面加载策略 normal (默认); eager; none
        options.set_capability('pageLoadStrategy', 'eager')
        # 不加载图片(如果设置【页面加载策略】异常,可以添加以下参数,提升运行速度)
        options.add_argument('blink-settings=imagesEnabled=false')

        # # 默认启动的driver窗体最大化
        # options.add_argument('start-maximized')
        # 以最高权限运行 (解决DevToolsActivePort文件不存在的报错)
        options.add_argument('--no-sandbox')

        # ERROR:ssl_client_socket 不安全的地址错误,循环报错,导致程序终止。以下参数可忽略掉那些证书错误
        options.add_argument('--ignore-certificate-errors')
        # 彻底禁用gpu加速启动
        options.add_argument('--disable-gpu --disable-software-rasterizer')

        # # 无头模式。
        # options.add_argument('--headless')

        # ----------------- 反爬措施 ----------

        # # 设置User-Agent
        # options.add_argument(f'User-Agent={self.useragent}')

        # 代理ip
        # options.add_argument('--proxy-server=http://ip:port')

        # ----------------- 反爬措施 ----------

        prefs = {}
        # 添加去掉密码弹窗管理(chrome密码登录时弹出的密码提示框,遮挡了要点击的元素,导致元素不可点击)
        prefs.update({"credentials_enable_service": False ,"profile.password_manager_enabled": False})

        # # -------------- 下载相关 -----------
        # # 设置下载目录(当前目录,可设置其他目录)
        # download_path = './'
        # prefs.update({"download.default_directory": download_path})
        # # 开启自动下载
        # prefs.update({"download.prompt_for_download": False})
        # # 取消浏览器下载时保存路径弹框
        # prefs.update({"download.directory_upgrade": True})
        # # -------------- 下载相关 -----------

        # # 是禁止弹出所有窗口(慎用)
        # prefs.update({"profile.default content settings·popups": 0})

        # 去掉"此文件类型可能会损害您的计算机”的提示
        prefs.update({"safebrowsing.enabled": True})
        options.add_experimental_option("prefs", prefs)

        # 设置语言
        options.add_argument('lang=en_US')

        options.add_argument("--disable-popup-blocking")
        options.add_argument('--no-first-run')
        options.add_argument('--no-service-autorun')
        options.add_argument('--no-default-browser-check')
        options.add_argument('--password-store=basic')

        return options
# conftest.py 生成driver对象

import undetected_chromedriver as uc

@pytest.fixture(scope="session")
def driver2():
    global driver
    # 驱动路径
    print(f'chromedriver.exe 完整路径是:{Config.chromedriver_dir}')
    sys.path.append(Config.chromedriver_dir)

    chrome_options = Options().conf_options()
    # 指定chrome.exe:browser_executable_path、driver_executable_path
    driver = uc.Chrome(version_main=91, headless=True, options=chrome_options,browser_executable_path=Config.chrome_exe_dir, driver_executable_path=Config.chromedriver_dir,keep_user_data_dir=Config.keep_user_data_dir)

    yield driver
    print("全部用例执行完后 teardown quit dirver")
    driver.quit()

# project.py   项目路径

import os

class Config:
    # 全局项目根目录
    root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    # logger.info(f'全局项目根目录:{root_dir}')

    excle_dir = os.path.join(root_dir, "./file/excle_data.xlsx")
    chromedriver_dir = os.path.join(root_dir, "./chrome/chromedriver.exe")
    chrome_exe_dir = os.path.join(root_dir, "./chrome/chrome.exe")
    keep_user_data_dir = os.path.join(root_dir, "./chrome/cache")

settings = Config()

二、其他操作

浏览器参数配置

设置随机User-Agent

from fake_useragent import UserAgent

options.add_argument(f'User-Agent={UserAgent().random}')

去掉提示正在执行自动化的警告条

options.add_experimental_option('useAutomationExtension', False)
options.add_experimental_option('excludeSwitches', ['enable-automation'])

随机ip访问

通过启动参数 --proxy-server代理有访问目标

# 代理ip
# options.add_argument('--proxy-server=http://ip:port')

如何获取那么多的可用、稳定ip呢?

查看爬虫系列的另一篇文章:爬虫系列:自建并维护代理ip池