资讯动态

Selenium ChromeDriver版本匹配与Web自动化实战:从环境配置到元素定位

发布时间:2026/9/9 10:56:39 来源:尧图企业网站定制
1. 为什么一定要先搞懂ChromeDriver版本匹配做Web自动化的人应该都经历过这种场景Selenium代码写得挺顺一运行控制台直接甩一个SessionNotCreatedException说什么host version和chromedriver version不匹配你还得去翻日志才能看懂。这个错误从我开始用Selenium的第一天起就见过无数次后来帮同事排查问题也频繁碰到。今天这篇我就围绕Selenium ChromeDriver这条主线把从版本匹配到环境配置从元素定位到爬虫可视化的完整链路拆开来讲顺便把那些我踩过的坑、试出来的土办法一并分享出来。ChromeDriver的本质可以理解成一座桥。Selenium是自动化脚本的指挥中心ChromeDriver是桥梁脚本的命令通过它传给Chrome浏览器执行。这座桥一旦跟浏览器版本对不上就算脚本逻辑再正确也白搭。先解决一个最核心的问题怎么判断自己该下载哪个版本的ChromeDriver。1.1 版本不匹配的典型翻车现场先看两个最经典的报错信息大家以后碰见了可以直接照方抓药SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 108 Current browser version is 121.0.6167.85 with binary path ...还有这种UnknownError: session deleted because of page crash第一种直白地告诉你驱动版本和浏览器版本对不上。第二种虽然看起来像是在说页面崩溃但很多时候也是ChromeDriver和Chrome版本之间不兼容导致的尤其是那些用旧驱动去驱动新浏览器的场景。我第一次遇到的时候第一反应是重装Chrome折腾半天没用。后来才发现问题根本不在浏览器而在Driver版本上。1.2 版本匹配背后的原理ChromeDriver和Chrome之间不是随意兼容的它遵循一个版本主版本匹配原则。什么意思呢就是ChromeDriver的主版本号必须跟Chrome浏览器的主版本号保持一致。Chrome版本号一般长这样121.0.6167.85。第一段是主版本号也就是121。如果Chrome是121版本那ChromeDriver也必须是121开头的版本这就叫主版本匹配。但这里有个细节容易被忽略ChromeDriver的版本号并不完全跟Chrome一致。比如Chrome是121.0.6167.85ChromeDriver可能就叫121.0.6167.184尾号不同很正常只要主版本号是121就基本能用。注意我自己实测过主版本号差1个版本90%的情况下会报错但也有极少数小版本跨度内能跑通。别赌这个概率老老实实对齐主版本。1.3 怎么查看本机Chrome版本在动手下载驱动之前先确认自己电脑上Chrome的版本。Windows上打开Chrome浏览器点右上角三个点找到帮助再点关于Google Chrome弹出来的页面里就能看到完整版本号。Linux服务器上可以在终端里执行google-chrome --versionMac上执行/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version确认完版本号记下第一段的数字比如121后面下载驱动就照着这个找。2. ChromeDriver下载与环境搭建全流程网上关于ChromeDriver下载地址的说法很多有些还指向第三方站点我劝你一律不要用。第三方站点经常捆绑旧版本、带广告、甚至打包一些脚本进去安全性完全没有保障。2.1 ChromeDriver官方下载地址与选择方法官方下载地址就两个背下来就行稳定版下载https://googlechromelabs.github.io/chrome-for-testing/历史版本存档https://chromedriver.chromium.org/downloads注意现在Google把ChromeDriver的下载入口统一收编到了chrome-for-testing这个页面以前那个老的chromedriver.storage.googleapis.com虽然还能用但界面已经不维护了。打开chrome-for-testing页面后你会看到类似这样的表格或者列表版本号发布日期下载链接151.0.7922.1382025-xx-xx多个平台可用150.x......121.0.6167.184......你需要找到跟自己Chrome主版本号一致的条目。比如你Chrome是151就找151.0.7922.138这个版本。提示如果页面列出了多个同主版本的条目选最新的那个。比如有151.0.7922.138和151.0.7922.120选138。2.2 Windows、Linux、Mac不同平台驱动下载差异ChromeDriver的压缩包按操作系统分了好几种下载的时候要看清楚平台标识win64Windows 64位现在绝大多数Windows电脑都是这个linux64Linux 64位服务器上常见mac-x64Mac的Intel芯片mac-arm64Mac的M1/M2/M3芯片这里有第一个容易踩的坑就算你是Windows 32位系统现在官方也已经不单独出win32了直接下载win64版本就行。Chrome从某个版本开始已经放弃了32位支持所以别纠结。下载下来是个压缩包解压后里面只有一个可执行文件Windows下叫chromedriver.exeLinux/Mac下叫chromedriver。2.2.1 Windows下的放置与路径配置Windows下你解压后可以直接把chromedriver.exe放到一个固定目录比如C:\selenium\然后把C:\selenium加入环境变量的Path里。怎么加右键此电脑 → 属性 → 高级系统设置 → 环境变量 → 在系统变量里找到Path编辑新建一条填上C:\selenium保存。加好之后重新打开命令行输入chromedriver --version如果能打印出类似ChromeDriver 151.0.7922.138的信息说明环境变量配置成功。2.2.2 Linux服务器下的放置与权限Linux下更简单解压后把文件移动到/usr/local/bin目录下sudo mv chromedriver /usr/local/bin/ sudo chmod x /usr/local/bin/chromedriver然后执行chromedriver --version验证。注意chmod x这步不能忘我之前在服务器上就因为没有执行权限报了一堆诡异的错。2.3 三种驱动加载方式对比很多教程在讲环境变量之后就直接进入了Selenium代码但我觉得这里有必要多说两句。因为实际工作里驱动加载方式不止一种每种适用场景不一样。方式代码/操作适用场景环境变量系统PATH中配置driver路径代码里不用指定单机开发环境固定代码指定路径代码里写executable_path或service参数临时切换驱动版本、项目内管理驱动Selenium Manager自动管理不指定驱动Selenium自动下载匹配版本Selenium 4.6网络不受限时我个人的建议如果是自己电脑上学习、调试用环境变量方式最省事。但如果是写项目、交给别人跑一定要用代码指定路径的方式因为别人机器上的环境变量不一定配了。代码指定路径的写法有两种取决于你的Selenium版本。Selenium 4.6之前的写法from selenium import webdriver driver webdriver.Chrome(executable_pathrC:\selenium\chromedriver.exe)Selenium 4.6及之后的写法旧写法虽然能用但会有DeprecationWarningfrom selenium import webdriver from selenium.webdriver.chrome.service import Service service Service(rC:\selenium\chromedriver.exe) driver webdriver.Chrome(serviceservice)关于Selenium Manager这里单独说一下。Selenium 4.6版本开始内置了一个叫Selenium Manager的工具如果你不指定驱动路径它会自动检测你本机Chrome版本然后去官方源下载对应版本的ChromeDriver自动缓存到本机。听起来非常智能对吧但它有个硬前提你的机器能正常访问官方下载源。如果网络受限Selenium Manager会卡住或者报错。所以我的结论是能联网的场景下可以用Selenium Manager省事但是有网络白名单的环境老老实实手动下载驱动别折腾。3. Selenium安装与核心概念扫盲3.1 Selenium库安装与版本选择Selenium是一个自动化测试框架支持Python、Java、JavaScript、C#等主流语言。我自己最常用的是Python所以下面的示例都以Python为主。安装Selenium很简单直接pip安装pip install selenium装完以后检查一下版本pip show selenium如果你看到的是4.6以上的版本恭喜可以直接体验Selenium Manager如果是4.1或更早建议升级一下pip install --upgrade selenium这里有个细节Selenium 4和3之间的API有几处差异。如果你在网上搜到的教程是2021年之前的很多写法在Selenium 4里会有警告比如executable_path这个参数以及find_element_by_id、find_element_by_xpath这一系列方法在Selenium 4里全部变成了find_element(By.ID, ...)的写法。3.2 Selenium是什么能解决什么问题顺便给刚入门的朋友补个基础概念。Selenium归根结底是一个浏览器自动化框架它不爬数据它只是模拟人类操作浏览器。你可以用它自动点击按钮填写并提交表单提取网页内容截屏爬虫需要执行JavaScript动态渲染的页面比起直接发HTTP请求的爬虫库比如requestsSelenium最大的优势在于它能执行JavaScript。很多网站的页面数据是异步加载的requests拿不到但Selenium控制真实浏览器浏览器渲染完页面后数据自然就在那儿了。3.3 爬虫可视化是什么意思很多人可能听过selenium爬虫可视化这个说法其实它有两层意思一层意思是你用Selenium做爬虫时操作过程是可见的——浏览器会真实打开一个窗口你能看到页面加载、滚动、点击的过程。这对调试非常有帮助出了问题可以直观看到。另一层意思是浏览器开发者工具F12里的Network面板、Elements面板、Console面板都是可视化的你可以用它来观察请求、定位元素、调试脚本。比起纯命令行抓包这种方式直观得多。我在调试爬虫脚本时几乎全程盯着浏览器窗口看哪里点错了、哪个元素没加载出来一眼就能看到。这就是Selenium比requests优雅的地方。4. 元素定位实操八种方法怎么选4.1 Selenium八种元素定位方式写Selenium自动化最核心的实操就是元素定位。Selenium一共提供了八种定位方式我把它们的API列出来定位方式Selenium 4写法使用频率ID定位By.ID最高类名定位By.CLASS_NAME高Name定位By.NAME中标签名定位By.TAG_NAME低链接文本定位By.LINK_TEXT中部分链接文本定位By.PARTIAL_LINK_TEXT低XPath定位By.XPATH极高CSS选择器定位By.CSS_SELECTOR高先说结论By.ID优先找不到就用By.XPATH再不行用By.CSS_SELECTOR。为什么ID优先因为HTML规范要求页面内ID是唯一的一个页面里不可能出现两个相同ID的元素所以用ID定位是100%精准的。不过实际项目里并不是所有元素都有ID尤其是一些老系统、复杂系统前端开发不写ID或者动态生成ID这时候就得靠XPath。4.2 XPath定位的进阶技巧XPath是很多人的痛点但也是解决复杂定位的钥匙。我把它拆解成几个实用的套路。绝对路径写法不推荐长而且脆弱。比如这样/html/body/div[1]/div[2]/div/div/form/input页面结构稍微调整一下这个定位就废了。推荐相对路径//input[idusername]意思是任意位置找到input标签且它的id属性等于username。掌握了//加属性这种写法再配合几个逻辑语法基本能应付80%的场景语法含义示例//标签[属性值]按属性定位//input[nameq]//标签[text()文本]按文本定位//button[text()登录]//标签[contains(class, xx)]模糊匹配属性//div[contains(class, item)]*[idxx]任意标签//*[idusername]//标签[a1 and b2]多条件与//input[typetext and nameuser]//标签//子标签后代关系//form//input这几个语法组合起来能解决绝大多数定位问题。我记忆方法很简单先按标签名找找不到按属性找属性不确定就加contains多个条件就加and。4.3 元素定位失败的五种常见原因与解决方案元素定位报错最常见的是NoSuchElementException报错会告诉你找不到对应元素。但实际十次里有八次不是定位表达式写错了而是另一些原因。我把这些原因整理成一个排查清单页面还没加载完就执行了下一步元素在JavaScript运行之后才出现在DOM里。解决方案加等待。元素在iframe里直接找肯定找不到要先切换进iframe。解决方案driver.switch_to.frame()。元素在Shadow DOM里这类元素需要先获取宿主元素再用JS进入ShadowRoot去操作。窗口没有切换到新打开的标签页点击链接打开了新窗口但driver还在旧window句柄上。解决方案driver.switch_to.window()。元素被遮挡或者不可见Selenium默认只跟可交互元素交互如果元素被弹窗、浮层挡住了要先把遮挡物处理掉。这几种情况里iframe是新手最容易踩的。判断方法很简单在F12的Elements里搜元素如果DOM树里它处于iframe标签内部那就需要先切frame。切frame的代码# 按索引切第一个iframe driver.switch_to.frame(0) # 按name或id切换 driver.switch_to.frame(iframeName) # 按WebElement对象切换 iframe_element driver.find_element(By.XPATH, //iframe[idxx]) driver.switch_to.frame(iframe_element)操作完iframe内部元素后如果要操作主页面元素记得切回来driver.switch_to.default_content()4.4 等待策略显式等待和隐式等待刚才排查清单第一条就是页面加载问题这里展开说说Selenium的等待机制。Selenium提供了三种等待方式强制等待time.sleep(2)无脑但低效隐式等待driver.implicitly_wait(10)给find_element设置一个最大等待时间显式等待WebDriverWait配合expected_conditions等待某个条件成立我对三者的推荐顺序显式等待优先隐式等待兜底强制等待能不用就不用。隐式等待的缺点是它只对元素查找生效而且一旦设置对整个driver生命周期都生效。页面虽然还在加载但如果元素已经出现在DOM里隐式等待会立即返回。显式等待的代码这样写from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 最多等10秒直到id为login的元素可见 element WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, login)) )这里有个容易踩的坑presence_of_element_located和visibility_of_element_located不一样。前者只要求元素在DOM中存在后者要求元素可见。有些元素虽然存在于DOM但被隐藏了用前者能拿到用后者会超时。我的建议是如果下一步要点击元素用element_to_be_clickable这个条件同时检查了存在、可见、可用三重状态是最稳妥的。button WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.XPATH, //button[text()提交])) ) button.click()5. 完整实操从零写一个Web自动化脚本理论讲了不少下面我带大家完整走一遍实操流程。这个案例我选择的是自动登录一个普通网站查询某个信息并抓取结果。5.1 需求分析与脚本结构设计假设目标网站在https://example.com/login我们需要打开登录页输入用户名和密码点击登录按钮等待跳转到首页提取首页上某个区块的数据打印结果并关闭浏览器这个任务看起来简单但里面涉及了Web自动化的经典环节启动浏览器、元素定位、输入、点击、等待、数据提取、资源释放。一套流程跑完差不多就摸清Selenium的常规操作了。5.2 完整代码与逐行说明直接上代码我会把每一步的意图写在注释里import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.service import Service from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 通过Service指定驱动路径避免依赖环境变量 service Service(rC:\selenium\chromedriver.exe) # 启动浏览器 driver webdriver.Chrome(serviceservice) # 1. 打开登录页 driver.get(https://example.com/login) # 设置窗口大小方便观察有些页面在小窗口下布局会变 driver.maximize_window() try: # 2. 等待用户名输入框出现并输入用户名 username_input WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, username)) ) username_input.clear() username_input.send_keys(my_account) # 3. 输入密码 password_input driver.find_element(By.ID, password) password_input.clear() password_input.send_keys(my_password) # 4. 点击登录按钮 login_btn WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.XPATH, //button[contains(text(), 登录)])) ) login_btn.click() # 5. 等待页面跳转确认登录成功 # 常见的判断方式等待某个登录后才会出现的元素 welcome WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CLASS_NAME, welcome-text)) ) print(登录成功欢迎信息, welcome.text) # 6. 提取目标数据这里假设页面上有一个列表 items driver.find_elements(By.XPATH, //div[classinfo-item]) for index, item in enumerate(items, start1): title item.find_element(By.CLASS_NAME, title).text value item.find_element(By.CLASS_NAME, value).text print(f第{index}条{title} {value}) except Exception as e: # 任何时候出错可以截图保存现场这招调试特别有用 driver.save_screenshot(debug_screenshot.png) print(脚本执行出错, e) finally: # 7. 释放资源关闭浏览器 driver.quit()补充几个细节。第27行send_keys是模拟键盘输入的方式能输入文本、还能模拟组合键如Keys.ENTER、Keys.CONTROL a全选。第31行contains(text(), 登录)这个写法是模糊匹配因为有些按钮的文本可能带空格或者前后有其他字符。如果用text()登录精确匹配会出问题。第57行driver.quit()和driver.close()不一样。close()只关闭当前标签页quit()会结束整个Chrome进程并释放所有资源。我建议一律用quit()因为close()关掉标签页后Chromedriver进程可能还在后台挂着占用资源。5.3 运行调试与结果验证跑这个脚本的时候你会看到一个Chrome窗口自动打开然后自动执行一系列操作。这就是爬虫可视化的效果整个过程尽收眼底。如果某一步卡住了把异常处理里的截图打开看看。截图里能直接看到浏览器最后的状态——是停留在登录页没跳转还是弹出了错误提示一目了然。我在实际项目里调试这些脚本的流程是先让它跑出错就看截图根据截图判断是定位问题、等待问题还是页面结构变化然后修改代码重新跑。这种可视化调试的效率比写代码去打印一堆日志要高很多。6. 常见问题与排查技巧实录6.1 ChromeDriver版本冲突与闪退前面的报错我已经列过两种。这里说说更隐蔽的一种情况Chrome浏览器在后台自动更新了版本但你本地的ChromeDriver还是旧版第二天跑脚本就报错了。怎么解决最直接的办法是更新驱动。但还有一个更优雅的方案把Chrome的自动更新关掉或者用固定版本的Chrome浏览器做测试环境。我自己在服务器上跑定时任务时都是固定一个Chrome版本下载对应的ChromeDriver然后把这个组合固化下来。这样只要服务器不手动更新脚本就能一直稳定运行。6.2 打开网页白屏或者页面加载极慢这个问题通常不是Selenium本身的问题而是启动参数导致的。Chrome默认会加载一堆扩展、还有一些硬件加速逻辑会影响启动速度。解决办法是在启动时加options参数禁用这些功能from selenium.webdriver.chrome.options import Options options Options() options.add_argument(--disable-extensions) options.add_argument(--disable-gpu) options.add_argument(--disable-dev-shm-usage) options.add_argument(--no-sandbox) options.add_argument(--langzh-CN) # 无头模式不显示浏览器窗口服务器上常用 options.add_argument(--headlessnew) driver webdriver.Chrome(serviceservice, optionsoptions)--no-sandbox这行在Linux服务器上跑容易遇到权限问题加上能省很多事。--headlessnew是无头模式适合在服务器上跑爬虫不弹窗口还能节省资源。6.3 元素点击失败明明定位到了却报错有一种情况很常见元素定位到了但一点击就报ElementClickInterceptedException。原因是元素被其他元素遮挡了。比如页面底部有个悬浮广告挡住了你要点的按钮。解决办法可以绕一下用JavaScript直接触发点击绕过遮挡层element driver.find_element(By.XPATH, //button[text()提交]) driver.execute_script(arguments[0].click();, element)这个方法的本质是绕过Selenium对元素必须可见可交互的检查直接触发元素的事件。我在处理复杂页面时经常用但要注意不要滥用正常能点的情况下没必要走这一步。6.4 关于chromedriver 108和151这种版本号的特殊问题网上经常有人搜chromedriver 108或者chromedriver 151.0.7922.138说明大家在实际下载中经常会遇到具体版本号的问题。我特别提醒一句搜索到的那些第三方下载站很多驱动都是旧版本而且网站界面做得跟官方一模一样非常容易混淆。我之前有个同事就是从某个高仿网站下载的压缩包解压后发现chromeDriver打不开仔细一看文件大小不对根本是恶意的假文件。所以再次强调只从googlechromelabs.github.io/chrome-for-testing和chromedriver.chromium.org下载。如果这两个地址在你的网络环境里访问不了尝试通过镜像或者干脆换一台网络正常的机器下载后再拷贝过来也不要图省事从第三方随便下载。6.5 常见错误速查表我整理了平时最常碰到的几个报错以及排查方向方便你直接对照报错信息根因排查/解决方法SessionNotCreatedExceptionChromeDriver与Chrome版本不匹配检查两者主版本号下载对应的ChromeDriverWebDriverException: unknown error: cannot find Chrome binaryChrome安装路径没有被Selenium找到用options.binary_location指定Chrome路径NoSuchElementException元素不存在或未加载出来确认定位表达式、是否在iframe中、是否加等待ElementClickInterceptedException元素被其他元素遮挡用JS点击或先关闭遮挡元素TimeoutException等待条件超时增加等待时间或检查页面是否有异常弹窗StaleElementReferenceException元素已从DOM中移除引用过期重新获取元素引用InvalidArgumentException参数格式不对检查send_keys类型、URL格式7. 几个提高效率的个人经验7.1 把Driver路径写进配置文件我在实际项目里一般不会在代码里硬编码driver路径而是写一个配置文件比如config.pyimport os DRIVER_PATH os.getenv(CHROME_DRIVER_PATH, rC:\selenium\chromedriver.exe)这样换机器、换驱动版本时只需要改环境变量代码不用动。7.2 用复制XPath代替手写F12的Elements面板里右键一个元素可以直接Copy→Copy XPath。但要注意这个功能复制出来的是绝对路径非常长而且脆弱我只用它来快速定位问题不会用到生产代码里。更好的办法是复制Copy selector拿到的是CSS选择器通常比绝对XPath短一些。但在项目里我还是坚持以手写相对XPath为主因为可控性最强。7.3 关于无头模式的一个小技巧服务器上跑无头模式时如果遇到页面看起来正常但某些元素没有加载的情况可以先调试一遍有头模式加上截图输出看到底是哪一步出的问题。另外无头模式的--headlessnew和旧版--headless在渲染行为上有些差异新版更接近有头模式。如果你用的Selenium版本比较老有些站会在检测到无头模式时故意返回不同的页面内容这时候可以尝试用user-agent伪装一下options.add_argument(user-agentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36)7.4 定期巡检脚本如果是白嫖的免费网站前端团队改版是常态。你辛苦写的自动化脚本很可能在某一天早上就突然跑不动了。我的习惯是给爬虫脚本设置一个简单的健康检查每次运行时如果连续失败3次就发一个告警通知。这样即使半夜脚本挂了我次日早上也能第一时间知道而不是等到数据缺失了才发现。最后再说一点个人体会Selenium这套体系看起来就是一个库加一个驱动但真正跑起来之后你会发现细节特别多。版本匹配、元素定位、等待策略、异常处理每一个环节都藏着经验。把这些基础打牢再去写那些复杂的自动化场景就会从容很多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价