You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中如何确保爬虫完成后再将数据存入PostgreSQL数据库

问题解决:先完成爬虫爬取再执行PostgreSQL插入

核心问题原因

你的代码里getMatch()是异步函数,调用后不会阻塞后续代码执行,导致数据库插入操作在爬虫还没爬取到数据时就已执行,此时match_data还是空数组,所以插入了空值。另外你的插入语句写法有误,VALUES ($1,$2,$3,$4,$5)是单条数据的占位方式,但你传入的是数组的数组,会触发语法错误。

修复步骤

  1. 让爬虫函数返回爬取结果:放弃全局变量,改用函数返回值,避免异步场景下的变量状态不可控。
  2. 按顺序执行异步操作:利用async/await确保爬虫执行完毕后,再启动数据库插入流程。
  3. 修正批量插入语法:按照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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 10:20:28