在 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 推送到了 126,snap 里的 Chromium 可能还在 125;Chrome 到了 130,snap 可能才跟上 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、不用考虑文件夹层级。但如果你刚装了一个很新的 Chromium,apt 里的旧驱动大概率带不动。
另外提醒一句:如果你还要从其他途径手动装新版 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; d=json.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; d=json.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, timeout=30) 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']}", file=sys.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(service=service, options=options) 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 doesn't exist这种报错常见于容器环境、CI 环境、或者 snap 严格沙箱下权限不足。可以在启动参数里加上:
options.add_argument("--remote-debugging-port=9222") 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 到底来自哪条渠道,以及你愿不愿意先花两分钟去确认版本号。