# 爬虫系列:反爬的几种措施 一些大型的网站(亚马逊、沃尔玛、淘宝、京东等)会对 `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](http://biji.51automate.cn/blogs/img/image-20230210142323438.png) ![image-20230210142809335](http://biji.51automate.cn/blogs/img/image-20230210142809335.png) 但是有可能遇到 无法自动识别到Chrome浏览器的版本号,`self.patcher.version_main`返回为`None`,就会报错![image-20230210143552457](http://biji.51automate.cn/blogs/img/image-20230210143552457.png) 所有最好的设定以下参数 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池