作为一名常年跟数据抓取打交道的人,我太清楚那种"信心满满写好代码,结果跑出来一片空白"的感受了。尤其是当你面对一个用现代前端框架(Vue、React)搭建的网站时,用requests能拿到的往往只是一个空壳HTML,真正的数据全是JavaScript在浏览器里动态渲染出来的。这个场景下,Selenium就不再是"可选工具",而是"救命工具"。这篇内容没有教科书式的废话,全是基于实际项目踩坑后的经验总结,围绕JavaScript渲染这个核心痛点,把Selenium从环境搭建到风控对抗的完整链路说透,希望能帮你少走那些我走过的弯路。
1. 为什么requests会扑空:JavaScript渲染页面的数据流变化
先从一个最基础但很多人没想透的问题说起。为什么你用requests请求一个网页,拿到的HTML里明明有<div id="app"></div>这种标签,但里面的内容却空空如也?
因为现代网站的开发模式变了。十年前的服务端渲染,是服务器把数据库里的数据直接拼进HTML字符串再返回给浏览器,所以curl看到一个页面什么样,用户在浏览器里看到的就什么样。现在的前端工程化项目完全不是这个逻辑,服务器返回的HTML通常只是一个"骨架",里面可能只有一个挂载点,剩下的所有列表、商品、用户信息,都要靠浏览器执行JavaScript代码,触发Ajax请求、再通过DOM操作把数据渲染到页面上。
这个过程涉及两个关键角色:
- Ajax异步请求:页面加载完成后,JS代码会向后端接口发起HTTP请求,后端返回的往往是JSON格式的纯数据。
- DOM动态渲染:拿到JSON数据后,JS再把数据一个个塞进页面的各个节点。
所以当requests去请求这个页面时,它只有能力把服务器最初返回的那个"空骨架"拿回来,根本没有执行JS这一步,自然也就拿不到任何有价值的内容。
1.1 Selenium到底解决了什么问题
Selenium做的事情,简单说就是"替你把浏览器跑起来"。它不是直接去抓HTML字符串,而是通过WebDriver协议,驱动一个真实的浏览器实例去加载页面。既然是真实浏览器,那它就会像正常用户一样:解析HTML、执行JavaScript、触发网络请求、渲染DOM。整个过程跑完之后,你再从浏览器实例里提取已经渲染完整的页面。
这个"驱动真实浏览器"的思路,和requests这类纯HTTP库有本质区别。
| 对比项 | requests | Selenium |
|---|---|---|
| 请求载体 | Python代码直接发HTTP请求 | 驱动真实浏览器发请求 |
| JavaScript执行 | 不执行,只拿静态HTML | 完整执行,拿到渲染结果 |
| 数据提取 | 解析HTML或直接调接口 | 可解析DOM,也可拦截网络响应 |
| 反爬识别风险 | 请求头特征容易被识别 | 浏览器指纹相对自然 |
| 效率 | 高,毫秒级 | 低,秒级甚至更慢 |
用Selenium处理JS渲染页面的逻辑在于,你不再和"接口签名、加密参数、请求头顺序"这些细节纠缠,而是直接站在用户视角拿到最终结果。它像是一个笨重但可靠的兜底方案,当requests完全无解的时候,Selenium往往还能打开局面。
1.2 什么时候该用Selenium,什么时候不该用
很重要的一点:Selenium不是万能的,而且它效率很低。如果你面对的是一个接口可以直接返回JSON且没有复杂加密的网站,优先用requests就能解决。非要硬上Selenium,反而会陷入性能瓶颈。
我一般这样判断:
- 页面数据通过JS异步加载,且接口加密逻辑复杂、短时间无法逆向,直接上Selenium。
- 网站有严格的行为检测,纯HTTP请求很快被识别为爬虫,上Selenium配合模拟操作。
- 页面需要交互(点击、滚动、翻页)才能加载出数据,也适合用Selenium。
但反过来,如果目标网站是传统的服务端渲染页面,或者能直接从包管理器里定位到数据接口,直接用requests一把梭,不要给自己找麻烦。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 搭建Selenium环境时最容易被卡的三个环节
真正开始用Selenium之后,你会发现难点根本不在"写代码爬数据",而在环境搭建。这个环节我前前后后踩了不少坑,尤其新手时期,经常在安装和驱动配置上卡一整天。按照下面的流程走,可以最大程度避免折腾。
2.1 安装Selenium库
Python的安装没什么好说的,直接pip搞定:
bash复制pip install selenium
如果你用的是Anaconda,也可以用conda装,不过pip一般就够用了。这里稍微提醒一下,尽量在虚拟环境里装,别把全局环境搞乱了,尤其是你手头同时维护多个爬虫项目时,依赖隔离能省掉很多麻烦。
2.2 浏览器驱动的坑:版本必须严格匹配
这一步是最多人翻车的地方。Selenium本质是通过一个中间层(WebDriver)与浏览器进行通信,Chrome浏览器有ChromeDriver,Firefox有GeckoDriver,Edge有EdgeDriver。如果驱动版本和浏览器版本对不上,启动时会直接报错,常见的错误是SessionNotCreatedException。
关于驱动下载和对应关系,现在有两种方式:
- 手动管理:去Chrome官网查看当前浏览器版本,然后到ChromeDriver镜像站下载对应版本的driver,把可执行文件放到PATH路径下或直接在代码里指定路径。
- Selenium Manager自动管理:Selenium 4.6之后内置了Selenium Manager,只要你本地装了Chrome,它会自动检测浏览器版本并下载匹配的driver,基本不需要手动配置。
如果你还在用Selenium 3.x,我强烈建议升级到4.x,就为了这个自动驱动机制也值得。手动下载driver还有个常见坑:不少人把driver放在项目目录下,然后代码里没加路径,程序找不到文件然后抛异常。最稳妥的做法是用Service对象显式指定路径,或者干脆把driver目录加进系统PATH。
2.3 第一次启动浏览器的错误排查
代码写好了,环境也装好了,结果一跑发现浏览器根本弹不出来,或者一闪而过。这种情况多半是以下几个原因:
- 浏览器没有安装在默认位置,Selenium找不到可执行文件。
- 驱动权限有问题,Linux/macOS下可执行权限未开启。
- Chrome和driver版本严重不匹配。
- 部分系统下还需要安装额外的依赖库(
