selenium启动报错或空白页主因是驱动与浏览器版本不匹配或浏览器自动更新,需下载同主版本号且架构匹配的驱动;元素获取失败应优先用显式等待并等可交互状态;反爬关键在于抹除自动化指纹、模拟人类行为而非依赖万能驱动。

为什么 selenium 启动就报 WebDriverException 或空白页
多数情况不是代码写错了,而是驱动和浏览器版本不匹配,或者没关掉浏览器自动更新。Chrome 一升级,chromedriver 就可能失效;Edge 同理,得用对应版本的 msedgedriver。
- 检查浏览器版本:
chrome --version(终端执行),再上 chromedriver 官网 下载同主版本号的驱动 - 把驱动放系统 PATH 里,或启动时显式指定路径:
webdriver.Chrome(options=opts, service=Service("/path/to/chromedriver")) - Mac M1/M2 用户注意:必须下载 arm64 架构的
chromedriver,x86_64 会静默失败 - Windows 上如果弹出“开发者模式”警告页,说明启用了自动化标志,加这行屏蔽:
opts.add_experimental_option("excludeSwitches", ["enable-automation"])
页面加载完却拿不到元素:等什么、怎么等才可靠
time.sleep() 是最常见也最危险的写法——慢了浪费时间,快了就 NoSuchElementException。真实网页有 JS 渲染、懒加载、接口延迟,光看 document.readyState === "complete" 不够。
- 优先用显式等待:
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".item-list"))) - 别只等“存在”,要等“可交互”:
EC.element_to_be_clickable比presence_of_element_located更贴近真实操作 - 遇到 Vue/React 动态渲染的列表,等父容器出现后,再查子元素数量是否 > 0,比硬等某个 class 更稳
- 慎用
driver.implicitly_wait():它影响全局,且对“元素已存在但不可见”无效
登录后还是被识别为机器人:哪些行为暴露了 Selenium
网站不靠 UA 判断,而是检测 navigator.webdriver、plugins、languages 等指纹特征。默认 selenium 浏览器几乎等于“此用户是爬虫”。
- 必须关闭自动化标记:
opts.add_argument("--disable-blink-features=AutomationControlled"),再配合 JS 注入覆盖navigator.webdriver - 随机化
user-agent不够,还要伪造accept-language和screen.width/height,否则行为太“标准” - 鼠标移动不能直线,用
ActionChains做带偏移、变速的移动,哪怕只是 hover 登录按钮 - 避免连续调用
click(),中间穿插move_to_element()和pause(0.3),模仿人类停顿
为什么用 undetected-chromedriver 反而更不稳定
它本质是自动 patch Chrome 二进制、绕过检测,但每次 Chrome 更新都可能让 patch 失效。不是“用了就万事大吉”,而是把问题从 JS 层转移到了二进制兼容性层。
- 新版
undetected-chromedriver v3已弃用,推荐改用uc包(pip install undetected-chromedriver2) - 它默认禁用扩展、关闭日志、隐藏
cdc_变量,但如果你自己又加了--load-extension,反而触发检测 - 在 CI/CD 环境(如 GitHub Actions)中,无头模式下
uc可能因缺少字体或音频设备崩溃,这时不如手动配置原生selenium+ 指纹抹除 - 真正难绕过的不是登录页,而是后续行为:比如 3 秒内点 5 个商品、滚动到底部立刻翻页——这种节奏比 UA 更容易被风控
反爬机制永远在变,稳定的关键不是找一个“万能驱动”,而是让每次访问的 DOM 访问路径、JS 执行痕迹、网络请求时序都带点人味儿。越想藏得严实,越要花时间观察目标站的真实用户行为。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











