在 Ubuntu 上给 Chromium 配 Selenium最让人抓狂的往往是 chromedriver 版本对不上。你去下载页随手拿了“最新版 chromedriver”结果一启动就报This version of ChromeDriver only supports Chrome version XXX然后开始怀疑人生。其实这不是操作问题而是很多人没搞明白Ubuntu 上的 Chromium 是一套非常特殊的发布体系它的版本和驱动之间不是“都是最新就行”的关系而是“必须精确对齐”的关系。这篇文章我会从 Ubunt 的 Chromium 是怎么装的讲起逐步帮你确定当前版本、对比三条常见的获取驱动路线最后给出一套可以落地的安装脚本和排查清单。不管你是第一次在 Linux 上跑 Selenium还是已经被版本问题折磨过几轮按这个流程走完基本不会再被 chromedriver 折腾。1. 先搞清楚Ubuntu 上的 Chromium 版本是一个“移动靶”很多人在 Ubuntu 里执行apt install chromium-browser以为装的是一个普通的 deb 包。但真相是Ubuntu 从较早的版本开始就不再直接维护 Chromium 的 deb 包了20.04 之后你通过 apt 装到的chromium-browser往往只是一个过渡包最终的二进制是从 snap 商店拉下来的快照。换句话说Chromium 浏览器的版本不再跟着 Ubuntu 的软件源仓库走了而是跟着 snap 的更新渠道走。这是一个非常关键的事实因为它直接决定了“最新版 chromedriver”应该从哪里来。如果你把这个 Ubuntu 的 Chromium 和 Google 官方发布的 Chrome 比一下你会发现版本号通常有偏差。Chrome 推送到了 126snap 里的 Chromium 可能还在 125Chrome 到了 130snap 可能才跟上 128。这不是 Ubuntu 故意落后而是 snap 的构建、审核、灰度发布有自己的节奏。chromedriver 的问题就出在这里。它不是一个“通用遥控器”它是和具体浏览器版本绑定的调试代理。ChromeDriver 通过 Chrome DevTools Protocol 和浏览器通信这个协议在不同版本之间会有新增、废弃、调整。你可以把 chromedriver 想象成一把钥匙浏览器版本就是锁芯的齿纹版本差的太大就插不进去。实际操作中最常见的报错长这样session not created: This version of ChromeDriver only supports Chrome version 130 Current browser version is 128.0.xxxx with original user data directory这个报错已经把答案写在脸上了驱动是 130 的浏览器却是 128 的。解决办法不是去改代码而是让二者的版本号对到同一个频道上。所以所谓“最新版 chromedriver”在 Ubuntu 这个场景下其实有两个含义全网最新的 chromedriver与你本机 Chromium 版本匹配的、最合适的那一个。多数人要的是第二个。因为就算你把最新版驱动下载下来了你的浏览器没跟上照样跑不起来。这篇文章后续所有步骤都会围绕“让你的浏览器和驱动精确匹配”这个目标展开。2. 开工前先确诊你的 Chromium 是哪一种当前版本是多少不要一上来就下载驱动先花两分钟完全搞清楚你机器上到底装了什么。先执行这个命令组合which chromium chromium-browser google-chrome 2/dev/null ls -l $(which chromium) 2/dev/null snap list chromium 2/dev/null dpkg -l | grep -i chromium 2/dev/null不同输出代表不同情况如果snap list chromium有结果说明你用的是 snap 版 Chromium如果dpkg -l | grep -i chromium显示的是chromium-browser那多半是旧版 deb或者是过渡包如果ls -l /usr/bin/chromium显示的是一个指向/snap/bin/chromium的软链接那它本质上仍然是 snap 版。确认类型之后再读取版本号chromium --version正常情况下你会看到类似Chromium 126.0.6478.126记下这个版本号后面所有下载匹配操作都靠它。注意 Chromium 的版本号是四段式主版本.次版本.构建版本.补丁版本例如126.0.6478.126。其中主版本最容易变也最容易引发兼容性问题Build 号在 Chromium 生态里也比 Chrome 的版本更能体现内核迭代的位置。顺便确认一下系统架构uname -m如果你是 x86_64后面可以用 Google 官方提供的 linux64 驱动包如果你是 aarch64比如树莓派上跑 Ubuntu很多官方测试文件没有对应的 aarch64 构建这种情况下 snap 自带的驱动可能反而是你唯一的省心方案。如果你的系统里根本还没装 Chromium那就先装sudo snap install chromium装完再跑一次chromium --version记住这个版本。到这里你已经完成了最容易被忽略的一步不是在“猜”我应该用什么驱动而是在“确定”我当前的浏览器版本。3. 三条路搭 chromedriver利弊、命令、我的选择获取 chromedriver 的路不止一条但每条路的坑不一样。下面我把三条主流路线拆开讲清楚命令也给全你按自己的情况选就行。3.1 Ubuntu apt 包省事但版本大概率“年龄不小”最简单粗暴的做法是sudo apt update sudo apt install chromium-chromedriver -y装好之后驱动一般会出现在/usr/bin/chromedriver执行一下chromedriver --version你会看到类似输出ChromeDriver 115.0.5790.110问题是这个版本很可能不是最新的。因为 Chromium 已经从 apt 仓库里退场apt 维护的chromium-chromedriver也就失去了同步更新的源头。它的版本往往停留在仓库最后一次构建的时间点和 snap 里不断更新的 Chromium 之间存在明显落差。这条路线适合什么场景呢如果你对“最新”没有执念只要浏览器和驱动能匹配上而且你查了下两者版本刚好相近那用它最省心不用解压、不用配 PATH、不用考虑文件夹层级。但如果你刚装了一个很新的 Chromiumapt 里的旧驱动大概率带不动。另外提醒一句如果你还要从其他途径手动装新版 chromedriver尽量别直接覆盖/usr/bin/chromedriver否则以后 apt 升级时可能和你自己放的文件冲突。比较干净的做法是把自己下载的驱动放到/usr/local/bin。3.2 Snap 自带驱动版本最一致但能不能用要看接口很多人不知道Ubuntu 的 Chromium snap 包里其实是自带 chromedriver 的。先直接执行chromium.chromedriver --version如果它能正常输出版本号那恭喜你这是所有方案里版本匹配最完美的驱动和浏览器一起发布、一起升级永远不会出现“驱动新了、浏览器还没跟上”的错位。如果提示命令不存在或者提示需要连接接口可以检查一下 snap 接口snap connections chromium看到有chromedriver相关接口未连接时手动连接一次sudo snap connect chromium:chromedriver这里不同发行版维护的 snap 版本可能略有差异接口名称以snap connections chromium实际输出为准。Snap 自带驱动的优点很吸引人但也要留意它的边界。snap 的沙箱机制比较严格chromium 进程和 chromedriver 之间可能有额外的权限限制尤其是做远程调试、自定义 profile 目录、操作下载文件这类场景时偶尔会遇到诡异的问题。我的建议是如果只是跑常规自动化脚本优先尝试它如果后面遇到和沙箱强相关的报错再切换到底层权限更直接的官方驱动包。3.3 Chrome for Testing 官方目录真正能拿到“当前最新版”的地方Google 官方为自动化测试场景提供了一个专门的版本目录叫 Chrome for Testing网址核心是https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-download-urls.json这个 JSON 里列出了发布过的所有“已知可用版本”以及 Chrome 浏览器和 chromedriver 对应的下载地址。它不是直接给你一个 zip 链接而是给一个结构化清单你需要自己解析出想要的版本。先去拿最新版本号curl -s https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-download-urls.json | python3 -c import json,sys; djson.load(sys.stdin); print(d[versions][-1][version])拿到类似154.0.xxxx的输出后再拼出下载地址。更推荐的方式是直接用一小段脚本解析出 linux64 的驱动链接LATEST_VERSION$(curl -s https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-download-urls.json | python3 -c import json,sys; djson.load(sys.stdin); print(d[versions][-1][version])) DRIVER_URL$(curl -s https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-download-urls.json | python3 - $LATEST_VERSION PY import json, sys, urllib.request target sys.argv[1] data json.load(urllib.request.urlopen(https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-download-urls.json)) for item in data[versions]: if item[version] target: for d in item[downloads][chromedriver]: if d[platform] linux64: print(d[url]) break break PY ) wget $DRIVER_URL unzip -o $(basename $DRIVER_URL) cd chromedriver-linux64 sudo install -m 0755 chromedriver /usr/local/bin/chromedriver chromedriver --version这个方案的优点是版本新、渠道官方、没有 apt 和 snap 的“滞后滤镜”而且你可以在 JSON 清单里自由选择任意历史版本非常灵活。缺点是命令比 apt 多还需要一点解析 JSON 的基础第一次操作时会觉得繁琐。注意不同时期的压缩包内部目录名不完全一致。老版本一般叫chromedriver_linux64新版本叫chromedriver-linux64解压后自己ls看一眼再进目录即可。3.4 选型建议路线版本匹配度获取成本适合场景主要坑apt 安装低容易滞后最低版本恰好匹配、追求省事驱动版本老旧snap 自带最高低不想折腾沙箱可接受权限/沙箱问题Chrome for Testing可精确指定中需要最新或精确版本需解析 JSON我的常规选择顺序是先试chromium.chromedriver --version能用就直接用不能用就走 Chrome for Testing 官方目录。apt 只在我确认它版本匹配时才考虑因为它最省事但也最不可控。4. 把浏览器和驱动按同一版本号“焊接”起来版本匹配这一步是整个流程里最值得认真做的。很多教程只告诉你“下载最新版”却没说清楚怎么判断“最新版适不适合我”。下面是我自己常用的完整流程。4.1 版本对齐的基本功先并行执行两个命令对比chromium --version chromedriver --versionchromedriver --version输出版本时通常长这样Starting ChromeDriver 126.0.6478.126 (......) on port 9515如果浏览器是126.0.6478.126驱动也是126.0.6478.126那基本就不用担心协议错位。严格来说真正强行要求的是主版本一致例如 126 对应 126但我在生产环境见过主版本相同但 build 号不同的场景仍然会偶发崩溃所以我建议能精确就精确至少保证主版本.次版本.构建版本三段对齐。4.2 一个自动锁定版本的安装脚本下面这个脚本会读取你本机 Chromium 的版本自动去 Chrome for Testing 清单里找对应版本的 chromedriver找不到就回退到同主版本的最新一个已知版本。#!/usr/bin/env bash set -euo pipefail CHROME_VERSION$(chromium --version | grep -oE [0-9]\.[0-9]\.[0-9]\.[0-9] | head -1) echo 检测到 Chromium 版本: $CHROME_VERSION DRIVER_URL$(python3 - $CHROME_VERSION PY import json, sys, urllib.request target sys.argv[1] url https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-download-urls.json with urllib.request.urlopen(url, timeout30) as resp: data json.load(resp) match None for item in data[versions]: if item[version] target: match item break if match is None: major target.split(.)[0] candidates [item for item in data[versions] if item[version].startswith(major .)] if not candidates: raise SystemExit(f没有找到主版本 {major} 对应的 chromedriver请手动检查清单) fallback candidates[-1] print(f精确版本 {target} 不在发布清单回退到 {fallback[version]}, filesys.stderr) match fallback for d in match[downloads][chromedriver]: if d[platform] linux64: print(d[url]) break PY ) echo 下载地址: $DRIVER_URL cd /tmp wget -N $DRIVER_URL ARCHIVE$(basename $DRIVER_URL) unzip -o $ARCHIVE if [ -d chromedriver-linux64 ]; then sudo install -m 0755 chromedriver-linux64/chromedriver /usr/local/bin/chromedriver elif [ -d chromedriver_linux64 ]; then sudo install -m 0755 chromedriver_linux64/chromedriver /usr/local/bin/chromedriver else echo 压缩包解压后没有找到预期的 driver 目录请检查 exit 1 fi chromedriver --version脚本里那句回退逻辑很重要。Chrome for Testing 的清单不是每天都更新的“版本流水账”它是“已知良好版本”清单偶尔有你本机 Chromium 特别新、但清单还没来得及收录的情况。这时候退回到同主版本最近的版本通常能跑通但需要你多留个心眼上线前务必跑一遍完整用例。4.3 找不到精确版本时的回退策略如果你机器上的 Chromium 版本特别老老到连 Chrome for Testing 早期目录里都没有那就别死磕 JSON 渠道。老版本驱动用的下载规则是https://chromedriver.storage.googleapis.com/{版本号}/chromedriver_linux64.zip比如你的 Chromium 是95.0.4638.54那么驱动地址就是https://chromedriver.storage.googleapis.com/95.0.4638.54/chromedriver_linux64.zip这个老规则目前仍然能访问用来兼容老旧浏览器非常方便。唯一的注意点是这个区域下载的 zip 解压后文件夹和二进制名称都是chromedriver_linux64/chromedriver安装方式和前面一样。还有一个更“极端”的办法不看版本号直接下载和你最接近版本对应的驱动强行跑。我不推荐在重要项目里这么干。大多数情况下它能跑因为 CDP 协议对旧版本兼容做得还可以但“可以兼容”不是“官方保证”。一旦遇到 CDP 命令变更你会得到一些很隐晦的报错排查成本反而更高。4.4 最小 Selenium 冒烟测试驱动装好之后不要急着跑完整项目先建一个干净环境做冒烟测试python3 -m venv .venv source .venv/bin/activate pip install selenium然后写一个最小脚本from selenium import webdriver from selenium.webdriver.chrome.service import Service options webdriver.ChromeOptions() # 如果你使用的是 snap 版 Chromium并且遇到了启动失败再把下面两行打开 # options.add_argument(--no-sandbox) # options.add_argument(--disable-dev-shm-usage) service Service(/usr/local/bin/chromedriver) browser webdriver.Chrome(serviceservice, optionsoptions) browser.get(https://example.com) print(browser.title) browser.quit()如果这能输出Example Domain说明浏览器和驱动已经从“安装成功”进化到了“真正能配合工作”的状态这时候再回归你的正式脚本效率会高很多。5. 实测中绕不开的坑和一句话排查法最后把我踩过、也帮别人排查过的几类高频问题集中列一下每一条都对应一个非常具体的现象和解决方向。5.1session not created报错先砍版本别改代码错误信息里已经把“支持版本”写得非常明白比如This version of ChromeDriver only supports Chrome version 130 Current browser version is 128.0.xxxx这说明驱动和浏览器版本不一致。解决方向不是去加options.add_argument也不是去降级 Selenium而是老老实实让驱动版本贴近浏览器版本。优先用第四节的脚本做一次对齐安装。5.2chromedriver找不到或者 Permission denied路径和可执行位Selenium 报错常见这两句chromedriver executable needs to be in PATH或者PermissionError: [Errno 13] Permission denied: chromedriver前者说明你只给 Selenium 传了文件名没传完整路径。最稳妥的写法是Service(/usr/local/bin/chromedriver)不要依赖 PATH 自动查找。后者说明驱动文件没有可执行权限。用install -m 0755安装即可或者手动sudo chmod x /usr/local/bin/chromedriver有一点容易被忽略如果你从 zip 里解压出来的驱动是在 Windows 或 Mac 上直接拖到 Linux 里的二进制格式是错的chmod 也没用。必须重新在 Linux 环境下下载 linux64 版本。5.3 snap 沙箱导致的启动失败该加的参数还是得加用 snap 版 Chromium 跑 WebDriver 时偶尔会遇到DevToolsActivePort file doesnt exist这种报错常见于容器环境、CI 环境、或者 snap 严格沙箱下权限不足。可以在启动参数里加上options.add_argument(--remote-debugging-port9222) options.add_argument(--disable-dev-shm-usage)如果还是起不来再加--no-sandbox。但是我要多嘴一句--no-sandbox会降低浏览器进程的隔离保护只建议在受控的测试环境里使用别拿到生产环境里图省事。5.4 更新后的再次崩盘把版本“钉”住Chromium snap 默认是自动更新的。你今天调好的版本可能过几天浏览器自动升上去了而手动装的 chromedriver 还停在旧版本于是又报session not created。如果测试环境的稳定性比版本新鲜更重要可以把 Chromium 快照钉住不让它随便更新sudo snap refresh --hold chromium想恢复自动更新时sudo snap refresh --unhold chromium我的习惯是每周固定一个时间手动snap refresh chromium然后重跑一次本机版本对齐脚本。这样既不会长期落后也不会在项目进行到一半时突然“被升级”。最后再分享一个经验别把“能打开一个网页”当作最终验收标准。版本对齐之后最好把项目里涉及截图、文件下载、登录态、弹窗处理这类核心用例全部过一遍因为这些场景对 CDP 协议的依赖更深最容易暴露版本差异。排过几次错之后你会发现Ubuntu 上配置 chromedriver 其实不复杂真正复杂的只是你的 Chromium 到底来自哪条渠道以及你愿不愿意先花两分钟去确认版本号。