如何在Puppeteer中定位Poshmark的分页‘下一页’按钮?
问题:Poshmark爬虫分页按钮定位及函数调用故障
- 开发爬取Poshmark男装夹克页面卖家用户名的程序,目标遍历所有页面提取数据,但所有分页按钮HTML类名完全一致,无法区分「下一页」按钮
- 普通Chrome浏览器中页面为无限滚动模式,因此编写了
scrollToBottom异步函数,但Puppeteer启动的Chrome显示分页按钮,导致无限滚动逻辑失效 gotoNextPage函数无法正确找到并点击目标按钮initItemArea函数未被有效调用,相关逻辑已硬编码到main函数中
目标页面:https://poshmark.com/category/Men-Jackets_&_Coats?sort_by=like_count&all_size=true&my_size=false
相关代码:
const e = require('express'); const puppeteer = require('puppeteer'); const url = "https://poshmark.com/category/Men-Jackets_&_Coats?sort_by=like_count&all_size=true&my_size=false"; let usernames = []; const initItemArea = async (page) => { const itemArea = await page.evaluate(() => { return Array.from(document.querySelectorAll('.tc--g.m--l--1.ellipses')).map(x => x.textContent); }); } const pushToArray = async (itemArea, page) => { itemArea.forEach(function (element) { //console.log('username: ', $(element).text()); usernames.push(element); }); }; const scrollToBottom = async (itemArea, page) => { while (true) { previousHeight = await page.evaluate('document.body.scrollHeight'); await page.evaluate('window.scrollTo(0, document.body.scrollHeight)'); await page.waitForFunction(`document.body.scrollHeight > ${previousHeight}`); await new Promise((resolve) => setTimeout(resolve, 1000)); await page.screenshot({path : "ss.png"}) } }; const gotoNextPage = async (page) => { await page.waitForSelector(".button.btn.btn--pagination"); const nextButton = await page.evaluate((page) => { document.querySelector(".button.btn.btn--pagination") }); await page.click(nextButton); console.log('Next Page Loading') }; async function main() { const client = await puppeteer.launch({ headless: false, executablePath: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" }); const page = await client.newPage(); await page.goto(url); await page.waitForSelector(".tc--g.m--l--1.ellipses"); const itemArea = await page.evaluate(() => { return Array.from(document.querySelectorAll('.tc--g.m--l--1.ellipses')).map(x => x.textContent); }); gotoNextPage(page) }; main();
解决方案
1. 正确定位「下一页」按钮
分页按钮类名相同,但可通过文本内容或aria-label属性区分「下一页」。Poshmark的下一页按钮包含「Next」文本,可使用精准选择器:
const gotoNextPage = async (page) => { try { // 等待下一页按钮出现,超时5秒避免无后续页面时卡住 const nextButton = await page.waitForSelector('.button.btn.btn--pagination:has-text("Next")', { timeout: 5000 }); await nextButton.click(); // 等待页面加载完成,以商品元素出现为标志 await page.waitForSelector(".tc--g.m--l--1.ellipses"); console.log('已跳转到下一页'); return true; // 返回true表示跳转成功 } catch (err) { console.log('已无更多页面'); return false; // 返回false表示无后续页面 } };
注意:page.evaluate无法直接返回DOM元素到Puppeteer上下文,直接通过Puppeteer的选择器API操作即可。
2. 修复函数调用与逻辑整合
- 改造
initItemArea使其返回提取的用户名数组,简化pushToArray为同步数组操作:
const initItemArea = async (page) => { return await page.evaluate(() => { // 去除用户名前后空格,避免无效数据 return Array.from(document.querySelectorAll('.tc--g.m--l--1.ellipses')).map(x => x.textContent.trim()); }); }; const pushToArray = (itemArea) => { // 用扩展运算符批量添加,提升效率 usernames.push(...itemArea); };
- 在
main函数中循环调用分页与提取逻辑,处理异步操作(必须加await):
async function main() { // 修正变量名:client改为browser更符合Puppeteer惯例 const browser = await puppeteer.launch({ headless: false, executablePath: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" }); const page = await browser.newPage(); // 等待网络空闲,确保页面完全加载 await page.goto(url, { waitUntil: 'networkidle2' }); let hasNextPage = true; while (hasNextPage) { // 提取当前页用户名 const itemArea = await initItemArea(page); pushToArray(itemArea); console.log(`当前页提取${itemArea.length}个用户名,累计${usernames.length}个`); // 尝试跳转到下一页 hasNextPage = await gotoNextPage(page); } // 输出结果或保存到文件 console.log('所有用户名提取完成:', usernames); await browser.close(); }; main();
3. 其他优化
- 删除无用的
express依赖,代码未用到该包 - 移除无效的
scrollToBottom函数,适配Puppeteer的分页模式 - 添加错误捕获,避免单个页面加载失败导致程序崩溃
内容的提问来源于stack exchange,提问作者jjfish fishman
相关产品推荐
相关产品推荐

