Node.js导出Puppeteer爬取值打印显示[object Object]问题排查
问题原因与解决方案
核心问题
你遇到的问题有两个关键原因:
- 异步导出时机错误:CommonJS的
require是同步加载机制,你的两个模块里都把导出逻辑放在了**立即执行异步函数(IIFE)**中。当index.js执行require时,异步函数还没跑完,模块默认导出的是初始空对象,所以你拿到的priceModule和nameModule都是空对象。 - 对象拼接触发默认toString:就算导出成功,直接用
+连接对象会自动调用toString()方法,结果必然是[object Object]。
修正方案(推荐Promise方式)
因为Puppeteer的操作本身就是异步的,所以模块应该导出Promise,再在主文件中用async/await获取结果。
1. 修改nameModule.js
const puppeteer = require("puppeteer"); const url = "https://www.sec.gov/edgar/search/#/dateRange=custom&category=custom&startdt=2017-11-05&enddt=2022-11-07&forms=4"; // 直接导出异步函数返回的Promise module.exports = (async () => { let browser; try { browser = await puppeteer.launch(); const [page] = await browser.pages(); const $ = (...args) => page.waitForSelector(...args); const text = async (...args) => (await $(...args)).evaluate(el => el.textContent.trim()); await page.goto(url, {waitUntil: "domcontentloaded"}); const info = { secTableEN: await text(".table td.entity-name"), secTableFiled: await text(".table td.filed"), secTableLink: await text(".table td.filetype"), }; return info.secTableEN; } catch (err) { console.error(err); throw err; // 抛出错误让主文件捕获 } finally { await browser?.close(); } })();
2. 修改priceModule.js
const puppeteer = require("puppeteer"); const url = "https://www.sec.gov/edgar/search/#/dateRange=custom&category=custom&startdt=2017-11-05&enddt=2022-11-07&forms=4"; // 直接导出异步函数返回的Promise module.exports = (async () => { let browser; try { browser = await puppeteer.launch(); const [page] = await browser.pages(); const ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"; await page.setUserAgent(ua); await page.goto(url, {waitUntil: "domcontentloaded", timeout: 0}); const responseP = page.waitForResponse(res => res.status() === 200 && res.url().endsWith(".xml") ); const a = await page.waitForSelector(".filetype .preview-file"); await a.click(); const html = await (await responseP).text(); await page.evaluate(html => document.body.outerHTML = html, html); const price = await page.$$eval(".FormText", els => els.find(e => e.textContent.trim() === "$") .parentNode .textContent .trim() ); return price; } catch (err) { console.error(err); throw err; // 抛出错误让主文件捕获 } finally { await browser?.close(); } })();
3. 修改index.js
const priceModule = require("./price"); const nameModule = require("./name"); // 用async/await解析Promise,获取实际值后再打印 (async () => { try { const secName = await nameModule; const secPrice = await priceModule; console.log(secName, secPrice); // 或用模板字符串 `${secName} ${secPrice}` } catch (err) { console.error("加载模块失败:", err); } })();
额外注意事项
- 永远不要在异步函数内部修改
module.exports,CommonJS模块加载是同步的,异步代码执行时模块已经完成加载,修改不会生效。 - 处理异步数据时,必须等Promise解析完成后再操作,不能直接对Promise对象进行拼接或其他同步操作。
内容的提问来源于stack exchange,提问作者Jojo Amankwa
相关产品推荐
相关产品推荐

