使用Puppeteer抓取动态加载内容失败,需处理加载更多按钮
Puppeteer爬动态内容失败+处理「加载更多」按钮的解决办法
问题根源
- 你代码里的
new Promise(r => setTimeout(r, 5000))没加await,等于白等——代码不会暂停,直接往下执行,这时候动态内容还没加载出来,自然抓不到。 - 没处理「Cargar más」按钮的循环点击,只能拿到初始加载的少量内容,分页的文章链接根本没机会获取。
修正后的完整代码
async function getLinksFromBase(category) { const urlBase = 'https://xepelin.com/blog/'; const browser = await puppeteer.launch({ headless: 'new', // 用新版无头模式,兼容性更好 args: ['--no-sandbox', '--disable-setuid-sandbox', '--start-maximized'] }); const page = await browser.newPage(); // 设置桌面端视口,避免网站加载移动端布局 await page.setViewport({ width: 1200, height: 800 }); // 跳转到目标页面,等待网络空闲再继续(确保初始内容加载完) await page.goto(urlBase + category, { waitUntil: 'networkidle2' }); // 循环点击「加载更多」按钮,直到按钮消失 while (true) { try { // 等加载更多按钮出现,超时10秒就退出 const loadMoreBtn = await page.waitForSelector('button:has-text("Cargar más")', { timeout: 10000 }); // 点击按钮(用evaluate避免元素不可交互的问题) await page.evaluate(btn => btn.click(), loadMoreBtn); // 等新文章加载出来:对比当前文章数量,等数量增加再继续 const prevCount = await page.$$eval('.blog-posts .post-item', items => items.length); await page.waitForFunction( count => document.querySelectorAll('.blog-posts .post-item').length > count, {}, prevCount ); } catch (err) { // 按钮找不到或者超时,说明没有更多内容了,退出循环 break; } } // 只抓博客文章的链接,过滤掉无关的a标签 const hrefs = await page.$$eval('.blog-posts .post-item a', anchors => { return anchors.map(anchor => anchor.href).filter(href => href.includes('/blog/')); }); await browser.close(); return hrefs; }
关键修改说明
修复等待逻辑:
- 删掉没用的
setTimeout,改用page.goto的waitUntil: 'networkidle2',等页面网络请求基本结束再继续,比固定等几秒靠谱。 - 如果确实需要额外等待,用
await page.waitForTimeout(3000)(不过这个方法已经被标记为过时,更推荐等特定元素出现)。
- 删掉没用的
处理加载更多按钮:
- 用
while(true)循环,一直检查按钮是否存在,直到按钮消失就停。 - 每次点击后,等新的文章加载出来再继续,避免还没加载完就又点按钮。
- 用
精准抓取目标链接:
- 不再抓所有
a标签,只定位到博客文章容器里的链接,还加了过滤确保只留博客相关的,减少无效数据。
- 不再抓所有
优化无头模式配置:
- 用
headless: 'new',这是Puppeteer新版本推荐的,比旧无头模式更稳定。 - 加了
--start-maximized和setViewport,确保网站加载桌面端布局,避免移动端内容不一样。
- 用
调试小技巧
- 把
headless改成false,打开浏览器窗口看页面加载情况,确认动态内容是不是真的加载出来了。 - 加一行
page.on('console', msg => console.log('页面日志:', msg.text())),看看页面有没有JS报错,有时候报错会导致内容加载失败。 - 点击按钮后可以加个短等待,比如
await page.waitForTimeout(1000),模拟真实用户的操作节奏,避免触发反爬。
内容的提问来源于stack exchange,提问作者Diego Collao Alcayaga
相关产品推荐
相关产品推荐

