Node.js异步爬虫执行完成后如何将结果正确写入本地txt文件
问题解决方案
核心问题说明
https.get为回调风格API,未封装为Promise时,for await不会等待请求返回结果,只会瞬间完成所有请求的发起,导致后续写文件逻辑提前执行await res.on("end", ...)属于无效写法:事件监听方法on返回的是事件发射器实例,不是Promise,无法通过await等待回调执行
改造后完整代码
const https = require("https"); const fs = require("fs"); const readline = require("readline"); const path = require("path"); // 封装单个URL爬取逻辑,返回Promise function fetchUrl(url) { return new Promise((resolve) => { https .get(url, (res) => { const { statusCode } = res; let error; if (statusCode !== 200) { error = new Error("Request Failed.\n" + `Status Code: ${statusCode}`); } if (error) { const firstPath = url.split("/")[7]; const result = `${firstPath} - nothing found`; console.error("data : " + result); res.resume(); resolve(result); return; } res.setEncoding("utf8"); let rawData = ""; res.on("data", (chunk) => { rawData += chunk; }); res.on("end", () => { try { const parsedData = JSON.parse(rawData); const parsedResult = parsedData["data"]["id"] + " - " + parsedData["data"]["price"]; console.log("data : " + parsedResult); resolve(parsedResult); } catch (e) { console.error(e.message); resolve(`${url} - parse JSON failed: ${e.message}`); } }); }) .on("error", (e) => { const errorResult = `${url} - request error: ${e.message}`; console.error(errorResult); resolve(errorResult); }); }) } (async function main() { // 1. 读取所有URL const urls = []; const fileStream = fs.createReadStream("urls.txt"); const rl = readline.createInterface({ input: fileStream, crlfDelay: Infinity, }); for await (let line of rl) { urls.push(line); } rl.close(); // 2. 并发执行所有爬取任务,等待全部完成 const results = await Promise.all(urls.map(url => fetchUrl(url))); // 3. 所有任务完成后写入文件 await fs.promises.writeFile('result.txt', results.join('\n')); console.log("File write successfull"); })();
改动说明
- 将单个URL的爬取逻辑封装为返回Promise的
fetchUrl函数,所有成功/错误结果都通过resolve返回,统一收集 - 使用
Promise.all等待所有爬取任务全部执行完成后,再调用写文件逻辑,保证不会提前执行 - 写文件时将数组转为换行分隔的字符串,避免默认的逗号分隔格式不符合预期
- 移除了全局变量存储结果的逻辑,改为通过Promise返回值收集,避免全局变量污染和异步时序导致的数据丢失
内容的提问来源于stack exchange,提问作者Nelson Biggety
相关产品推荐
相关产品推荐

