所需数据在浏览器渲染或交互后才出现时,使用 Selenium 采集。关键是等待让数据可用的状态,而非假定页面加载事件或固定延迟意味着可以提取。
此 Python 示例打开虚构的本地商品目录,等待首批数据,点击 Load more,等待下一批并保存三个商品,将浏览器交互与后续记录校验分开。
流程概览
1. 准备浏览器与本地示例
在 Python 环境中安装 Selenium:
2. 完成 Selenium 采集流程
保存为
selenium_products.py:3. 等待真正完成任务的条件
示例先等待
data-page="1",再等待data-page="2"。这比等待某个商品元素更具体,因为第二批加载前已有商品元素。4. 页面变化后重新定位元素
一些界面点击后会替换整个结果容器,之前定位的元素引用可能失效。示例在第二批完成后重新定位商品,而非保留交互前的引用。
5. 交给下游前校验结果
确认预期字段已填充、需要唯一的标识符没有重复,且记录数量符合采集范围。定期任务还应保留来源与采集时间。
6. 启动会话前添加网络设置
不包含嵌入式鉴权的 HTTP 代理,可以通过 Chrome 选项在浏览器启动前选择:
1. 准备浏览器与本地示例
在 Python 环境中安装 Selenium:
python -m pip install selenium还需要兼容的浏览器与驱动。标准驱动配置可使用 Selenium Manager;受限网络或受管工作站可能需要显式配置驱动。请遵循环境对应的官方浏览器配置文档。
使用 python3 demo_server.py 启动附带服务,打开 http://127.0.0.1:8766/dynamic。服务器返回空商品容器,JavaScript 加入前两条记录,按钮再加载第三条。
示例故意在商品容器暴露 data-page,每批插入后改变其值。此属性属于教程测试页面,并非所有网站的通用功能。
2. 完成 Selenium 采集流程
保存为 selenium_products.py:
import json
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()
try:
driver.get("http://127.0.0.1:8766/dynamic")
wait=WebDriverWait(driver,10)
wait.until(lambda d:d.find_element(By.ID,"products").get_attribute("data-page")=="1")
wait.until(EC.element_to_be_clickable((By.ID,"load"))).click()
wait.until(lambda d:d.find_element(By.ID,"products").get_attribute("data-page")=="2")
rows=[]
for card in driver.find_elements(By.CSS_SELECTOR,"article.product"):
rows.append({"id":card.get_attribute("data-id"),"name":card.find_element(By.TAG_NAME,"h2").text,"price_usd":card.find_element(By.CSS_SELECTOR,".price").text.lstrip("$")})
with open("selenium-products.json","w",encoding="utf-8") as f:json.dump(rows,f,ensure_ascii=False,indent=2)
print(json.dumps(rows,indent=2))
finally:
driver.quit()在文件目录执行 python selenium_products.py。脚本写入 selenium-products.json,并通过 finally 关闭浏览器,即使提取因异常中断也会清理。
输出含 Travel Mug、Desk Lamp 和 Notebook 三条虚构记录。前两条在初次渲染后出现,第三条在 Load more 完成后出现。

3. 等待真正完成任务的条件
条件 | 能够确认 | 不能确认 |
|---|---|---|
元素存在 | 存在匹配节点 | 节点可见、启用或已填充 |
元素可见 | 具有显示状态与尺寸 | 业务操作已完成 |
元素可点击 | 可见且启用 | 遮罩或后续页面变化不会打断点击 |
预期数据或状态出现 | 选定的完成信号满足 | 已采集网站全部记录 |
示例先等待 data-page="1",再等待 data-page="2"。这比等待某个商品元素更具体,因为第二批加载前已有商品元素。
其他网站可选择结果数量改变、已知记录 ID 出现,或加载标记消失且新行出现。根据页面行为选择能够解释的条件。
避免混用隐式和显式等待;Selenium 文档说明这种组合可能产生意外等待时间,参见等待指南。
4. 页面变化后重新定位元素
一些界面点击后会替换整个结果容器,之前定位的元素引用可能失效。示例在第二批完成后重新定位商品,而非保留交互前的引用。
遇到 StaleElementReferenceException 时,检查网站何时更新 DOM,在有意义的状态变化后重新定位。无限重试同一个失效引用不能解决根本的时序问题。
多次加载时,为点击次数或页数设置上限,并记录已见数据。达到规定的完成条件后停止。本测试页面的禁用按钮是一种信号,真实网站可能不同。
5. 交给下游前校验结果
确认预期字段已填充、需要唯一的标识符没有重复,且记录数量符合采集范围。定期任务还应保留来源与采集时间。
可选字段缺失时决定是否保留部分记录;必填字段缺失时报告问题,不要用看似真实的值填补。浏览器提取的文本仍需进行货币、日期和类型检查。
数据已在 HTTP 响应中且不需要交互时,可使用 HTTP 客户端与解析器。Python 采集指南介绍了这种较轻的方式。
6. 启动会话前添加网络设置
不包含嵌入式鉴权的 HTTP 代理,可以通过 Chrome 选项在浏览器启动前选择:
import os
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument("--proxy-server=" + os.environ["MIYA_PROXY_URL"])
driver = webdriver.Chrome(options=options)使用端点提供的实际协议、主机与端口。不要假定此标记能够处理用户名密码鉴权;认证代理的配置取决于浏览器和环境。遵循 MIYAIP 连接指南,单独验证浏览器路由。
分别配置网络路径、等待条件和选择器。目标改变后,确认所需元素与返回数据范围。
常见问题
Selenium 会渲染 JavaScript 吗?
它控制能够执行页面脚本的浏览器。代码仍需要等到结果状态出现后再读取。
每次点击后都应使用 time.sleep() 吗?
应等待与预期页面变化关联的条件。固定延迟可能在一次运行中过慢,在另一次运行中又不够。
无头模式会改变结果吗?
可能影响渲染或网站行为。先用可见浏览器调试,再在任务实际使用的模式下验证相同字段和交互。
应用需要直接控制浏览器时继续使用 Selenium。任务已被 MIYAIP 接口目录支持时,可比较异步 Crawler API 方式。