Node.js中如何确保爬虫完成后再将数据存入PostgreSQL数据库
问题解决:先完成爬虫爬取再执行PostgreSQL插入
核心问题原因
你的代码里getMatch()是异步函数,调用后不会阻塞后续代码执行,导致数据库插入操作在爬虫还没爬取到数据时就已执行,此时match_data还是空数组,所以插入了空值。另外你的插入语句写法有误,VALUES ($1,$2,$3,$4,$5)是单条数据的占位方式,但你传入的是数组的数组,会触发语法错误。
修复步骤
- 让爬虫函数返回爬取结果:放弃全局变量,改用函数返回值,避免异步场景下的变量状态不可控。
- 按顺序执行异步操作:利用
async/await确保爬虫执行完毕后,再启动数据库插入流程。 - 修正批量插入语法:按照PostgreSQL要求构造批量插入的SQL语句和参数。
修正后的完整代码
const cheerio = require("cheerio"); const axios = require("axios"); const { Pool } = require('pg'); const url = "https://www.covers.com/sports/nba/matchups?selectedDate=2023-03-08" const pool = new Pool({ user: ###, host: ###, database: ###, password: ###, port: ### }); // 初始化数据库表,确保表创建完成再执行后续操作 async function initTable() { try { await pool.query(` CREATE TABLE IF NOT EXISTS nba_test5( id varchar PRIMARY KEY NOT NULL, hometeam varchar, awayteam varchar, homescore varchar, awayscore varchar ) `); console.log("表初始化完成"); } catch (error) { console.error("表创建失败:", error); throw error; } } async function getMatch() { try { const response = await axios.get(url); const $ = cheerio.load(response.data); const match_data = []; const match_list = $('.cmg_matchup_game_box.cmg_game_data'); match_list.each(function(){ const match_id = $(this).attr('data-event-id'); const home_team = $(this).attr('data-home-team-fullname-search'); const away_team = $(this).attr('data-away-team-fullname-search'); const home_score = $(this).attr('data-home-score'); const away_score = $(this).attr('data-away-score'); match_data.push({ match_id, home_team, away_team, home_score, away_score }); }); console.log("爬取到的数据:", match_data); return match_data; } catch(error) { console.error("爬虫执行失败:", error); throw error; } } async function insertData(matchData) { if (matchData.length === 0) { console.log("没有数据需要插入"); return; } // 构造批量插入的占位符和参数数组 const placeholders = matchData.map((_, index) => `($${index*5+1}, $${index*5+2}, $${index*5+3}, $${index*5+4}, $${index*5+5})` ).join(','); const values = matchData.flatMap(item => [ item.match_id, item.home_team, item.away_team, item.home_score, item.away_score ]); try { await pool.query( `INSERT INTO nba_test5 (id, hometeam, awayteam, homescore, awayscore) VALUES ${placeholders}`, values ); console.log(`${matchData.length}条数据插入成功`); } catch (error) { console.error("数据插入失败:", error); throw error; } } // 主执行函数,按顺序串联所有操作 async function main() { try { await initTable(); const matchData = await getMatch(); await insertData(matchData); await pool.end(); } catch (error) { console.error("程序执行出错:", error); await pool.end(); process.exit(1); } } main();
关键说明
- 异步流程控制:通过
async/await强制异步操作按顺序执行,彻底解决爬虫未完成就插入的问题。 - 无全局变量设计:爬虫结果通过函数返回传递,避免全局变量在异步场景下的状态混乱。
- 批量插入优化:一次性插入所有爬取数据,相比单条插入大幅提升效率,同时符合PostgreSQL语法规范。
- 完整错误处理:每个环节都添加错误捕获,确保程序出错时能正确关闭数据库连接并退出。
内容的提问来源于stack exchange,提问作者Jerry
相关产品推荐
相关产品推荐

