Pydoll 完整教程:动态页面查询、分页与结果采集
用 Pydoll 3 打开动态列表、点击标签筛选、逐页读取关联字段,保存 CSV 与诊断截图,并用 URL 和内容等待避免重复读取旧页面。
在动态页面里,点击完成、网络空闲和结果更新是三个不同状态。只在每次点击后睡两秒,任务可能在快页面浪费时间,在慢页面读到旧数据。
本文用 Pydoll 3 读取 Quotes to Scrape 的动态列表,选择 life 标签,再处理最多两页结果。每条名言保留作者和来源,输出 CSV;失败时尝试保存当前页面截图,帮助定位卡在哪一步。
准备输入地址
先在浏览器找到下列页面并确认内容,再从地址栏复制完整地址。服务或仓库地址从相应账户设置、官方项目的接入说明或克隆菜单取得。不要从示例输出中反推真实地址。
QUOTES_LIST_URL:Quotes to Scrape JavaScript 列表页地址,路径为 /js/。
在执行后续命令的同一个 Bash/WSL 终端中设置:
export QUOTES_LIST_URL='<paste-the-actual-quotes-list-url>'下文 JSON 或任务参数中的 <变量名> 是待替换标记,提交前填写刚复制的实际值;JSON 不会自动展开环境变量。结果示例中的 example.16yun.cn 只表示来源字段的形状,不是本文部署的演示站。
安装与浏览器准备
使用 Python 3.12,并确保已经安装 Chrome 或 Edge。Pydoll 不为你下载浏览器,也不需要 WebDriver。安装:
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install pydoll-python==3.0.0本文采用 v3 的导入和元素 API。不要把旧版本中同名属性、其他自动化库的等待接口直接混用。基础用法见 Pydoll 官方仓库。
定位与等待先建立明确含义
本例使用 CSS 确定目标:.quote 是重复对象,内部 .text 与 .author 构成一条数据。标签链接的 href 表示目标筛选;点击后先等待 URL 到达目标,再确认列表出现。
这种方法适用于当前站点的完整导航。若另一站点点击后 URL 不变,应等待实际结果标记或列表内容更新,不能继续用 URL 变化判断成功。
完整代码
创建 collect_quotes.py:
import asyncio
import os
import csv
from pathlib import Path
from urllib.parse import urljoin
from pydoll import Chrome
async def main():
out = Path("pydoll-output")
out.mkdir(exist_ok=True)
rows, seen = [], set()
async with Chrome() as browser:
tab = await browser.start()
try:
await tab.go_to(os.environ["QUOTES_LIST_URL"])
link = await tab.query('a.tag[href="/tag/life/page/1/"]', timeout=15)
target = urljoin(await tab.current_url(), link.get_attribute("href"))
await link.click()
await tab.wait_for_url(target, timeout=20)
for page_number in range(1, 3):
await tab.query(".quote", timeout=15)
cards = await tab.query(".quote", find_all=True)
source_url = await tab.current_url()
for card in cards:
text = (await (await card.query(".text")).text()).strip()
author = (await (await card.query(".author")).text()).strip()
if not text or not author:
raise ValueError("名言或作者缺失")
key = (text, author)
if key not in seen:
seen.add(key)
rows.append({
"text": text, "author": author,
"source_url": source_url, "page_number": page_number,
})
if page_number == 2:
break
next_link = await tab.query("li.next a", timeout=2, raise_exc=False)
if next_link is None:
break
next_url = urljoin(source_url, next_link.get_attribute("href"))
if next_url == source_url:
raise ValueError("下一页仍指向当前页")
await next_link.click()
await tab.wait_for_url(next_url, timeout=20)
await tab.take_screenshot(str(out / "last-page.png"), beyond_viewport=True)
except Exception:
try:
await tab.take_screenshot(str(out / "failure.png"), beyond_viewport=True)
except Exception as shot_error:
print("截图未保存:", type(shot_error).__name__)
raise
if not rows:
raise ValueError("没有取得任何目标记录")
with (out / "quotes.csv").open("w", encoding="utf-8-sig", newline="") as stream:
writer = csv.DictWriter(stream, fieldnames=["text", "author", "source_url", "page_number"])
writer.writeheader()
writer.writerows(rows)
print({"unique_quotes": len(rows)})
asyncio.run(main())运行:
python collect_quotes.pyasync with 负责当前程序启动的浏览器生命周期。截图动作与采集失败分开处理,截图失败不会把原来的页面错误改写成成功。
get_attribute 在本文版本中读取元素属性,不加 await;text 是异步方法,需要 await。接口形式相似不代表它们有相同调用方式。
怎样核对 CSV
打开 pydoll-output/quotes.csv,检查来源路径是否为 life 标签分页,并抽查正文与作者是否属于同一个 .quote。不要分别抓全页正文数组和作者数组后按位置拼接。
预期数据结构是“文本、作者、来源、页号”,具体条数由当时页面决定。最多两页并不是两页一定都存在;当没有 next 时正常停止,但仍需核对页面是否确实已经到末页。
去重键是本例的文本与作者组合。它适合这个练习任务,不是通用商品键。迁移商品数据时使用 SKU 或明确业务编号,避免相同展示名称被误合并。
当前脚本只有完全走完主线才写最终 CSV。失败后不要把目录里上一次的 quotes.csv 当成新一轮结果;正式使用时为批次增加独立输出目录,或者在调用方记录运行状态。
如何迁移到自己的动态查询页
先修改进入地址与筛选元素,确认动作确实改变数据;再修改重复对象与内部字段,最后处理分页终止条件。需要输入搜索词时,用该版本元素输入接口填写,并等待与你业务结果相关的标记,而非只调用 network idle。
代理配置只在网络条件确实需要时加入。先用直连建立选择器与字段基线,再检查代理或账号条件的差异,这样错误不会同时来自四个配置来源。
如果列表是虚拟化滚动,DOM 里可能只有当前窗口的少量项。本文按常规分页处理,不适合直接将当前 DOM 数量当作整份无限列表总量。
常见问题与处理
启动提示没有浏览器。 安装系统浏览器或明确配置其可执行路径。反复安装 Python 包不会自动补齐浏览器。
标签找不到。 检查当前 URL、动态列表是否加载,以及该标签链接是否仍存在。若更换筛选词,同步修改 href 与任务预期。
点击后页面仍未更新。 查看目标地址是否变化;URL 不变的应用应增加内容更新判断。不要只延长固定睡眠。
第二页重复第一页。 比较保存的 source_url、next href 与实际正文,检查下一页是否指向当前页。只靠去重把重复行删掉,会隐藏漏页原因。
属性读取报错。 区分同步 get_attribute 与异步 text/query,核对依赖版本,不通过在所有地方增删 await 猜测。
错误截图也失败。 原始异常仍应保留;浏览器已失联或页面被关闭时,不应要求截图一定可得。根据阶段检查启动、导航与元素操作。
CSV 中文或标点异常。 先检查内存文本与文件回读,再检查表格软件导入编码,不把编码问题当成选择器错误。
动态列表的关键是把每次动作与数据更新证据连接起来。浏览器能点按钮之后,还要证明读到的是对应筛选条件和页面的新结果。
需要企业代理方案?
我们可根据目标站点、并发规模与稳定性目标提供定制方案。