Selenium是一个功能强大的自动化测试工具,由于可以用来处理JavaScript渲染、Ajax请求以及复杂的用户交互,所以也被广泛地应用到爬虫和数据抓取中。然而,在使用Selenium进行自动化操作或爬虫时,有时也会遇到被目标网站检测并阻止的情况。接下来,本文将探讨网站是如何检测Selenium的,并提供几种常用的解决思路。
网站检测Selenium的途径
首先,在给出具体的解决办法之前,让我们了解一下常见的检测角度,以及它们的实现原理。
window.navigator.webdriver属性检测
window.navigator.webdriver 属性是由浏览器驱动程序(如 Selenium WebDriver)在浏览器的全局 window 对象的 navigator 子对象中设置的。它有三个值:
-
true表示“当前浏览器正在被自动化工具控制” -
false表示“当前浏览器没有被自动化工具控制” -
undefined表示“没有可用信息表明浏览器是否被自动化工具控制”
当使用 Selenium WebDriver 启动浏览器时,WebDriver 会默认设置这个属性的值为true,以便网站可以通过 JavaScript 检测到自动化会话。
在正常的用户访问信息里,这个属性的值是false或者undefined;但是如果使用Selenium但没有修改window.navigator.webdriver 属性,在当前访问请求里它的值就是true.
一旦检测到这是来自自动化工具的访问请求,网站就可能会执行特定的响应措施,比如显示验证码、限制页面访问、记录日志或发送警告等。

(上图为BrowserScan的指纹识别和机器人识别监测结果)
Chrome DevTools Protocol (CDP) 检测
Chrome DevTools Protocol (CDP)是Chrome浏览器内置的一套工具,通常被开发人员用来检查和调试自己的网站。在使用Selenium时,利用CDP可以更好地模拟或控制浏览器活动。
针对这一点,网站通常会通过监视比较少用,或者非常规用户生成的命令来监测CDP的使用情况,比如调用普通用户几乎不会用到的特定API端口组合、异常更改文档对象模型(DOM)等等。
如果涉及更复杂的功能,调试端口上的网络活动也是很容易被检测到的,如9222端口(常用于远程调试);以及表单上的批处理操作等非人工交互的模式等等。总的来说,它们主要都是针对非人类的行为活动进行严格的检测和排查,也就是下面要提到的“用户行为分析”。

(上图为BrowserScan的CDP监测结果)
User-Agent 字符串检测
user-agent字符串会告诉网站访问它的设备和浏览器的类型。如果没有仔细修改,不少自动化脚本可能使用默认的或比较少见的用户代理字符串:比如包含“Selenium”字样,或是使用了不常用的浏览器版本......这些信息有可能引起网站的警惕,检测到非人类的网络活动。所以在运行程序之前,最好先更改用户代理字符串以模仿流行的浏览器。
用户行为分析
可以明显看到,自动化脚本与网页的交互方式通常和人类不同,网站检测自动化脚本和爬虫的一大抓手就是分析判断这些行为是否来自人类,例如:
●页面滚动和停留时间:脚本通常会在页面上使用最少的时间,固定地匀速滚动页面,比较机械死板;而普通的人类用户在浏览的时候会根据兴趣的变化在不同的地方停留不同的时间不会用一种固定的模式去翻页。
●鼠标点击:很多自动的鼠标点击程序会以一致的时间间隔运行,并出现在精确的同一屏幕位置,与人类的随机点击行为截然不同
●访问网站的时间:机器人可能在非高峰时间运行,如深夜或清晨;甚至有些脚本因为程序设置不当,24小时都在工作。
●请求间隔:与人类活动的零星模式不同,自动化脚本可能以常规的、可预测的间隔发出请求。特别是当它们使用相同的用户代理字符串高频率地发送请求时,不仅容易被网站检测到,还有可能因为占用过多网站资源而触发网站的DDos(Distributed Denial of Service)防御机制。
浏览器指纹检测
浏览器指纹是网站收集用户浏览器发出的详细信息后创建出的浏览器的唯一配置文件,包括浏览器版本、屏幕分辨率、安装的字体、安装的插件等。由于是独一无二的标识,相当于用户的在线指纹,所以又叫做浏览器指纹。由于自动化脚本通常缺乏个性化的浏览器配置,容易与已知的自动化工具或爬虫的指纹模式相匹配或相似,因此很容易被识别出来。
如果Selenium被检测出来,如何解决?
虽然网站的反爬机制越来越严格,检测自动化脚本的手段也越来越多,但在不违反法律和道德准则的前提下,我们仍有一些应对方法。在此,本文总结了以下几大基础解决思路,可以根据实际情况和需求加以运用。
使用BrowserScan的机器人检测功能
首先,在运行脚本或者更新版本前,不妨先使用专门的工具去排查具体存在的问题。BrowserScan就是一个功能全面的强大工具,它拥有专业的机器人检测功能,主要包含以下四个关键的检测方向,涵盖了网站可以检测到的大多数参数或漏洞。除了本文提到的所有常见漏洞,还有其他几十个相关检测参数,帮助你便捷地排除问题,及时调整:
-
WebDriver:检查你的浏览器是否能被发现由WebDriver控制的迹象
-
user-agent: 检查你的user-agent字符串看起来是否像一个真实的用户,或者它是否泄露了你正在使用脚本。
-
CDP (Chrome DevTools Protocol):BrowserScan可以准确地检测出使用开发者模拟/控制浏览器的情况。
-
Navigator对象:通过检查 Navigator 判断是否存在欺骗行为, 即与典型用户数据不匹配的异常情况

2.修改 WebDriver 属性
正如上文所说,网站判断一个访问是否来自自动化脚本的关键点就是比对其行为与正常人类行为的异同。要想防止网站检测出机器人程序并施以限制,就得让你的程序在运行时尽量模仿人类的行为模式。首先是从代码配置的层面去模拟正常用户的特征:下面列举了可修改的WebDriver属性,帮助你降低被检测到的风险,同时优化脚本的运行效率。
1). 关闭 window.navigator.webdriver 标记
首先,我们可以通过修改刚刚所说的window.navigator.webdriver属性去让浏览器在网站面前隐藏其自动化状态。在启动浏览器时添加 --disable-blink-features=AutomationControlled 标记,就能使 window.navigator.webdriver 属性变为 false
2). 使用无头浏览模式
在无头模式下运行浏览器时,浏览器就会在没有图形用户界面的情况下运行,即在后台工作。在这种模式下相对更难被网站检测出来,因为脚本在没有完整浏览器界面的情况下运行,可以绕过网站用来识别自动化工具的元素。 我们可以通过add_argument方法添加 --headless 参数来进入无头浏览器模式。另外还有一些同样是通过add_argument添加的附加参数,可以按需使用:
● --incognito: 这个参数是用来以隐身模式启动浏览器的,可以防止浏览器存储任何 cookie、缓存或浏览历史记录
● --disable-gpu: 虽然 GPU 硬件加速可以改善浏览器中的渲染性能,但在无头模式下不需要用到它,因此关闭 GPU 硬件来释放占用的资源反而能够隐藏浏览器指纹,优化脚本运行的效果。 ● --no-sandbox: 这个参数在容器化或受限环境中运行浏览器时特别有用。它禁用了Chrome浏览器的沙箱模式,能够绕过操作系统的安全模型,隔离浏览器进程,同时减少沙盒抛出错误或导致浏览器崩溃的问题。在 Docker 容器或类似的沙盒环境中运行浏览器时,--no-sandbox 参数可以避免因沙盒限制而导致的权限问题。
3). 设置自定义用户代理字符串
使用自定义用户代理来模仿流行的浏览器版本也是爬虫和自动化脚本设置中的基本一环,它可以使你的 Selenium 驱动的浏览器看起来像普通用户的浏览器。在脚本运行的过程中,也可以通过更改用户代理字符串让你的访问看起来像来自不同的设备。以下是一个包含上述所有设置的代码例子,可供参考。
示例代码:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
#Options类用于设置Chrome浏览器的启动选项。
options = Options()
#创建一个Options对象,并使用它来配置Chrome浏览器的启动参数。
options.add_argument("--disable-blink-features=AutomationControlled")
#这行代码添加了一个启动参数,用于禁用Chrome中的Blink引擎特性--AutomationControlled
options.add_argument("--headless")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--incognito")
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"
options.add_argument(f'user-agent={user_agent}')
#定义了一个用户代理字符串,并将其作为启动参数传递给Chrome
driver = webdriver.Chrome(options=options)
#启动Chrome浏览器,使用前面设置的所有选项。
3. 增加扩展程序
扩展程序可以改变你的浏览器管理任务,如广告拦截等,也有助于模拟典型的用户浏览器配置。
示例代码:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_extension('path/to/extension.crx')
#从指定的路径导入Chrome扩展
driver = webdriver.Chrome(options=options)
4. 使用代理 IP
使用代理可以隐藏你的真实IP 地址,让你的自动化脚本更难以被追踪。如果当前 IP 地址被目标网站封锁,你也可以通过切换到不同的 IP 地址来尝试解决。 接下来的这个示例代码用于启动 Chrome 浏览器,并将所有 HTTP 和 HTTPS 请求通过指定的代理服务器路由。
示例代码:
from selenium import webdriver
from selenium.webdriver.common.proxy import Proxy, ProxyType
proxy_ip = '192.168.1.1:8080' # Replace with a valid proxy IP
proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = proxy_ip
proxy.ssl_proxy = proxy_ip
#设置代理类型为手动(ProxyType.MANUAL)
#设置HTTP代理和HTTPS代理为上面定义的proxy_ip。
capabilities = webdriver.DesiredCapabilities.CHROME
proxy.add_to_capabilities(capabilities)
#CHROME是一个预定义的字典,包含了启动Chrome浏览器所需的默认能力
driver = webdriver.Chrome(desired_capabilities=capabilities)
5. 模拟正常用户行为
要在自动化脚本中模拟类似人类的行为,常规的做法是模拟鼠标和键盘的自然交互,以及变化这些交互的时间。在接下来的部分中,我们将分开两点来讲解具体的实现步骤:
a. 模拟鼠标和键盘操作
许多开发人员可能使用 ActionChains 进行移动鼠标和输入文本等用户操作。不过,当涉及到需要键盘输入的动作时,ActionChains 类的 send_keys() 方法存在一定的局限。 因为在某些情况下,ActionChains 类的 send_keys() 方法可能无法触发 JavaScript 事件,或者可能用了与实际用户输入不同的方式来触发,这就很容易被识别为自动化脚本的操作。 如果你的目标网站涉及大量 JavaScript 交互,您可以根据特定需求使用 IJavaScriptExecutor 接口来解决此问题。
b. 设置随机延迟
改变脚本在页面上的停留时间或与元素的交互方式也可以帮助规避检测。下面给出的代码是一个简单的随机延迟代码,主要是为了让脚本在执行任务时可以随机停留一段时间,避免过快地发送访问请求或者过于频繁地点击网页。 如果有更复杂的需求,可以为每个动作设置不同的时间间隔,例如:设置在一次访问完成后等待1- 5 秒再进行下一次访问,每次点击操作后 1-3秒等。
示例代码:
# Random delay between 5 and 10 secondsimport time
import random
time.sleep(random.randint(5, 10))
#随机延迟5-10秒
6. 使用Undetectable Chromedriver库
Undetectable Chromedriver是一个封装了 Selenium ChromeDriver 的Python库,专为自动化脚本模拟真实用户的浏览器行为,减少自动化工具被识别的风险。它与 Selenium WebDriver API 兼容,可以无缝集成到现有的 Selenium 脚本中,并且功能比较全面,可以绕过许多常见的自动化检测手段。
示例代码:
import undetected_chromedriver.v2 as uc
driver = uc.Chrome()
driver.get('https://www.example.com')
#应修改为你的目标网址
7. 使用 excludeSwitches 选项
这段代码用到了Selenium WebDriver的add_experimental_option 方法,允许用户通过传递键值对来设置浏览器的实验性选项;其中的"excludeSwitches" 选项用来指定开关列表,这些开关在浏览器启动时不会被应用。"enable-automation"参数就是被传递的排除值, 排除后可以阻止浏览器加载自动化控制功能,看起来更像是普通用户在操作, 由此规避一些基于用户行为分析的简单爬虫检测机制。
示例代码:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_experimental_option("excludeSwitches", ["enable-automation"])
#排除Chrome的"enable-automation"命令行参数。
driver = webdriver.Chrome(options=options)
driver.get('https://www.example.com')
#应修改为你的目标网址
为什么你的 Selenium 很容易被检测到?
请求频率和行为的重复率过高
你的 Selenium 机器人可能被抓住的一个常见原因是过高的请求频率和重复行为。如果您的脚本发送请求太快或持续访问同一页面,它就会引发警觉。还有在网页上的动作与人类浏览网页的方式不符,比如总是点击一个按钮,只抓同一个位置的数据等等。
此外,如果你的脚本全天候抓取数据,即使是在正常人的休息时间还在不停地访问网站,那也很容易会被识别为机器人。为了解决这个问题,可以尝试分散请求来源(也就是使用轮换代理、更改User-Agent等),改变访问的页面或顺序,并设置脚本在正常时间内用恰当的时间间隔去运行。
仅爬取源代码
许多网站使用 JavaScript 动态生成内容。如果你的Selenium爬虫只爬取初始源代码并忽略 JavaScript 渲染的内容,它可能就会错过或与人类用户的行为不同。这就需要根据目标网页去更改你的 Selenium 设置,让它能够像一个使用常规浏览器的用户那样执行并与 JavaScript 交互。
使用单一的浏览器和操作系统配置
使用相同的浏览器设置进行所有爬取任务很容易让你的程序被发现。很多网站都可以检测到浏览器指纹中的模式,这些模式包括您的浏览器版本、操作系统,甚至是屏幕分辨率等细节。为了避免被检测,应该在程序运行前先用相关工具进行浏览器指纹检测、机器人检测等,在修改漏洞后再开始使用自动化脚本。并且在运行程序时可以更换一些用户代理字符串、浏览器配置等信息,模拟不同来源的访问请求。
IP 地址被封锁
如果排除了以上提到的这些原因,那可能是你当前使用的 IP 地址进行了过多的会话或发送了太多请求,导致它被网站检测到并封锁了。这是网站用来限制抓取活动的一种常见手段;关于这个问题的解决办法也是使用轮换IP代理、更改访问请求的身份信息来绕过封禁。