// 导入需要的模块 const request = require('request'); const fs = require('fs'); const xpath = require('xpath'); const dom = require('xmldom').DOMParser; const mysql = require('mysql'); // 要爬取的网页地址 // https://data.rmtc.org.cn/gis/PubIndexM.html?type=0 // https://data.rmtc.org.cn/gis/PubIndexM.html?type=1 const mysqlConfig = { host: 'localhost', // 数据库地址 user: 'root', // 数据库用户名 password: '123456', // 数据库密码 database: 'open_data' // 数据库名称 } // main() async function main() { try { await doFetch('0') } catch (err) { console.error('type=0 爬取时出现错误,正在重试...') try { await doFetch('0') } catch (err) { console.error('type=0 爬取时出现错误,爬取失败') } } try { await doFetch('1') } catch (err) { console.error('type=1 爬取时出现错误,正在重试...') try { await doFetch('1') } catch (err) { console.error('type=1 爬取时出现错误,爬取失败') } } console.log('爬取完成') } // async function doFetch(type) { const url = 'https://data.rmtc.org.cn/gis/PubIndexM.html?type=' + type await new Promise((resolve, reject) => { // 发送请求,获取网页内容 request(url, async (error, response, body) => { if (error) { console.error(error); // return reject() } // fs.writeFileSync('output/html.json', body, 'utf-8'); // 使用dom模块解析body内容,生成文档对象 const doc = new dom().parseFromString(body); // 修改了这个xpath表达式,用li标签而不是text(),因为text()会匹配所有文本节点,包括空白和换行 const lis = xpath.select("//ul[@data-role='listview']/li", doc); // 定义一个空数组,用于存储转换后的数据 const data = []; const childrenPage = []; // 遍历提取到的数据,将其转换为对象,并存入数组中 for (let i = 0; i < lis.length; i++) { const li = lis[i] /*
  • 红沿河核电厂 (复州城)

    83 nGy/h 2023-08-25  

  • */ // 使用nodeValue属性获取文本内容 const name = xpath.select1(".//h2/span[@class='epfy'][1]/text()", li).nodeValue.trim(); const location = xpath.select1(".//h2/span[@class='epfy'][2]/text()", li).nodeValue.trim(); const value = xpath.select1(".//p/span[@class='span-count']/text()", li).nodeValue.trim(); const date = xpath.select1(".//p/span[@class='showtime']/text()", li).nodeValue.trim(); // 使用正则表达式匹配type和id的值 const href = xpath.select1("./a/@href", li).nodeValue.trim(); const regex = /type=(\d+)&id=(\d+)/; const match = regex.exec(href); const type = match[1]; const id = match[2]; // 创建一个对象,存储每一条数据 const item = { name, location, value, date, parent_id: null, type, id }; // 将对象推入数组中 data.push(item); childrenPage.push({ type, id, href, name }) } // 打印转换后的数据 // console.log(data); // console.log('主表数据完成', JSON.stringify(data)); console.log('主表数据完成'); saveToDb(data) // fs.writeFileSync('output/data.json', JSON.stringify(data, null, 4), 'utf-8'); console.log('childrenPage', childrenPage) for (let page of childrenPage) { console.log('#######################################################') console.log('page', page) await doFetch2(page.type, page.id, page.name, page.href) console.log('#######################################################') await new Promise((resolve) => { setTimeout(resolve, 1000) }) } resolve() }); }) } async function doFetch2(parentType, parentId, parentName, relativeUrl) { const url = 'https://data.rmtc.org.cn/gis/' + relativeUrl // 发送请求,获取网页内容 let data = await new Promise((resolve) => { request(url, (error, response, body) => { if (error) { console.error(error); return } const doc = new dom().parseFromString(body); const lis = xpath.select("//ul[@data-role='listview']/li", doc); const data = []; // 遍历提取到的数据,将其转换为对象,并存入数组中 for (let i = 0; i < lis.length; i++) { const li = lis[i] /*
  • 老渔窝

    71 nGy/h 2023-08-25  

  • */ // 使用nodeValue属性获取文本内容 const time = xpath.select1(".//a/@time", li).nodeValue.trim(); const itemkey = xpath.select1(".//a/@itemkey", li).nodeValue.trim(); const itemcode = xpath.select1(".//a/@itemcode", li).nodeValue.trim(); const itemname = xpath.select1(".//a/@itemname", li).nodeValue.trim(); const location = xpath.select1(".//h2/text()", li).nodeValue.trim(); const value = xpath.select1(".//p/span[@class='span-count']/text()", li).nodeValue.trim(); const date = xpath.select1(".//p/span[@class='showtime']/text()", li).nodeValue.trim(); // 创建一个对象,存储每一条数据 const item = { name: parentName, location, value, date, parent_id: parentId, type: parentType, id: null, itemkey: itemkey, itemcode: itemcode, itemname: itemname, time, }; // 将对象推入数组中 data.push(item); } // 打印转换后的数据 // console.log(data); // console.log('二级分类数据完成', parentType, parentId, JSON.stringify(data)); console.log('二级分类数据完成', parentType, parentId); resolve(data) // fs.writeFileSync('output/data.json', JSON.stringify(data, null, 4), 'utf-8'); }); }) saveToDb(data) } function saveToDb(data) { if (!data || data.length == 0) { console.error("没有数据需要保存") return } // 创建一个数据库连接对象 const connection = mysql.createConnection(mysqlConfig); // 连接数据库 connection.connect((err) => { if (err) { console.error(err); } else { console.log('数据库连接成功'); const sql = `INSERT IGNORE INTO nuclear_data (${Object.keys(data[0]).join(', ')}) VALUES ?`; // `REPLACE INTO nuclear_data (name, location, value, date, parent_id, type, id) VALUES ?`; // `INSERT IGNORE INTO nuclear_data (name, location, value, date, parent_id, type, id) VALUES ?`; // 将数据转换为二维数组,方便插入 const values = data.map(item => Object.values(item)); // let data = [ // { // name: '红沿河核电厂', // location: '复州城', // value: '83 nGy/h', // date: '2023-08-25', // parent_id: '1', // type: '1', // id: '2410283902' // }, // ]; // const values = [ // [ // "红沿河核电厂", // "复州城", // "83 nGy/h", // "2023-08-25", // "1", // "1", // "2410283902" // ] // ] // 执行插入或替换数据的语句,传入values作为参数 connection.query(sql, [values], (err, result) => { if (err) { console.error(err); } else { console.log('成功'); // 关闭数据库连接 connection.end(); } }); } }); } module.exports = { run: main, }