如何正确解析CSV供Puppeteer读取UPC并填充到网站输入框爬取图书数据
问题原因
1. CSV分隔符配置错误
你提供的CSV样例是*逗号(,)*作为字段分隔符,但你代码中调用csv-parser时指定的分隔符是冒号:,导致CSV解析逻辑无法正确拆分字段,拿不到CODECONTENT列的有效值,最终读取到的UPC数组是空值或者全为NaN。
2. 不必要的数值类型转换
你在读取CODECONTENT时加了+号强制转为数值类型:rows.push(+row.CODECONTENT),UPC是13位编码,部分特殊场景可能开头带0,转为数值会丢失前置0,导致后续搜索匹配失败。
3. 价格获取逻辑冗余
你写的finally块会强制覆盖try和catch中得到的newprice值,前面的价格判断逻辑完全失效,属于多余代码。
修复方案
第一步:修正CSV解析逻辑
把readCsvAsync调用时的分隔符改为逗号,,同时去掉强制转数值的+号:
async function upcData() { try { // 把分隔符从':'改为',' const rows = await readCsvAsync('Book_Bulk.csv', ','); return rows; } catch (err) { console.log(err); return []; } } // 同时修改readCsvAsync中的push逻辑,去掉+号 function readCsvAsync(filename, delimiter=',', encoding='utf-8') { return new Promise((resolve, reject) => { const rows = []; try { fs.createReadStream(filename, {encoding: encoding}) .pipe(parse({delimiter: delimiter})) // 去掉+号,保留字符串格式的UPC .on('data', (row) => rows.push(row.CODECONTENT)) .on('end', () => resolve(rows)) .on('error', reject); } catch (err) { reject(err); } }); }
第二步:优化爬取逻辑
每次搜索前清空输入框,避免上一次的UPC残留,同时删除多余的finally块:
async function getpageData(page,upc){ await page.goto('https://www.bookdepository.com/'); const searchInput = '#book-search-form > div.el-wrap.header-search-el-wrap > input.text-input'; await page.waitForSelector(searchInput); // 先清空输入框再填入新UPC await page.$eval(searchInput, input => input.value = ''); await page.type(searchInput, upc); await page.click('#book-search-form > div.el-wrap.header-search-el-wrap > button'); // 原有字段获取逻辑不变,仅修改价格部分: let newprice = '无定价'; try { await page.waitForSelector('div.price.item-price-wrap.hidden-xs.hidden-sm > span.sale-price', { timeout: 1500 }); const price = await page.$eval('div.price.item-price-wrap.hidden-xs.hidden-sm > span.sale-price', span => span.innerText); newprice = price.slice(-6); } catch { try { await page.waitForSelector('p.list-price', { timeout: 1500 }); const price = await page.$eval('p.list-price', p => p.innerText); newprice = price.slice(-6); } catch {} } return { title: title, author: author, genre: genre, format: format, publisher: publisher, year: newyear, price: newprice } }
第三步:增加异常处理避免单条UPC爬取失败中断整个流程
修改main函数中的循环逻辑,增加try catch包裹单条爬取逻辑:
async function main(){ const allupcs = await upcData(); // 先打印UPC数组确认解析结果 console.log('解析到的UPC列表:', allupcs); const browser = await puppeteer.launch({ headless: false, defaultViewport: null, args: ['--start-maximized']}); const page = await browser.newPage(); const scrapedData = []; for(let upc of allupcs){ if(!upc) continue; // 跳过空的UPC try { const data = await getpageData(page,upc); scrapedData.push({upc, ...data}); console.log(`UPC ${upc} 爬取完成`); } catch (e) { console.log(`UPC ${upc} 爬取失败:`, e.message); // 失败后等待2秒再继续,避免触发反爬 await page.waitForTimeout(2000); } } console.log('全部爬取结果:', scrapedData); await browser.close(); }
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

