使用Node.js与Puppeteer抓取随机词时如何添加进度描述/进度条?
Puppeteer 抓取进度展示及代码优化方案
一、进度展示实现逻辑
当前代码为单次抓取流程,可将全流程拆分为固定节点,给每个节点分配对应进度占比,执行到对应节点时直接打印进度和状态,无头模式下终端会直接输出内容,清晰直观。如果后续要扩展为批量多次抓取,可以按总抓取次数计算百分比进度。
具体实现要点:
- 拆分全流程为核心节点,对应进度占比:启动浏览器(10%) → 打开目标页面(25%) → 填充抓取参数(40%) → 等待结果加载(60%) → 解析页面内容(80%) → 写入本地文件(95%) → 完成任务(100%)
- 每个节点执行完成后打印当前进度,可搭配简单字符进度条提升可读性
- 所有关键步骤加异常捕获,出错时直接打印错误原因,方便无头模式下排查问题
二、代码规范优化点
- 依赖声明统一放到代码顶部,不要在函数内部声明
require - 移除冗余无用变量(原代码中定义的
file = 'word.txt'未实际使用) - 修正
writeFileSync的错误写法:同步写入方法没有回调参数,用try/catch捕获异常即可 - 常量统一外置管理,后续修改参数不需要调整函数内部逻辑
- 给所有异步操作加异常捕获,避免程序直接崩溃
三、修改后完整代码
// 依赖统一顶部声明 const puppeteer = require('puppeteer'); const fs = require('fs'); // 常量外置统一管理 const CONFIG = { TARGET_URL: 'https://www.sodacoffee.com/words/list-generator', GENERATE_BTN_SELECTOR: '#ctl00_ContentPane_btn', RESULT_COUNT_SELECTOR: '#ctl00_ContentPane_resultscounter', WORD_TABLE_SELECTOR: '#ctl00_ContentPane_GridView1 tbody tr', SCRAPE_COUNT_PER_TIME: 50, OUTPUT_FILE_PATH: './words.json', // 如需批量抓取可以新增这个参数 // TOTAL_SCRAPE_TIMES: 10 } async function launchSearch() { let progress = 0; // 打印进度的工具函数 function printProgress(currentProgress, desc) { const barLength = 20; const filledBar = '='.repeat(Math.floor(currentProgress / 100 * barLength)); const emptyBar = ' '.repeat(barLength - filledBar.length); console.log(`[${filledBar}${emptyBar}] ${currentProgress}% | ${desc}`); } let browser; try { // 1. 启动浏览器 browser = await puppeteer.launch({ // 无头模式直接改为'new'即可 headless: 'new', }); progress = 10; printProgress(progress, '浏览器启动完成'); // 2. 打开目标页面 const page = await browser.newPage(); await page.goto(CONFIG.TARGET_URL); progress = 25; printProgress(progress, '目标页面加载完成'); // 3. 填充抓取参数 const numWordsScrape = await page.$(CONFIG.RESULT_COUNT_SELECTOR); await numWordsScrape.click(); await numWordsScrape.type(String(CONFIG.SCRAPE_COUNT_PER_TIME)); progress = 40; printProgress(progress, '抓取参数填充完成'); // 4. 点击生成等待结果加载 await Promise.all([ page.waitForNavigation(), page.click(CONFIG.GENERATE_BTN_SELECTOR) ]); progress = 60; printProgress(progress, '结果页面加载完成'); // 5. 解析页面内容 const wordList = await page.evaluate((selector) => { return Array.from(document.querySelectorAll(selector)) .map(elem => elem.innerText.trim()); }, CONFIG.WORD_TABLE_SELECTOR); progress = 80; printProgress(progress, '页面内容解析完成'); // 6. 写入本地文件 fs.writeFileSync(CONFIG.OUTPUT_FILE_PATH, JSON.stringify(wordList, null, 2)); progress = 95; printProgress(progress, '结果写入本地完成'); // 完成 progress = 100; printProgress(progress, '全部任务执行完成'); console.log(`共抓取到${wordList.length}个词汇,已保存到${CONFIG.OUTPUT_FILE_PATH}`); } catch (err) { console.error(`任务执行出错:${err.message}`); } finally { if (browser) await browser.close(); } } launchSearch();
内容的提问来源于stack exchange,提问作者McBraunie
相关产品推荐
相关产品推荐

