Selenium被网站检测怎么办:undetected-chromedriver反检测实战指南
·
前言
Selenium是Python自动化测试和爬虫中最常用的工具之一,但它有一个致命的问题:网站一眼就能看出你在用Selenium。
打开Chrome DevTools控制台输入navigator.webdriver,如果返回true,恭喜你已经暴露了。Cloudflare、Akamai、Imperva等反爬系统检测到这个标志后,会直接给你一个验证码页面或者403。
本文将深入分析Selenium被检测的原因,然后给出实际可用的反检测方案。
Selenium为什么会被检测
1. navigator.webdriver标志
这是最基本的检测点。ChromeDriver启动时会自动设置这个标志:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://bot.sannysoft.com')
# 在控制台中
# navigator.webdriver = true ← 暴露!
2. Chrome DevTools Protocol痕迹
ChromeDriver通过CDP协议控制浏览器,会留下多个痕迹:
// 这些属性在自动化浏览器中存在,正常浏览器中不存在
window.cdc_adoQpoasnfa76pfcZLmcfl_Array
window.cdc_adoQpoasnfa76pfcZLmcfl_Promise
window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol
// chrome对象中的异常
window.chrome.runtime // 正常浏览器中有完整的runtime API
3. 缺少用户态特征
自动化浏览器缺少正常用户的特征:
# 正常浏览器有的,Selenium默认没有的
missing_features = {
'plugins': '浏览器插件列表为空',
'languages': '语言列表异常',
'permissions': '权限API行为异常',
'webgl': 'WebGL渲染结果可能不同',
'chrome_app': 'chrome.app 对象缺失',
}
```
## 方案一:undetected-chromedriver(推荐入门)
undetected-chromedriver(简称UC)是最流行的Selenium反检测库,通过修改ChromeDriver二进制文件来移除自动化痕迹。
### 安装
```bash
pip install undetected-chromedriver
基本使用
import undetected_chromedriver as uc
# 创建反检测浏览器实例
driver = uc.Chrome()
# 访问受保护的网站
driver.get('https://nowsecure.nl')
# 检查 - navigator.webdriver 现在返回 undefined
result = driver.execute_script('return navigator.webdriver')
print(f'webdriver标志: {result}') # None (undefined)
# 正常操作
driver.get('https://target-site.com')
content = driver.page_source
print(f'页面长度: {len(content)}')
driver.quit()
配置选项
import undetected_chromedriver as uc
options = uc.ChromeOptions()
# 设置用户数据目录(保持登录状态)
options.add_argument('--user-data-dir=/tmp/chrome-profile')
# 设置窗口大小
options.add_argument('--window-size=1920,1080')
# 设置语言
options.add_argument('--lang=zh-CN')
# 禁用GPU加速(服务器环境)
options.add_argument('--disable-gpu')
# 指定Chrome版本(可选)
driver = uc.Chrome(
options=options,
version_main=124, # 指定大版本号
)
driver.get('https://bot.sannysoft.com')
import time
time.sleep(10) # 查看检测结果
driver.quit()
使用代理
import undetected_chromedriver as uc
options = uc.ChromeOptions()
# HTTP代理
options.add_argument('--proxy-server=http://user:pass@proxy:8080')
# 或者SOCKS5代理
options.add_argument('--proxy-server=socks5://proxy:1080')
driver = uc.Chrome(options=options)
driver.get('https://httpbin.org/ip')
print(driver.page_source)
driver.quit()
方案二:Patchright(Playwright的反检测版)
如果你更喜欢Playwright的API风格,Patchright是一个很好的选择。它是Playwright的补丁版本,移除了自动化检测标志。
安装
pip install patchright
patchright install chromium
基本使用
from patchright.sync_api import sync_patchright
with sync_patchright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto('https://bot.sannysoft.com')
# 检查webdriver标志
result = page.evaluate('navigator.webdriver')
print(f'webdriver: {result}') # undefined
page.screenshot(path='sannysoft.png')
browser.close()
```
### 异步使用
```python
from patchright.async_api import async_patchright
import asyncio
async def main():
async with async_patchright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto('https://nowsecure.nl')
content = await page.content()
print(f'页面长度: {len(content)}')
await browser.close()
asyncio.run(main())
方案三:手动修补Selenium
如果不想用第三方库,可以手动修补Selenium来绕过检测:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
options = Options()
# 1. 排除自动化开关
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_experimental_option('useAutomationExtension', False)
# 2. 禁用Blink特征检测
options.add_argument('--disable-blink-features=AutomationControlled')
# 3. 设置合理的窗口大小和UA
options.add_argument('--window-size=1920,1080')
options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36')
driver = webdriver.Chrome(options=options)
# 4. 通过CDP命令覆盖webdriver属性
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': '''
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
});
// 伪造plugins
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5]
});
// 伪造languages
Object.defineProperty(navigator, 'languages', {
get: () => ['zh-CN', 'zh', 'en']
});
// 删除CDP痕迹
const originalQuery = window.navigator.permissions.query;
window.navigator.permissions.query = (parameters) => (
parameters.name === 'notifications'
? Promise.resolve({ state: Notification.permission })
: originalQuery(parameters)
);
'''
})
driver.get('https://bot.sannysoft.com')
注意:手动修补的成功率不如UC或Patchright,因为检测点很多且持续更新。
实战:完整的反检测爬虫
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import random
import json
class StealthBrowser:
def __init__(self, proxy=None, headless=False):
options = uc.ChromeOptions()
if proxy:
options.add_argument(f'--proxy-server={proxy}')
if headless:
options.add_argument('--headless=new')
options.add_argument('--window-size=1920,1080')
options.add_argument('--lang=zh-CN')
self.driver = uc.Chrome(options=options)
self.wait = WebDriverWait(self.driver, 15)
def get(self, url, wait_selector=None):
"""访问页面,可选等待特定元素加载"""
self.driver.get(url)
self._random_delay()
if wait_selector:
self.wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, wait_selector))
)
return self.driver.page_source
def scroll_page(self, times=3):
"""模拟人类滚动行为"""
for _ in range(times):
scroll_amount = random.randint(300, 800)
self.driver.execute_script(f'window.scrollBy(0, {scroll_amount})')
self._random_delay(0.5, 1.5)
def click_element(self, selector):
"""点击元素,带随机偏移"""
element = self.wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, selector))
)
# 先滚动到元素可见
self.driver.execute_script('arguments[0].scrollIntoView({block: "center"})', element)
self._random_delay(0.3, 0.8)
element.click()
self._random_delay()
def fill_input(self, selector, text):
"""模拟人类输入"""
element = self.wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, selector))
)
element.clear()
for char in text:
element.send_keys(char)
time.sleep(random.uniform(0.05, 0.15))
def _random_delay(self, min_s=1.0, max_s=3.0):
time.sleep(random.uniform(min_s, max_s))
def close(self):
self.driver.quit()
# 使用示例
browser = StealthBrowser(headless=False)
try:
# 访问受保护的网站
html = browser.get(
'https://target-site.com',
wait_selector='div.content'
)
# 模拟滚动
browser.scroll_page(times=3)
# 提取数据
elements = browser.driver.find_elements(By.CSS_SELECTOR, '.item')
for el in elements:
print(el.text)
finally:
browser.close()
```
## 处理验证码
即使用了反检测浏览器,某些场景仍然会遇到验证码。这时需要结合API解决:
```python
import undetected_chromedriver as uc
from passxapi import PassXAPI
import re
import time
class AntiDetectScraper:
def __init__(self, captcha_api_key=None):
self.driver = uc.Chrome()
self.solver = PassXAPI(api_key=captcha_api_key) if captcha_api_key else None
def navigate(self, url):
self.driver.get(url)
time.sleep(3)
# 检查是否遇到验证码
page_source = self.driver.page_source
if self._has_captcha(page_source):
print('检测到验证码,尝试解决...')
self._solve_captcha(page_source, url)
return self.driver.page_source
def _has_captcha(self, html):
captcha_signs = [
'data-sitekey', 'g-recaptcha', 'h-captcha',
'cf-turnstile', 'challenge-platform'
]
return any(sign in html for sign in captcha_signs)
def _solve_captcha(self, html, url):
if not self.solver:
print('未配置验证码API')
return
# 提取sitekey
match = re.search(r'data-sitekey="([^"]+)"', html)
if not match:
return
sitekey = match.group(1)
# 根据类型调用对应的解决方法
if 'cf-turnstile' in html:
result = self.solver.solve_turnstile(sitekey=sitekey, url=url)
elif 'h-captcha' in html:
result = self.solver.solve_hcaptcha(sitekey=sitekey, url=url)
else:
result = self.solver.solve_recaptcha(sitekey=sitekey, url=url)
token = result.get('token')
if token:
# 注入token
self.driver.execute_script(f'''
document.querySelector('[name="cf-turnstile-response"], [name="g-recaptcha-response"], [name="h-captcha-response"]').value = "{token}";
''')
# 触发验证回调
self.driver.execute_script('''
if (window.turnstileCallback) turnstileCallback(arguments[0]);
if (window.onCaptchaSuccess) onCaptchaSuccess(arguments[0]);
''', token)
time.sleep(2)
print('验证码已解决')
def close(self):
self.driver.quit()
# 使用
scraper = AntiDetectScraper(captcha_api_key='your_passxapi_key')
try:
html = scraper.navigate('https://protected-site.com')
print(f'获取到内容: {len(html)} 字符')
finally:
scraper.close()
```
## 检测你的浏览器
在开发反检测爬虫时,用这些网站验证你的伪装效果:
```python
import undetected_chromedriver as uc
import time
driver = uc.Chrome()
# 测试网站列表
test_sites = [
'https://bot.sannysoft.com', # 综合检测
'https://nowsecure.nl', # Cloudflare检测
'https://abrahamjuliot.github.io/creepjs/', # CreepJS指纹
'https://pixelscan.net', # 浏览器指纹
]
for site in test_sites:
driver.get(site)
time.sleep(5)
driver.screenshot(f'test_{site.split("/")[2]}.png')
print(f'已截图: {site}')
driver.quit()
常见坑
1. Headless模式更容易被检测
# 不推荐:headless模式检测点更多
driver = uc.Chrome(headless=True)
# 推荐:用xvfb在服务器上运行有头模式
# apt install xvfb
# xvfb-run python scraper.py
2. 不要频繁创建销毁浏览器实例
# 错误:每个请求都创建新浏览器
for url in urls:
driver = uc.Chrome() # 慢!每次启动Chrome
driver.get(url)
driver.quit()
# 正确:复用浏览器实例
driver = uc.Chrome()
for url in urls:
driver.get(url)
time.sleep(random.uniform(2, 5))
driver.quit()
```
### 3. 记得模拟人类行为
```python
# 机器人行为:瞬间完成所有操作
driver.get(url)
driver.find_element(By.ID, 'search').send_keys('keyword')
driver.find_element(By.ID, 'submit').click()
# 人类行为:带随机延迟
driver.get(url)
time.sleep(random.uniform(1, 3))
search_box = driver.find_element(By.ID, 'search')
for char in 'keyword':
search_box.send_keys(char)
time.sleep(random.uniform(0.05, 0.2))
time.sleep(random.uniform(0.5, 1.5))
driver.find_element(By.ID, 'submit').click()
总结
Selenium反检测的核心思路:
- 用UC或Patchright替代原生Selenium,自动处理大部分检测点
-
- 避免headless模式,用xvfb在服务器上运行有头浏览器
-
- 模拟人类行为:随机延迟、滚动、鼠标移动
-
- 遇到验证码用API解决,比手动点击更可靠
验证码解决推荐 PassXAPI(https://www.passxapi.com/en),注册即送1000次免费调用,支持reCAPTCHA、hCaptcha、Turnstile等主流验证码,$0.001/次。Python SDK:passxapi-python
- 遇到验证码用API解决,比手动点击更可靠
觉得有帮助请点赞收藏,有问题欢迎评论区讨论。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)