如何使用 Playwright 抓取无限滚动的产品集合
Scrapeless Agent Browser 运行由 Playwright 驱动的云端会话,而 Scrapeless Residential Proxies 为符合条件的采集任务提供按位置定向的线路。
简而言之
- 集合进度是一组产品身份。 虚拟化网格可以在不增加 DOM 节点数量的情况下替换其卡片。
- 每次滚动操作都需要有可观察到的结果。 观察光标、批次标记或下一个预期项,而不是计算固定的停顿时间。
- 一次抓取需要一个完成原因。 区分显式结束信号、无进展以及配置的工作限制。
- 产品发现和价格收集有单独的合同。 列表卡片可以识别 URL,而详细页面可以确认与特定变体相关的优惠。
识别是什么加载了下一个集合页面
无限滚动的产品集合会在用户到达某个触发点时请求更多商品,该触发点可能是页面边缘、哨兵元素或嵌套容器的底部。 Intersection Observer 规范 描述了页面如何观察目标穿过视口或容器边界。DevTools 可以帮助你识别实际发生滚动的元素,以及在该操作之后是否发起了获取请求。在筛选条件更改后也要进行检查。搜索、排序和库存筛选器各自都可能启动单独的集合。
首先查找允许使用的结构化数据源。商家自有的 feed 或受支持的分页端点可能会直接提供游标、稳定的项目标识符以及结束标志。保留定义集合的任何过滤条件。当用户体验本身是目标时,使用浏览器查看下一批内容如何加载,以及哪些状态告知客户该集合已结束。根据与所有者约定的范围处理从每个界面获取的数据。
表面上看到的页面高度可能会产生误导。虚拟化列表只维护一小批已挂载的卡片,并在用户滚动时重复利用它们。它的高度可能从一开始就被预留。在这种情况下,进度的信号是新观察到的条目 ID 或批次游标,而完成的信号则来自应用程序。本可见行的位置只是一个线索。
先决条件和安装
在 Node.js 环境中使用 Playwright 和 Chromium。将 Playwright 包添加到一个小型项目中,安装其 Chromium 浏览器或使用已配置的 Chromium 可执行文件,并从你可控的店面夹具开始。在实际集成中,检查标记以获取稳定的卡片 ID 和完成信号。示例中的测试 ID 是夹具属性。当你将该函数调整为实际商店时,预计它们会发生变化。
Use Playwright 定位器 以将产品元素限定在该集合内。过于宽泛的链接选择器可能会拾取导航、编辑卡片和推荐轮播。优先使用卡片上的不可变产品 ID 或已验证的 URL 模式。保留原始链接作为证据,并仅在已知规则下规范化 URL 组件。 URL 标准 描述浏览器的 URL 解析和序列化行为。
在每个批次离开 DOM 之前进行收集
在移动滚动位置之前,将当前卡片读取到以稳定 ID 为键的映射中。使用该 ID 存储显示的标题和解析后的产品 URL。当用户向上滚动时卡片重新出现时,映射会为该产品保留一条发现记录。如果多个变体有意作为单独的卡片出现,则使用能够表示期望发现单元的键。
以下示例在一个受控的店面样例上运行,其中包含一个可滚动面板、一个批次标记、两个按顺序挂载的产品卡片以及一个显式结束标记。确认权限和分页行为后,请使用相同的模式并替换为商店特定的选择器。实际的 Agent Browser 会话需要一个 Scrapeless 账户,以及在快速入门中描述的连接设置。
async function collect(page, targetUrl, maxRounds = 12) {
await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });
const grid = page.getByTestId('collection');
const cards = grid.locator('[data-product-id]');
const scroller = page.getByTestId('scroll-pane');
const seen = new Map();
for (let round = 0; round < maxRounds; round += 1) {
await cards.first().waitFor({ state: 'visible' });
const batch = await cards.evaluateAll(nodes => nodes.map(node => ({
id: node.getAttribute('data-product-id'),
title: node.querySelector('a')?.textContent.trim(),
url: node.querySelector('a')?.href
})));
for (const item of batch) {
if (item.id && item.title && item.url) seen.set(item.id, item);
}
if (await page.getByTestId('collection-end').isVisible()) {
return { status: 'complete', items: [...seen.values()] };
}
const batchId = await grid.getAttribute('data-batch');
if (!batchId) throw new Error('Collection batch identifier is missing');
await scroller.hover();
await page.mouse.wheel(0, 240);
try {
await page.waitForFunction(previous => {
const root = document.querySelector('[data-testid="collection"]');
return root?.getAttribute('data-batch') !== previous;
}, batchId, { timeout: 3000 });
} catch (error) {
if (error.name !== 'TimeoutError') throw error;
return { status: 'no_progress', items: [...seen.values()] };
}
}
return { status: 'round_limit', items: [...seen.values()] };
}
在从 DOM 中移除第一张卡片后,fixture 会返回状态为完成的项目 ID A 和 B。示例中的批次标记是 fixture 的实现细节。对于你运营的商店,绑定到相同筛选条件和游标的成功请求,一旦对应的卡片完成渲染,就可以作为有用的进度信号。延迟的变更应导致一个有界的“无进展”结果。该结果会保留可供检查的部分列表。
推进右侧滚动容器
下一个操作必须针对负责加载更多卡片的元素。嵌入在模态框或分类面板中的集合可能会忽略窗口滚动。在示例中,将鼠标悬停在面板上会把滚轮输入作用到正确的区域。使用一种滚动增量,确保在已挂载的多行之间保持重叠,并测量在每次步进之间是否遗漏了 ID。当跳跃幅度过大时,虚拟化网格可能会跳过中间的卡片。
观察加载指示器,并区分“已加载但集合为空”和“从未成功渲染出卡片”的情况。有意设计的空状态可以是一个完整的结果,只是产品数量为零。骨架屏、访问受限挑战、同意对话框或失效的选择器则应生成带解释的结果。在将空结果视为健康状态之前,扩展测试夹具以覆盖这些路径。
加载更多按钮需要不同的操作,但使用相同的进度模型。选择集合中的按钮,点击一次,然后等待新一批内容或结束状态。避免将全局不活动作为完成条件。网格之外的长时间运行请求可以继续处于活动状态,而可见集合可能已经就绪。
跨筛选条件跟踪完整性并存储变更
一次抓取针对其集合配置及其观测窗口完成。存储请求的分类、市场、排序、筛选参数、最终 URL、发现数量、完成原因和采集器版本。如果存在公布的结果数量,将其单独记录用于对比。店面在任务运行期间可能发生变化,因此不匹配既可能反映目录波动或重复展示,也可能是采集器缺陷。
保持发现与报价抽取相互独立。一个集合卡片可以代表一个产品系列,并展示一个起始价格。将稳定的发现 ID 和链接传递给单独的详情页工作器,以解析卖家、变体、价格和库存。 无限滚动抓取操作演练 涵盖了更多分页模式,而当发现的产品集合取决于市场时, 用于区域比较的价格监控解决方案 也很相关。
使用一个具有已知预期标识的小型集合测试分页。添加一个固定装置,使挂载节点数量在各批次之间保持不变。然后测试缺失的结束标记和停滞的批次。将返回的状态和条目 ID 与基准数据进行比较。如果同一个适配器同时覆盖一个分类及其搜索结果,则添加特定筛选条件的测试。
在需要时将浏览器执行迁移到云端
Playwright 采集器可以在本地浏览器或在 Scrapeless Agent Browser中运行。 Agent Browser Playwright 快速入门 展示了远程会话所支持的连接设置。使用 适用于动态网站的 Agent Browser 解决方案 在每个集合需要渲染控件和一系列输入事件时规划容量。将抓取状态及其最后接受的批次保留在你的应用中。
在需要地理位置以进行授权观察时使用 Residential Proxies ,并验证店面实际呈现的市场。固定区域并不指定集合的排序或筛选条件。将这些设置单独存储,当 Cookie 会影响目录时,保持每次市场运行相互隔离。在同一样本中测量完成和部分完成的任务后,根据 Scrapeless 定价 估算云浏览器时间和代理流量。
报告抓取实际看到的内容
使用显式进度标记并保留稳定的条目映射。将完成原因与发现的 URL 并存,以便下游任务区分完整集合和部分结果。从一个已知的分类开始,只有在基准覆盖虚拟化、空集合和停滞加载器之后再添加新来源。
准备好捕获动态产品集合了吗?
在托管浏览器会话中运行有界的 Playwright 集合。
立即注册即可获得 $5 in free credit — 无需信用卡.
领取你的 $5 额度 →常见问题
你如何知道一次无限滚动抓取什么时候结束?
显式的结束标记或已验证的终端游标支持完整结果。轮次上限或没有新批次属于部分结果,除非商店约定将该行为视为完成。
为什么卡片数量保持不变而新产品却不断出现?
虚拟化列表可以回收现有元素,并在相同数量的节点中渲染不同窗口的产品。从每个观测到的批次中收集稳定标识。
Playwright 集合是否需要代理或 AI agent?
Playwright 直接运行集合逻辑。在需要时使用代理进行获授权的特定市场路由,并在接受结果之前验证店面市场。
你应该如何处理访问被拒或集合限制?
在页面被拒时停止任务并记录其状态。与源站所有者确认允许的范围和速率限制,并在需要时与法律顾问一起审阅适用条款和法律。
当商店重新设计商品网格时应该做出哪些调整?
根据新布局的基准更新适配器的稳定标识选择器、限定容器和完成信号。将并发保持在所有者约定的限制内,并逐步扩容。
产品链接可以跨筛选条件去重吗?
稳定 ID 可以为同一商店和市场对发现行进行去重。如果分类位置或搜索排名重要,则保留独立的筛选成员记录。