
1. 项目概述与核心挑战最近几年身边用MacBook M1/M2/M3系列的朋友越来越多大家从开发到自动化测试都开始往苹果的ARM架构生态迁移。我自己也是从Intel Mac换到M1 Pro在搭建Python自动化测试环境特别是SeleniumChromeDriver这套经典组合时确实踩了不少坑。最典型的问题就是当你兴冲冲地pip install selenium然后去下载ChromeDriver时会发现官网默认提供的版本在M1芯片上要么根本装不上要么跑起来各种诡异报错比如“zsh: bad CPU type in executable”或者直接闪退。这背后的核心原因就是ARM架构aarch64与传统的x86_64架构不兼容。这篇内容就是把我从零开始在M1 Mac上成功部署并稳定运行Selenium自动化环境的完整过程、原理和避坑经验梳理出来目标是让你看完就能在自己的机器上复现无论是写爬虫还是做Web UI自动化测试都能顺畅跑起来。2. 环境准备与核心组件选型解析在M1/M2/M3的Mac上搞自动化和之前在Intel Mac上“无脑下一步”完全不同你得先理解整个技术栈的架构依赖关系。这套环境的核心就三个Python解释器、Selenium库、浏览器及其驱动。在ARM架构下这三者必须保持架构一致任何一环“掉链子”都会导致失败。2.1 Python环境原生ARM版是基石很多人环境出问题第一步就错了——用了基于Rosetta 2转译的Python。虽然通过Rosetta 2安装的x86版Python也能运行但效率和兼容性会打折扣尤其是在调用本地二进制依赖比如ChromeDriver时容易引发难以排查的问题。我的选择与理由我强烈推荐直接使用原生支持ARM架构的Python发行版。有以下几种可靠路径Homebrew首选这是macOS上最强大的包管理器。安装原生ARM版Python非常简单# 首先确保你的Homebrew本身是ARM原生版本 # 打开终端输入以下命令检查 which brew # 输出应该是 /opt/homebrew/bin/brew ARM版 # 如果是 /usr/local/bin/brew则需要重新安装ARM版Homebrew # 安装Python 3默认会安装最新的稳定版且是ARM原生版本 brew install python安装后python3和pip3命令会直接指向这个原生版本。用python3 --version和arch命令可以双重验证python3 --version # 例如Python 3.11.4 arch -arm64 python3 -c import platform; print(platform.machine()) # 应该输出 arm64官方Python.org安装包从Python官网下载macOS安装包时现在提供的都是“Universal2”安装包同时包含ARM64和x86_64架构安装时会自动适配你的芯片。这也是一个非常稳妥的选择。Miniconda/AnacondaConda也提供了ARM64原生版本。但请注意有些历史教程会让你创建基于x86的虚拟环境这在M1上会绕弯路。创建环境时务必指定原生架构# 创建名为“selenium_arm”的虚拟环境并明确使用ARM原生版本的Python conda create -n selenium_arm python3.9 conda activate selenium_arm注意无论用哪种方式安装后务必在终端用arch命令或在Python中用platform.machine()验证确保你正在使用的Python解释器是arm64架构。这是后续所有步骤能顺利进行的根本。2.2 浏览器选择Chrome for Apple Silicon浏览器也必须使用ARM原生版本。幸运的是主流浏览器如Google Chrome和Microsoft Edge都提供了Apple Silicon原生版本。Google Chrome直接前往Google Chrome官网下载安装程序会自动识别你的Mac芯片并下载对应的ARM64版本。你可以在Chrome中通过地址栏输入chrome://version/来查看在“用户代理”字符串中如果包含“ARM64”即表示正确。Microsoft Edge同样从官网下载选择Apple Silicon版本。为什么不能用基于Rosetta的浏览器理论上可以但当你用原生ARM的Python和Selenium去控制一个转译运行的x86浏览器时进程间通信和驱动调用可能会遇到意想不到的兼容性问题导致自动化脚本不稳定。为了减少变量一律使用原生版本是最佳实践。2.3 Selenium库纯Python库架构无忧Selenium的Python客户端库selenium本身是纯Python代码没有平台相关的二进制依赖因此通过pip安装时无需担心架构问题。无论你的Python是ARM还是x86版pip install selenium都能正确安装。它的作用是提供一套API让你的Python代码能够与浏览器驱动如ChromeDriver进行通信。3. 核心难点ChromeDriver的ARM架构适配实战这是整个部署过程中最关键、最容易出错的一步。Selenium本身不控制浏览器它需要通过一个名为“WebDriver”的标准化协议与浏览器对话。ChromeDriver就是这个协议针对Chrome浏览器的具体实现它是一个独立的、需要单独下载的可执行文件。3.1 为什么官网下载的ChromeDriver在M1上不能用如果你习惯性地访问ChromeDriver的官方下载页面通常是 storage.googleapis.com 或 chromedriver.chromium.org你会发现下载列表里通常只明确标注了“mac64”版本。这个“mac64”在Intel时代指的就是x86_64架构。对于M1芯片你需要的是“mac64_arm64”或“mac_arm64”版本。直接下载“mac64”版本你运行时会得到“Bad CPU type”错误。3.2 正确获取ARM版ChromeDriver的三种方法方法一使用浏览器内置命令最推荐自动匹配这是最优雅、最不容易出错的方法。新版本的Chrome浏览器大约从Chrome 115开始集成了一个实用命令。首先确保你的Chrome是Apple Silicon原生版本并且版本号在115以上在Chrome地址栏输入chrome://version/查看。打开终端运行以下命令/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version这会输出类似“Google Chrome 121.0.6167.139”的信息记下主版本号“121”。访问一个特殊的URL来触发下载。在终端运行google-chrome --disable-gpu --disable-software-rasterizer --disable-dev-shm-usage --headlessnew --no-sandbox --dump-dom https://googlechromelabs.github.io/chrome-for-testing/这个命令会以Headless模式启动Chrome并获取一个包含最新驱动信息的JSON文件。但更简单的方法是直接根据你的Chrome主版本号构造下载链接。 已知的下载模式是https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/[版本号]/mac-arm64/chromedriver-mac-arm64.zip例如对于版本121.0.6167.139你可以尝试访问https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/121.0.6167.139/mac-arm64/chromedriver-mac-arm64.zip如果这个链接失效最稳妥的办法是访问https://googlechromelabs.github.io/chrome-for-testing/这个官方页面查看“Known Good Versions”列表找到对应你Chrome主版本号的稳定版然后下载对应的“mac-arm64”驱动包。方法二使用第三方管理工具如webdriver-manager对于Python项目可以使用webdriver-manager库它能自动检测浏览器版本并下载匹配的驱动。安装库pip install webdriver-manager在你的Selenium脚本中这样使用from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager # ChromeDriverManager会自动下载并返回ARM版驱动的路径 service Service(ChromeDriverManager().install()) driver webdriver.Chrome(serviceservice)这个库会读取你本地Chrome的版本然后从它的镜像服务器下载正确的ARM64版本驱动非常方便。但需要注意网络环境因为需要从GitHub等地址下载。方法三手动下载并配置如果上述自动方法都失败了例如网络问题可以手动操作。确定你的Chrome主版本号如121。访问https://googlechromelabs.github.io/chrome-for-testing/找到“Known Good Versions”里对应你主版本号的那一行。在那一行的“Assets”里找到名为chromedriver-mac-arm64.zip的文件并下载。解压ZIP文件你会得到一个名为chromedriver的Unix可执行文件。将这个文件移动到系统PATH包含的目录并赋予执行权限。我通常放在/usr/local/bin/针对ARM Homebrew# 解压后进入解压目录 mv chromedriver /usr/local/bin/ # 赋予执行权限 chmod x /usr/local/bin/chromedriver验证在终端输入chromedriver --version应该能输出版本信息并且用file $(which chromedriver)命令查看应该显示包含“ARM64”字样。3.3 驱动路径配置与Service对象的使用在Selenium 4及以上版本中官方推荐使用Service对象来明确指定驱动路径这比旧版的executable_path参数更清晰也能避免一些环境变量问题。from selenium import webdriver from selenium.webdriver.chrome.service import Service # 指定ChromeDriver的绝对路径 chrome_driver_path /usr/local/bin/chromedriver service Service(executable_pathchrome_driver_path) # 创建浏览器选项可选用于添加一些配置 options webdriver.ChromeOptions() # 例如添加无头模式参数 # options.add_argument(--headlessnew) # 传入service和options创建驱动实例 driver webdriver.Chrome(serviceservice, optionsoptions)这样做的好处是即使你的chromedriver不在系统PATH里或者系统里有多个版本你也能精确控制使用哪一个。4. 完整安装与验证流程实录下面我以一个全新的M1/M2 Mac环境为例展示从零开始的完整命令行操作流程。假设你使用Homebrew作为包管理器。4.1 第一步检查与安装ARM原生Python打开终端Terminal依次执行# 1. 检查Homebrew架构确保是ARM版 which brew # 输出应为 /opt/homebrew/bin/brew # 2. 安装或更新PythonHomebrew会自动安装ARM原生最新版 brew install python # 3. 验证Python架构 arch -arm64 python3 -c import platform; print(Python架构:, platform.machine()) # 应该输出Python架构: arm64 # 4. 升级pip到最新版 python3 -m pip install --upgrade pip4.2 第二步安装Selenium库# 使用pip3安装selenium库 pip3 install selenium # 可选但推荐同时安装webdriver-manager方便后续管理驱动 pip3 install webdriver-manager4.3 第三步安装ARM原生Chrome浏览器如果你还没有安装Chrome直接访问https://www.google.com/chrome/下载。安装过程是图形化的下载的安装包会自动适配Apple Silicon。安装后在终端验证# 检查Chrome是否安装以及版本 /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version # 输出类似Google Chrome 121.0.6167.1394.4 第四步获取并配置ARM版ChromeDriver这里演示使用webdriver-manager的自动方法因为它最省心。首先创建一个测试脚本test_selenium_arm.pyfrom selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager import time def main(): print(正在自动检测Chrome版本并下载匹配的ARM版ChromeDriver...) # ChromeDriverManager().install() 会完成下载、解压、返回路径 driver_path ChromeDriverManager().install() print(f驱动已下载至: {driver_path}) # 使用Service对象 service Service(driver_path) # 创建浏览器选项可以添加一些常用参数 options webdriver.ChromeOptions() options.add_argument(--no-sandbox) # 在部分环境下可能需要 options.add_argument(--disable-dev-shm-usage) # 解决共享内存问题 # 如果想以无头模式运行不打开浏览器界面取消下面这行的注释 # options.add_argument(--headlessnew) print(正在启动Chrome浏览器...) driver webdriver.Chrome(serviceservice, optionsoptions) try: # 访问一个测试页面 test_url https://www.google.com print(f访问: {test_url}) driver.get(test_url) # 获取页面标题验证是否成功加载 page_title driver.title print(f页面标题: {page_title}) # 等待几秒方便观察 time.sleep(3) print(测试成功Selenium与ARM版ChromeDriver工作正常。) except Exception as e: print(f测试过程中发生错误: {e}) finally: # 关闭浏览器 driver.quit() print(浏览器已关闭。) if __name__ __main__: main()在终端运行这个脚本python3 test_selenium_arm.py如果一切顺利你会看到终端打印出驱动下载路径然后Chrome浏览器或无头模式会自动启动访问Google首页并在控制台输出成功信息。这个过程首次运行会稍慢因为需要下载驱动。4.5 第五步验证架构一致性终极检查为了彻底放心我们可以写一个小脚本来验证整个链条的架构都是ARM64。import subprocess import platform from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager print( 架构一致性验证 ) # 1. 验证Python架构 print(f1. Python 架构: {platform.machine()}) # 2. 验证Chrome浏览器架构 try: chrome_info subprocess.check_output([/Applications/Google Chrome.app/Contents/MacOS/Google Chrome, --version], textTrue) print(f2. Chrome 版本信息: {chrome_info.strip()}) # 通过活动监视器或更复杂的方法可以精确检查进程架构这里通常原生安装就是ARM版 except FileNotFoundError: print(2. Chrome 未找到或路径不正确。) # 3. 验证ChromeDriver架构 driver_path ChromeDriverManager().install() # 使用 file 命令检查二进制文件架构 result subprocess.check_output([file, driver_path], textTrue) print(f3. ChromeDriver 文件信息: {result}) if arm64 in result.lower() or arm64 in platform.machine().lower(): print(\n✅ 恭喜所有核心组件均为ARM64架构环境配置正确。) else: print(\n⚠️ 警告检测到可能不兼容的架构请检查上述输出。)5. 高级配置、常见问题与排查技巧即使按照上述步骤在实际项目中你可能还会遇到一些特定问题。下面是我总结的几个高频问题和解决方案。5.1 ChromeOptions常用参数配置针对ARM Mac和自动化测试的稳定性以下Options参数非常有用from selenium import webdriver from selenium.webdriver.chrome.options import Options chrome_options Options() # 基础稳定性参数 chrome_options.add_argument(--no-sandbox) # 绕过OS安全模型在Docker或无头环境中常用 chrome_options.add_argument(--disable-dev-shm-usage) # 使用/tmp而非/dev/shm避免内存不足问题 chrome_options.add_argument(--disable-gpu) # 早期无头模式需要现在有时仍可解决渲染问题 # 无头模式不显示浏览器窗口 chrome_options.add_argument(--headlessnew) # Selenium 4.8推荐使用new headless模式 # 忽略证书错误用于测试环境 chrome_options.add_argument(--ignore-certificate-errors) # 禁用浏览器通知、自动化控制提示 chrome_options.add_experimental_option(excludeSwitches, [enable-automation]) chrome_options.add_experimental_option(useAutomationExtension, False) # 设置用户代理可选 chrome_options.add_argument(user-agentMozilla/5.0 (Macintosh; ARM Mac OS X) AppleWebKit/537.36) # 设置初始窗口大小 chrome_options.add_argument(--window-size1920,1080) # 对于下载文件等需要设置首选项的情况 prefs { download.default_directory: /path/to/download/folder, download.prompt_for_download: False, plugins.always_open_pdf_externally: True } chrome_options.add_experimental_option(prefs, prefs)5.2 典型错误与解决方案速查表错误信息/现象可能原因解决方案zsh: bad CPU type in executable或Cannot execute binary file运行的chromedriver是x86_64版本与ARM架构不兼容。确保下载的是mac_arm64或mac64_arm64版本的ChromeDriver。使用本文3.2节的方法重新获取。session not created: This version of ChromeDriver only supports Chrome version XXChrome浏览器版本与ChromeDriver版本不匹配。1. 检查Chrome版本 (chrome://version)。2. 下载与该主版本号完全匹配的ChromeDriver。3. 使用webdriver-manager自动管理。unknown error: cannot find Chrome binarySelenium找不到Chrome浏览器的安装位置。1. 确保Chrome已安装。2. 通过ChromeOptions.binary_location指定绝对路径options.binary_location /Applications/Google Chrome.app/Contents/MacOS/Google Chrome浏览器闪退或自动化脚本运行不稳定可能是内存问题、驱动通信超时或存在多个浏览器实例冲突。1. 添加--disable-dev-shm-usage参数。2. 增加隐式等待或显式等待时间。3. 确保脚本结束时调用了driver.quit()来彻底关闭浏览器和驱动进程。4. 检查是否有其他Chrome进程在运行尝试先关闭它们。在无头模式下截图或渲染异常新的Headless模式 (--headlessnew) 可能仍有特定页面的兼容性问题。1. 尝试切换回旧的无头模式--headless(不推荐已废弃)。2. 或者暂时不使用无头模式进行调试。3. 确保已添加--disable-gpu参数对新Headless模式可能无效但可尝试。WebDriverException: Message: unknown error: cannot determine loading status页面加载状态判断出错常见于单页应用(SPA)或动态加载页面。不要依赖driver.page_source判断改用显式等待某个特定元素出现WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, \someId\)))使用webdriver-manager时下载速度慢或失败网络连接问题默认源可能访问不畅。1. 设置国内镜像源如果可用export WDM_SSL_VERIFY0(不推荐安全风险) 或寻找其他方法。2. 手动下载驱动并指定路径绕过自动下载。5.3 性能优化与最佳实践使用Driver Manager在生产环境或持续集成(CI)环境中强烈推荐使用webdriver-manager或类似的版本管理工具避免手动管理驱动版本带来的维护成本。显式等待优于隐式等待始终使用WebDriverWait配合expected_conditions进行显式等待这比全局的隐式等待更精确、更可靠。from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC element WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, myDynamicElement)) )资源清理务必在try...except...finally块中或在脚本最后调用driver.quit()而不是driver.close()。quit()会关闭所有窗口并终止WebDriver进程释放系统资源close()只关闭当前标签页。隔离环境为不同的自动化项目创建独立的Python虚拟环境如venv或conda env这样可以隔离依赖避免版本冲突。日志记录在复杂脚本中启用Selenium的日志记录功能有助于调试。from selenium.webdriver.chrome.service import Service service Service(executable_pathdriver_path, service_args[--verbose, --log-path./chromedriver.log])5.4 关于其他浏览器Edge, Firefox的说明Microsoft EdgeEdge浏览器也基于Chromium其驱动叫msedgedriver。适配逻辑与Chrome完全一样确保使用ARM原生版Edge然后下载对应的mac64_arm64版本msedgedriver。webdriver-manager也支持Edgefrom webdriver_manager.microsoft import EdgeDriverManager。Firefox (GeckoDriver)Firefox同样提供了Apple Silicon原生版本。你需要下载ARM64版本的Firefox和对应的geckodriver。在webdriver-manager中可以使用GeckoDriverManager。注意Firefox的配置选项与Chrome不同。6. 集成到自动化项目与持续集成(CI)考量当你把本地环境调通后下一步可能就是将其集成到自动化测试框架如pytest或部署到CI/CD服务器如Jenkins、GitHub Actions上。6.1 在GitHub Actions的macOS Runner上运行GitHub Actions提供了macos-latest运行器它现在默认就是Apple Silicon芯片M1。你的工作流配置文件.github/workflows/test.yml需要确保环境配置正确。name: Selenium UI Tests on macOS ARM on: [push] jobs: test: runs-on: macos-latest # 使用ARM架构的macOS运行器 steps: - uses: actions/checkoutv3 - name: Set up Python uses: actions/setup-pythonv4 with: python-version: 3.11 # 指定Python版本 - name: Install system dependencies (if needed) run: | brew update # 例如安装Chrome brew install --cask google-chrome - name: Install Python dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt # 你的依赖文件应包含selenium, webdriver-manager, pytest等 - name: Run UI Tests with Selenium run: | python -m pytest your_test_directory/ --headless # 假设你的测试脚本支持无头模式参数 env: # 如果测试需要无头模式确保你的ChromeOptions包含了--headlessnew # 并且可能还需要--no-sandbox和--disable-dev-shm-usage关键点在CI中你必须使用无头模式 (--headlessnew)并且很可能需要添加--no-sandbox和--disable-dev-shm-usage参数因为CI环境通常没有图形界面且资源受限。6.2 使用Docker进行跨平台测试进阶如果你需要在不同架构如ARM Mac本地开发x86 Linux服务器运行上保持环境一致可以考虑使用Docker。Selenium官方提供了包含浏览器和驱动的Docker镜像selenium/standalone-chrome。你需要寻找支持ARM64架构的标签版本。你可以编写一个Dockerfile来构建你的测试环境或者使用docker-compose来编排Selenium Grid。这样无论你的宿主机是什么架构测试都在一个确定性的容器环境中运行。不过这涉及到Docker和容器化知识是另一个话题了。经过以上从原理到实践从安装到排查的完整梳理你应该能够在M1/M2/M3 Mac上建立起一个稳定、高效的Selenium自动化测试环境。核心就是记住“架构一致”原则Python、浏览器、驱动三者都必须是ARM64原生版本。只要抓住了这个关键剩下的问题大多都有成熟的解决方案。