Steam交易卡价格爬取返回大量undefined问题求助
问题排查与解决方案
一、大量undefined的原因及修复
核心原因分析
- 文本提取逻辑错误:原代码中
$('.normal_price').text()会拼接所有匹配元素的文本,导致后续split(' ')[3]无法准确定位价格;且部分页面的文本结构与预期不符,索引3不存在时直接返回undefined。 - 部分游戏无交易卡:不是所有Steam游戏都支持交易卡,这类游戏的市场页面没有价格元素,自然无法提取有效数据。
- 高频请求被拦截:循环发起大量异步请求触发Steam反爬机制,部分请求返回异常页面,无价格信息。
- Cookie有效性问题:Cookie过期或格式错误时,请求会返回未登录状态页面,无法加载正确价格。
代码修复要点
1. 修正价格提取逻辑
只获取第一个匹配的价格元素文本,避免多元素文本拼接混乱;同时增加容错逻辑,用正则兜底提取价格:
function filterTradingCard(gameId){ var options = { 'method': 'GET', 'url': `https://steamcommunity.com/market/search?q=&category_753_Game%5B%5D=tag_app_${gameId}&category_753_cardborder%5B%5D=tag_cardborder_0&category_753_item_class%5B%5D=tag_item_class_2&appid=753#p1_price_asc`, 'headers': { 'Cookie': `webTradeEligibility=${webTradeEligibility}; browserid=${browserid}; steamLoginSecure=${steamLoginSecure}; sessionid=${sessionid}` } }; request(options, (error, response, html)=> { if (error) { console.error(`游戏ID ${gameId} 请求失败:`, error); return; } if (response.statusCode !== 200){ console.log(`游戏ID ${gameId} 响应错误: ${response.statusCode}`); return; } const $ = cheerio.load(html); // 只取第一个价格元素,避免多元素文本拼接 const priceElement = $('.normal_price').first(); if (!priceElement.length) { console.log(`游戏ID ${gameId} 无交易卡`); return; } const rawPriceText = priceElement.text().trim(); // 优先按空格分割取价格,失败则用正则匹配 let pricePart = rawPriceText.split(' ')[2]; if (!pricePart) { const priceMatch = rawPriceText.match(/\d+,\d+/); pricePart = priceMatch ? priceMatch[0] : undefined; } if (!pricePart) { console.log(`游戏ID ${gameId} 价格解析失败: ${rawPriceText}`); return; } // 转换为数值并输出 const numericPrice = convertPriceToNumber(pricePart); console.log(`游戏ID ${gameId} 交易卡价格: ${numericPrice} ARS`); }) }
2. 控制请求并发
将请求包装为Promise,限制并发数量并增加请求间隔,避免触发反爬:
const requestPromise = require('request-promise'); // 改写为返回Promise的异步函数 async function filterTradingCard(gameId){ var options = { 'method': 'GET', 'url': `https://steamcommunity.com/market/search?q=&category_753_Game%5B%5D=tag_app_${gameId}&category_753_cardborder%5B%5D=tag_cardborder_0&category_753_item_class%5B%5D=tag_item_class_2&appid=753#p1_price_asc`, 'headers': { 'Cookie': `webTradeEligibility=${webTradeEligibility}; browserid=${browserid}; steamLoginSecure=${steamLoginSecure}; sessionid=${sessionid}` } }; try { const html = await requestPromise(options); const $ = cheerio.load(html); const priceElement = $('.normal_price').first(); if (!priceElement.length) return null; const rawPriceText = priceElement.text().trim(); let pricePart = rawPriceText.split(' ')[2] || rawPriceText.match(/\d+,\d+/)[0]; return convertPriceToNumber(pricePart); } catch (error) { console.error(`游戏ID ${gameId} 请求失败:`, error); return null; } } // 批量处理游戏ID,控制并发 async function getInfo(){ try { const html = await requestPromise('https://store.steampowered.com/search/?sort_by=Price_ASC&maxprice=840&category1=998&category2=29'); const $ = cheerio.load(html); const gameIds = []; $('.col.search_capsule').each(function(i,element) { let gameId = $(this).find('img').attr('src').split("/")[5].trim(); gameIds.push(gameId); }); // 每次并发2个请求,间隔500ms const concurrency = 2; for (let i = 0; i < gameIds.length; i += concurrency) { const batch = gameIds.slice(i, i + concurrency); const results = await Promise.all(batch.map(id => filterTradingCard(id))); batch.forEach((id, index) => { if (results[index]) { console.log(`游戏ID ${id} 交易卡价格: ${results[index]} ARS`); } }); await new Promise(resolve => setTimeout(resolve, 500)); } } catch (error) { console.error("获取游戏列表失败:", error); } } async function getList(){ await getInfo(); } getList();
二、价格转数值实现
通过正则提取价格中的数字部分,替换逗号为小数点后转换为数值:
function convertPriceToNumber(priceStr) { if (!priceStr) return null; // 匹配带逗号的小数格式 const match = priceStr.match(/(\d+,\d+)/); if (match) { return parseFloat(match[0].replace(',', '.')); } return null; }
内容的提问来源于stack exchange,提问作者Lucas Genovese
相关产品推荐
相关产品推荐

