简介这是selenium 3.141.0的完整离线安装包面向经常因网络不稳定导致在线安装中断、从Python官网获取源码又异常缓慢的Python开发者。资源采用zip压缩格式解压后在任意目录打开命令行并切换至对应位置执行python setup.py install即可完成本地部署省去反复重试的麻烦。压缩包共104个文件大小约905KB其中86个py源码文件构成Selenium库核心另有js、so、txt、pkg-info、cfg、rst等文件分别承担WebDriver辅助脚本、动态库、文档说明、安装元数据与配置指南等作用目录结构清晰便于按需查看。目前已有2130人学习下载适合需要快速搭建自动化测试环境、批量操作网页或研究Selenium源码实现原理的初、中级Python开发者。资源包保留了完整的变更记录、许可文件及包描述安装异常时可对照文件清单排查缺失项也能帮助读者理解各模块之间的依赖关系。1. 拿到 selenium-3.141.0 先别急着装这个版本卡住了多少人的环境如果你接手过三年前的项目大概率见过requirements.txt里锁着selenium3.141.0或者在某个课程作业的压缩包里翻到这个 zip。别急着卸载换新版Selenium 3.141.0 是 3.x 系列的最后一个正式版本之后项目组直接跳到了 4.xAPI 层面动了刀子。现在网上大量存量脚本、企业内网系统、老教材都跑在 3.141.0 上你要是换成 4.xfind_element_by_id这类经典写法直接报错黑匣子一开全是红。这篇笔记就把 3.141.0 的环境搭建、核心 API、定位策略和踩坑记录拆开讲清楚适合三类人接手老代码的维护者、照着旧教材做自动化测试的学生、以及暂时不想折腾新 API 只想让脚本跑起来的开发者。2. 环境搭建从 Python 版本到浏览器驱动的全套匹配方案2.1 先确认 Python 版本别让解释器拖后腿Selenium 3.141.0 发布于 2018 年底它的底层网络库和线程模型是基于当时的 Python 运行时写的。我见过有人在 Python 3.10 上硬装结果import selenium没问题一跑webdriver.Chrome()就抛异常查半天发现是urllib3的兼容性翻车。最稳的组合是 Python 3.6 到 3.8这个区间内 selenium 的依赖解析不会出幺蛾子。如果你机器上只有 3.9也别急着退版本用虚拟环境隔离一下python -m venv selenium_venv source selenium_venv/bin/activate # Windows 下用 selenium_venv\Scripts\activate pip install selenium3.141.0 python -c import selenium; print(selenium.__version__)这里解释一下虚拟环境不是为了赶时髦而是防止你系统里其他项目把urllib3或certifi升级到不兼容版本。pip install selenium3.141.0会拉取当时锁定的依赖版本如果pip抱怨依赖冲突常见做法是加--no-deps参数跳过依赖检查但前提是你确认自己的环境里已有兼容的urllib3。打印版本号那步是必须的很多人装完就信了真跑起来才发现site-packages里是旧残留。2.2 浏览器驱动缺了它脚本连浏览器都拉不起来Selenium 3.x 的架构决定了它不能直接操作浏览器必须通过浏览器厂商提供的驱动Driver来通信。很多初次接触的人以为装了 selenium 库就完事了结果一执行webdriver.Chrome()就报WebDriverException: Message: chromedriver executable needs to be in PATH——这是 3.x 时代最经典的翻车现场没有之一。不同浏览器对应不同驱动它们的版本还必须和浏览器主版本号对齐。Chrome 用的是 chromedriverFirefox 用 geckodriverEdge 用 msedgedriver。下载驱动时记住一个原则驱动的大版本号必须和浏览器一致小版本可以略过。比如 Chrome 120 就找 chromedriver 120.x找不到 120 就找最接近的 119 或 121但别跨大版本。浏览器驱动名称匹配规则Chromechromedriver大版本号一致Firefoxgeckodriver0.30 对应较新版本通常兼容Edgemsedgedriver与 Edge 版本完全一致驱动下载后Windows 上解压到任意目录然后把目录加进PATH环境变量macOS/Linux 下推荐放到/usr/local/bin并加执行权限。还有种更省事的做法直接丢到 Python 解释器同目录下selenium 会在启动时查找当前目录这个技巧在实验室公用电脑上特别管用不用动全局环境变量。2.3 第一个能跑的脚本从启动到退出的完整闭环写第一个脚本时别贪多就做三件事打开一个页面、打印标题、退出。跑通了再往里面加东西。from selenium import webdriver driver webdriver.Chrome() # 启动 Chrome此时会弹出浏览器窗口 driver.get(https://www.example.com) # 阻塞直到页面 load 事件完成 print(driver.title) # 拿到页面标题验证页面真的打开了 driver.quit() # 关闭浏览器并清理进程这段代码背后有三个值得注意的地方get()方法不是等页面元素全部渲染完才返回它等的是浏览器的加载状态变成 complete所以如果页面里有异步请求后续定位元素时必须配合显式等待这个细节在 3.1 节展开driver.quit()和driver.close()完全不同close()只关当前标签页quit()才是彻底关闭浏览器进程脚本结束条件不写quit()你会看到后台一堆残留的 chrome 进程慢慢吃内存driver.title是经典属性写法在 3.x 版本里它不会自动等待如果页面标题是动态渲染的刚打开就取可能是空字符串。3. 核心 API 实战定位策略、显式等待与交互控制3.1 八种定位方式真正常用的就三种Selenium 3.141.0 提供了八种元素定位方法从find_element_by_id到find_element_by_xpath新手容易陷入背 API 的误区。我拆了几十个跑在 3.141.0 上的老脚本发现生产环境里超过八成用的是ID、XPATH和CSS_SELECTOR。ID定位最快但现代前端框架里 ID 往往带随机后缀一刷新就变XPATH最灵活能处理列表项、文本匹配、父子关系代价是性能稍慢、可读性差CSS_SELECTOR在速度和可读性之间取了平衡点前端工程师写样式时留下的class和>from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver webdriver.Chrome() wait WebDriverWait(driver, timeout10, poll_frequency0.5) login_button wait.until(EC.element_to_be_clickable((By.ID, login))) login_button.click()WebDriverWait的构造参数有三个driver是当前的浏览器实例timeout是最大等待时间单位秒超过这个时间条件还不满足就抛TimeoutExceptionpoll_frequency是轮询间隔默认 0.5 秒如果你要定位的元素出现在一个卡顿的页面里可以把间隔调大到 1 秒减少无效的 DOM 查找。element_to_be_clickable是EC模块里的一个条件类它和presence_of_element_located的区别在于后者只检查元素是否存在于 DOM 树中哪怕被遮挡、被禁用也会返回前者还要求元素可见且可用。实战中登录按钮常遇到这两种状态的差异新手容易栽在这里。3.3 交互操作输入、点击和下拉框的坑send_keys是模拟键盘输入的核心方法但它在 3.141.0 上的一个玄学问题是中文输入丢字。尤其在 Linux 环境上send_keys(用户名)偶尔会只输入一个用字或者干脆漏掉后半截。常见做法是先element.clear()清空输入框再逐字输入或者用clipboard方案把文本复制到剪贴板然后send_keys(Keys.CONTROL v)粘贴中文稳定性更高。click()方法看着简单坑在元素被遮住时会抛出ElementClickInterceptedException这类问题我会在第四章集中展开。下拉框处理是个独立的场景原生select标签用 Selenium 自带的Select类最省事但很多人不知道这个机制偏要写find_element_by_xpath(//option[value2]).click()结果发现点击选项后触发不了change事件。from selenium.webdriver.support.ui import Select province_select Select(driver.find_element_by_id(province)) province_select.select_by_value(110000) # 按 value 属性选 province_select.select_by_visible_text(北京市) # 按显示文本选 province_select.select_by_index(2) # 按可选列表的索引选从 0 开始Select类内部会自动处理展开和点击的逻辑不需要手动去点option。三个select_by_*方法的区别很明确select_by_value匹配的是option标签的value属性最稳定select_by_visible_text匹配用户看到的文本适合没有 value 属性的老系统select_by_index完全依赖选项顺序只要前端加了选项位置就会错位能不用就不用。另外这个 Select 类只能处理标准的select标签现在很多 React/Vue 项目用的是自定义下拉组件DOM 结构根本不是select这时候只能退回去写 XPATH 点击没有捷径。4. 避坑指南五个高复现率的故障场景与解法4.1 现象send_keys输入中文掉字只输入了第一个字原因Selenium 3.141.0 的输入事件处理在非拉丁字符集上有兼容问题尤其在 Linux 的 X11 环境下键盘事件的发送频率与输入法状态不稳定。解决放弃直接输入用剪贴板方案。import subprocess from selenium.webdriver.common.keys import Keys def set_clipboard(text): process subprocess.Popen([xclip, -selection, clipboard], stdinsubprocess.PIPE) process.communicate(text.encode(utf-8)) set_clipboard(测试账号) input_el driver.find_element_by_id(username) input_el.click() input_el.send_keys(Keys.CONTROL, v)xclip需要单独安装Windows 上可以用pyperclip库代替。这个方案的本质是绕过 selenium 的键盘事件通道直接操作系统剪贴板再通过快捷键触发粘贴。从那以后我每次处理包含非 ASCII 字符的输入都强制走剪贴板后续没有复发过。4.2 现象click()报WebDriverException: Element is not clickable at point原因目标元素被浮层、固定导航栏或加载动画遮挡selenium 模拟的是真实用户点击但浏览器的点击命中检测发现那个坐标为的顶层元素不是你的目标。解决先滚动到元素可见再用element_to_be_clickable显式等待最后兜底用 JavaScript 点击。from selenium.webdriver.common.action_chains import ActionChains ele driver.find_element_by_xpath(//button[idsubmit]) driver.execute_script(arguments[0].scrollIntoView();, ele) try: ele.click() except WebDriverException: driver.execute_script(arguments[0].click();, ele)scrollIntoView把元素滚动到视口内这一步能解决大部分遮挡问题。JavaScript 点击是最后的后悔药它会绕过可见性检测直接触发点击事件适合那种元素被opacity: 0隐藏但实际可用的场景。4.3 现象SessionNotCreatedException: This version of ChromeDriver only supports Chrome version X原因浏览器自动更新了主版本但 chromedriver 还停留在旧版本。这是本地开发环境最常见的高频事故Chrome 默认开启自动更新你睡一觉起来脚本就全挂。解决锁定浏览器版本关闭自动更新如果锁定不了就写个启动前检查函数比对driver.version和浏览器版本不一致时自动报错并提示去下载对应驱动。from selenium import webdriver driver webdriver.Chrome() actual_version driver.capabilities[browserVersion] driver_version driver.capabilities[chrome][chromedriverVersion].split()[0] print(f浏览器版本: {actual_version}, 驱动版本: {driver_version}) if actual_version.split(.)[0] ! driver_version.split(.)[0]: raise SystemExit(驱动大版本与浏览器不匹配请重新下载驱动)把这段检查写在你所有爬虫或测试脚本的入口处能省下一大堆定位问题的排查时间。4.4 现象显式等待一直超时元素明明已经出现在页面上原因最常见的是元素在 iframe 里selenium 默认只操作顶层文档find_element找不到 iframe 内部的东西只会干等。解决先切换到 iframe 再定位操作完记得切回默认内容。driver.switch_to.frame(main-frame) # 传入 iframe 的 id 或 name # 此时可以正常 find_element 定位 iframe 内的控件 driver.switch_to.default_content() # 切回顶层文档4.5 现象脚本跑到一半浏览器窗口被系统强制关闭原因对于超长任务浏览器进程因内存占用过高被操作系统杀掉。解决在任务循环里定期重启浏览器而不是一直复用同一个实例这是爬虫项目的通用做法。5. 进阶技巧无头模式与页面对象模式的双保险如果你要把这段 3.141.0 的脚本部署到服务器上没有显示器环境就必须启用无头模式headless。3.141.0 支持--headless参数但要注意它和 4.x 的--headlessnew参数在行为上有差异——旧版 headless 模式不渲染部分 CSS 和 JS截图结果和新版不一样。如果只是想跑数据交互差别不大但如果你依赖截图做页面回归对比建议在本地 4.x 上先跑一遍基准图再切到服务器用 3.141.0 执行。from selenium import webdriver from selenium.webdriver.chrome.options import Options options Options() options.add_argument(--headless) options.add_argument(--no-sandbox) options.add_argument(--disable-gpu) options.add_argument(--window-size1920,1080) driver webdriver.Chrome(chrome_optionsoptions) driver.get(https://www.example.com) print(driver.title) driver.quit()四个参数缺一不可--no-sandbox是因为容器环境里用户权限受限去掉会直接启动失败--disable-gpu是为了避免某些 Linux 图形栈的空指针崩溃--window-size非常关键headless 模式默认窗口是 800x600很多响应式页面的元素在窄屏下会被隐藏定位不到。chrome_options这个参数名在 3.141.0 里已经废弃官方推荐用options但老代码里两种写法都能跑不用急着改。页面对象模式Page Object Pattern是让脚本从能用走到好维护的关键一步。思路不复杂把一个页面的所有定位器和操作方法封装成一个类测试用例只关心业务流程不关心 XPath 细节。考虑到 3.141.0 的老项目多半是快速搭的直接上框架成本高我建议只做一步小的重构——把复用超过两次的定位逻辑抽成函数比如把wait.until(EC.element_to_be_clickable(...))封装成def click_btn(driver, locator)。这样即便后面前端改版你只需改一处就行而不是整个脚本里搜索。最后说个真实教训某次凌晨三点跑批量任务脚本在第二个循环就崩了查日志发现是网络抖动导致页面加载了一半显式等待超时。那以后我所有循环任务都在开头加了一个健康检查——先driver.execute_script(return document.readyState)确认页面真的 ready再往下走。希望这篇围绕 3.141.0 的拆解能帮你少踩几个坑让老项目在自动化这条路上继续发光发热。本文还有配套的精品资源点击获取