使用JavaScript实现多页网站爬取并导出CSV/Excel的问题求助
解决方案:多页爬取并导出CSV/Excel
步骤1:安装额外依赖
除已有的axios、cheerio、express外,还需安装处理文件导出的包:
npm install csv-writer xlsx
步骤2:完整代码实现
const PORT = 8000; const axios = require('axios'); const cheerio = require('cheerio'); const express = require('express'); const createCsvWriter = require('csv-writer').createObjectCsvWriter; const XLSX = require('xlsx'); const app = express(); // 爬取单页数据的函数 async function scrapePage(pageNum) { const url = `https://www.taneps.go.tz/epps/viewAllAwardedContracts.do?d-3998960-p=${pageNum}&selectedItem=viewAllAwardedContracts.do&T01_ps=100`; try { const response = await axios({ url, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } }); const html = response.data; const $ = cheerio.load(html); const rows = []; // 提取表头(仅第一页) let headers = []; if (pageNum === 1) { $('#T01 thead th').each((i, el) => { headers.push($(el).text().trim()); }); } // 提取表格行数据 $('#T01 tbody tr').each((i, el) => { const row = {}; $(el).find('td').each((j, cell) => { row[headers[j]] = $(cell).text().trim(); }); rows.push(row); }); return { headers, rows }; } catch (err) { console.error(`爬取第${pageNum}页失败:`, err); return { headers: [], rows: [] }; } } // 获取总页数 async function getTotalPages() { const url = 'https://www.taneps.go.tz/epps/viewAllAwardedContracts.do?d-3998960-p=1&selectedItem=viewAllAwardedContracts.do&T01_ps=100'; try { const response = await axios({ url, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } }); const html = response.data; const $ = cheerio.load(html); // 解析分页信息中的总页数,需根据页面实际结构调整选择器 const pageInfo = $('.paginationInfo').text().trim(); const totalPagesMatch = pageInfo.match(/of (\d+)/); if (!totalPagesMatch) return 1; return parseInt(totalPagesMatch[1]); } catch (err) { console.error('获取总页数失败:', err); return 1; // 默认仅爬第一页 } } // 主爬取函数:爬取所有页面并导出文件 async function scrapeAllPages() { const totalPages = await getTotalPages(); console.log(`开始爬取,共${totalPages}页`); let allData = []; let headers = []; // 循环爬取每一页,添加延迟避免反爬 for (let page = 1; page <= totalPages; page++) { console.log(`正在爬取第${page}页`); const { headers: pageHeaders, rows } = await scrapePage(page); if (page === 1) headers = pageHeaders; allData.push(...rows); // 每页间隔1秒,可根据情况调整 await new Promise(resolve => setTimeout(resolve, 1000)); } // 导出CSV文件 if (allData.length > 0) { const csvWriter = createCsvWriter({ path: 'awarded_contracts.csv', header: headers.map(header => ({ id: header, title: header })) }); await csvWriter.writeRecords(allData); console.log('CSV文件已导出: awarded_contracts.csv'); // 导出Excel文件(可选) const worksheet = XLSX.utils.json_to_sheet(allData); const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, worksheet, 'Awarded Contracts'); XLSX.writeFile(workbook, 'awarded_contracts.xlsx'); console.log('Excel文件已导出: awarded_contracts.xlsx'); } else { console.log('未爬取到任何数据'); } } // 启动服务器并开始爬取 app.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); scrapeAllPages(); });
关键改进点说明
- 多页爬取:通过URL中的
d-3998960-p参数控制页码,先获取总页数再循环爬取每一页。 - 数据提取优化:不再提取整个表格的文本,而是解析表头和每一行的单元格内容,保证导出的CSV/Excel结构清晰。
- 反爬处理:添加
User-Agent请求头,并且在分页爬取时加入延迟,降低被网站拦截的风险。 - 文件导出:使用
csv-writer生成CSV文件,xlsx生成Excel文件,两种格式可选。
注意事项
- 如果分页信息的选择器
.paginationInfo无效,需要打开目标网站的开发者工具,找到实际的分页信息元素来调整选择器。 - 如果爬取过程中出现请求失败,可能是网站的反爬机制限制,可以适当延长延迟时间,或者添加更多请求头(如
Referer)。 - 大量数据爬取时,建议分批写入文件,避免内存占用过高。
内容的提问来源于stack exchange,提问作者Gastone Dereck
相关产品推荐
相关产品推荐

