使用Puppeteer分页遍历获取全量商品链接时return返回异常如何解决
问题原因拆解
- 为什么
return links会让循环停止?return语句的作用是结束当前函数的执行并返回结果,你把它写在循环内部,第一次循环走到return的时候,整个getLinks函数就直接结束了,循环自然不会继续执行,只会返回第一次拿到的链接。 - 为什么会报
getLinks is not iterable?getLinks是async异步函数,这类函数的返回值默认是一个Promise对象,不是数组。你如果直接对getLinks()的返回值做遍历(比如用for...of),Promise对象本身不支持遍历,就会报这个错。必须用await关键字等待异步执行完成,拿到它返回的数组结果,才能正常遍历。 - 为什么不需要用Promise.all?
你这个场景是串行逐页翻页爬取,一页爬完再爬下一页,不需要同时处理多个并行的异步请求。Promise.all适用的是你同时发起多个异步任务,需要等所有任务都完成的场景,这里用一个数组逐次存结果就足够了。
修正后的完整代码
const puppeteer = require('puppeteer') async function getLinks(){ const browser = await puppeteer.launch({headless: false, defaultViewport: null}); const page = await browser.newPage(); // 新增:空数组用来存所有页面的商品链接 const allLinks = []; const url = "https://example.com/product-category?p=1&nidx" await page.goto(url) // 原国家选择弹窗处理逻辑保留 while(await page.$('.change-country-buttons > button:nth-child(1)')){ await page.waitForTimeout(2000); await page.keyboard.press('ArrowDown'); await page.waitForSelector('.change-country-buttons'); await page.waitForTimeout(2000); await page.click('.change-country-buttons > button:nth-child(1)'); await page.waitForTimeout(2000); } // 新增:先抓取第一页的链接,否则第一页数据会遗漏 const firstPageLinks = await page.$$eval('.item__info > .mtc-link:nth-child(2)', (allAs) => { return allAs.map((a) => a.href) }); allLinks.push(...firstPageLinks); // 把第一页链接塞入总数组 console.log('第一页链接已收集', firstPageLinks) // 原翻页循环逻辑保留 while(await page.$(".pagination .pagination--next")){ await page.waitForTimeout(2000); await page.evaluate(() => { document.querySelector(".pagination .pagination--next").scrollIntoView(); }); await page.waitForTimeout(1000); await page.waitForSelector(".pagination .pagination--next") await page.waitForTimeout(500); await page.click('.pagination .pagination--next') await page.waitForTimeout(1500); // 等待新页面加载完成 // 抓取当前页的链接 const currentPageLinks = await page.$$eval('.item__info > .mtc-link:nth-child(2)', (allAs) => { return allAs.map((a) => a.href) }); // 把当前页链接塞入总数组,不要在这里return allLinks.push(...currentPageLinks); console.log('当前页链接已收集', currentPageLinks) } // 所有页面爬完后关闭浏览器,避免后台残留进程 await browser.close(); // 最后统一返回所有链接的总数组 return allLinks; } // 调用示例:必须用await拿异步结果,否则会报not iterable错误 // await只能在async函数内使用,所以用立即执行异步函数包裹 (async () => { const allProductLinks = await getLinks(); console.log('所有页商品链接汇总:', allProductLinks); // 这里就可以正常遍历所有链接了 for (const link of allProductLinks) { console.log(link); } })()
内容的提问来源于stack exchange,提问作者Maco
相关产品推荐
相关产品推荐

