如何解决异步爬虫函数返回对象无法赋值给变量的问题
问题排查与解决步骤
以下是按优先级排序的排查方向,都是这类问题的常见坑:
1. 确认getSharesInfo函数是否正确return了数据
这是最常见的原因:很多人在函数里打印了数据,但忘记return结果。单独执行时console能看到数据,但函数本身返回的是Promise<undefined>,所以await后shares自然为空。
错误示例:
async function getSharesInfo() { const res = await axios.get('目标URL'); const $ = cheerio.load(res.data); const stockData = { /* 处理后的数据 */ }; console.log(stockData); // 能输出,但没return }
修正写法:
async function getSharesInfo() { const res = await axios.get('目标URL'); const $ = cheerio.load(res.data); const stockData = { /* 处理后的数据 */ }; console.log(stockData); return stockData; // 必须return结果 }
2. 确保Express路由的handler是async函数
如果路由回调没有声明为async,内部的await会无效,甚至可能静默失败(比如非async函数里用await会触发语法错误,或用then但未处理结果导致数据无法传递)。
错误示例:
// 非async回调,await不生效 app.get('/', (req, res) => { const shares = await getSharesInfo(); // 这里会直接报错,或静默返回Promise res.render('index', { shares }); });
修正写法:
// 声明为async回调,同时用try/catch捕获异常 app.get('/', async (req, res) => { try { const shares = await getSharesInfo(); res.render('index', { shares }); } catch (error) { console.error('获取股票数据失败:', error); res.status(500).send('数据加载失败'); } });
3. 检查getSharesInfo内部的错误处理是否吞掉了异常
如果函数内部用了try/catch但没有抛出错误或返回 fallback 数据,当请求失败时,函数会返回Promise<undefined>,导致await后shares为空且无报错。
错误示例:
async function getSharesInfo() { try { const res = await axios.get('目标URL'); const $ = cheerio.load(res.data); const stockData = { /* 处理后的数据 */ }; return stockData; } catch (err) { console.log('请求出错了'); // 只打印,没抛出或返回数据 } }
修正写法:
async function getSharesInfo() { try { const res = await axios.get('目标URL'); const $ = cheerio.load(res.data); const stockData = { /* 处理后的数据 */ }; return stockData; } catch (err) { console.error('爬取数据失败:', err); throw err; // 抛出错误让路由层处理 // 或者返回默认值:return {}; 或 return []; } }
4. 验证爬取的HTML结构是否符合预期
有些网站会根据请求头(比如User-Agent)返回不同内容,单独测试时用的是浏览器请求头,而Express中axios用的是Node环境默认头,可能被反爬返回空页面或验证码页面。
可以在getSharesInfo中把爬取到的HTML保存到本地,验证内容:
const fs = require('fs'); async function getSharesInfo() { const res = await axios.get('目标URL', { // 模拟浏览器请求头 headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' } }); // 保存HTML到本地 fs.writeFileSync('test.html', res.data); const $ = cheerio.load(res.data); const stockData = { /* 处理后的数据 */ }; return stockData; }
打开test.html查看是否为预期的股票页面,如果是空白或验证码,说明需要调整请求头或处理反爬。
5. 排查是否有未被等待的异步操作
如果getSharesInfo内部用了then而非await处理异步操作,可能导致函数提前return,比如:
// 错误写法:then回调的return不会作为函数的返回值 async function getSharesInfo() { axios.get('目标URL').then(res => { const $ = cheerio.load(res.data); const stockData = { /* 处理后的数据 */ }; return stockData; }); }
必须统一用await处理所有异步逻辑,确保函数在数据处理完成后再return。
内容的提问来源于stack exchange,提问作者Rosan Paudel
相关产品推荐
相关产品推荐

