Node.js环境下PDF抓取下载代码如何正确使用Async Await?
基于async/await的代码改造方案
核心修改逻辑
- 给
scrapPdf函数添加async关键字,声明为异步函数 - 替换
got的.then()链式调用为await写法,同步化异步请求逻辑 - 递归调用下一页的
scrapPdf时添加await,保证分页爬取完成后再执行后续下载、上传逻辑 - 额外优化:将
DownloaderHelper的回调包装为Promise,用await等待所有PDF下载完成后再执行上传,避免出现下载未完成就触发上传的问题
改造后完整代码
// 函数声明前加async标记为异步函数 async function scrapPdf(config, search_url, message) { console.log('PDF downloading'); try { // 用await替换.then()直接获取请求响应 const response = await got(search_url); const $ = cheerio.load(response.body); $('.search-result').find('li > a').each((idx, elem) => { if($(elem).text().trim() == 'PDF'){ const item = $(elem).attr('href'); pdf_lists.push(item); } }) // 转成原生数组用for of循环,支持内部await生效 const pageItems = $('ul.pagination').find('li.page-item').get(); for(const elem of pageItems) { if($(elem).attr('class').includes('page-item active navigation')){ if($(elem).next().hasClass('page-item navigation')){ // 递归调用异步函数必须加await,保证下一页爬取完成再走后续逻辑 await scrapPdf(config, $(elem).next('li').find('a').attr('href'), message); } else { const search_result_dir = `./${message.date_ini}-${message.date_end}`; if(!fs.existsSync(search_result_dir)){ fs.mkdirSync(search_result_dir) } // 把下载任务包装为Promise,等待所有下载完成 const downloadTasks = []; for(let i = 0;i < pdf_lists.length; i++){ const downloadPromise = new Promise((resolve, reject) => { const download = new DownloaderHelper(pdf_lists[i], search_result_dir); download.on('end', resolve) download.on('error', reject) download.start(); }) downloadTasks.push(downloadPromise); } await Promise.all(downloadTasks); console.log(`${pdf_lists.length} files Downloaded!`); uploadFile(search_result_dir); return ; } console.log($(elem).next('li').find('a').attr('href')); } } } catch (err) { // 异步错误统一用try/catch捕获 console.log(err); } }
补充说明
原代码中pdf_lists为全局变量,多任务并发爬取时会出现变量污染问题,建议改为通过函数参数传递或者用闭包存储,避免爬取结果混乱。
内容的提问来源于stack exchange,提问作者dev-ninja
相关产品推荐
相关产品推荐

