如何在async函数外部获取Puppeteer爬取的全局链接数组
问题根因
- 你代码里的
links.push逻辑本身可以正常执行、把链接值存入全局数组,问题出在 JavaScript的异步执行时序和Python的同步执行逻辑有本质区别:
你之前写的Python爬虫是阻塞式同步流程,代码从上到下跑完循环,links数组已经填充完毕,后续代码直接读取就能拿到值。但JavaScript中Puppeteer的浏览器启动、页面加载、DOM提取全流程都是异步返回Promise的,不会卡着主线程等结果返回。
对应到你的代码,实际执行顺序是:- 初始化空的全局
links数组 - 调用
main()拿到一个等待状态的Promise,执行.then()时只是把回调函数注册到微任务队列,不会立刻执行回调 - 立刻执行同步的
console.log(links),这时候队列里的回调根本没开始运行,links自然是空数组 - 等后续所有Puppeteer的异步流程跑完,才会轮到执行注册的then回调,完成链接拼接和push操作——这时候你早就打印完空数组了,自然会误以为push没生效。
- 初始化空的全局
- 代码里还有个小隐患:循环中用到的变量
i没有加let/const声明,会被挂载到全局作用域,后续可能触发变量覆盖的意外问题。
修正方案
要实现和Python版本一致的功能——把提取的链接存到全局links数组,直接按照JS的异步规则调整代码执行顺序即可,不需要修改你提取链接的核心逻辑:
- 所有需要读取、使用
links数组的业务逻辑,一定要等Puppeteer的爬取流程完全跑完之后再执行。最贴合你原有逻辑的写法如下:
const puppeteer = require('puppeteer'); // 全局links数组保持定义在函数外部,符合你的要求 let links = []; const baseUrl = 'https://www.blablabla.com'; async function main() { try { const browser = await puppeteer.launch(); const [page] = await browser.pages(); await page.goto(baseUrl); // 从页面提取所有目标a标签的原始href const rawHrefs = await page.evaluate(() => Array.from(document.querySelectorAll('a.o-job-card[href]'), (a) => a.getAttribute('href')) ); // 拼接完整域名后存入全局links数组 links = rawHrefs.map(href => baseUrl + href); // 爬取完成后,links数组已经填充完毕,后续所有依赖这个数组的逻辑都可以正常执行 console.log("全局links数组内容:", links); // 别忘了关闭浏览器实例 await browser.close(); } catch (err) { console.error(err); } } main();
- 如果你想保留原有的Promise链式写法,也必须把所有读取
links的逻辑放到then回调内部,不能在回调外部的同步代码里直接读:
let links = []; var txt = 'https://www.blablabla.com'; let userToken = main(); userToken.then(function (my_links) { // 所有依赖links值的逻辑都写在这个回调里 for (let i = 0; i < my_links.length; i++) { links.push(txt + my_links[i]); } // 这里打印才能拿到正确的数组内容 console.log(links); });
内容的提问来源于stack exchange,提问作者Ada
相关产品推荐
相关产品推荐

