一、准备环境
安装好Node.js
新建一个文件夹
新建一个js文件 spider
二、代码时间
1.首先引入相关模块
// 目标是获取某网站的疫情数据
const superagent = require('superagent')
const cheerio = require('cheerio')
const mysql =require('mysql')
const path = require('path')
var schedule = require('node-schedule');
//schedule模块用来执行定时任务
const request=require('request');
2.创建数据库连接
var connection ;
//创建数据库连接
//创建一个函数handleError,负责防止mysql断连
function handleError () {
connection = mysql.createConnection({
host:'localhost',
port:端口号,//安装数据库默认端口号为3306
user:"Mysql用户名",
password:"Mysql密码",
database:"你的数据库名称"
});
//连接错误,2秒重试
connection.connect(function (err) {
if (err) {
console.log('error when connecting to db:', err);
setTimeout(handleError , 2000);
}
});
connection.on('error', function (err) {
console.log('db error', err);
// 如果是连接断开,自动重新连接
if (err.code === 'PROTOCOL_CONNECTION_LOST') {
handleError();
} else {
throw err;
}
});
}
handleError();//执行函数
3.获取当前时间
//获取当天的时间
var getToday=function(){
var time=new Date();
var year=time.getFullYear();
var day=time.getDate();
if(day<10){
day='0'+day;
}
var month=time.getMonth()+1;
if(month<10){
month='0'+month;
}
var date=year+'-'+month+'-'+day;
return date
}
4.第一个执行函数
1.这个定时任务是负责获取数据,存入数据库中
2.先用superagent请求页面获得html
3.然后用cheerio解析html,可以通过jQuery的方法操作dom,获得里面的数据
4.获得数据之后,就写入数据库的alldata2数据表
var spider=function(){
// 1. 请求目标网站
const url = `https://ncov.dxy.cn/ncovh5/view/pneumonia`
superagent
.get(url)
.then(res => {
// console.log(res.text) // 相应的内容
// 浏览器可以解析html 但是node端不行
// 2. 去解析html字符串从里面提取对应疫情数据
const $ = cheerio.load(res.text) // 然后后我们就可以通过jQuery的方法操作dom
// 获取全国疫情信息数据
var $getAreaStat = $('#getAreaStat').html()
// console.log($getListByCountryTypeService1)
// 使用字符切割 正则匹配 eval函数
var dataObj = {}
eval($getAreaStat.replace(/window/g, 'dataObj'))
//console.log(dataObj)
// 3. fs写入数据到本地
var date=getToday();
var getAreaStat=dataObj.getAreaStat;
var arr=[]
getAreaStat.forEach(item => {
var provinceCode=item.locationId;
var result=item.cities;
//console.log(result);
if(result.length==0){
var addSql = 'INSERT INTO alldata2(id,date,province,provinceCode,city,cityCode,confirmed,suspected,cured,dead) VALUES(0,?,?,?,?,?,?,?,?,?)';
var cityCode=provinceCode;
var province=item.provinceName;
var city=province;
var confirmed=item.confirmedCount;
var suspected=item.suspectedCount;
var cured=item.curedCount;
var dead=item.deadCount;
var addSqlParams = [date,province,provinceCode,city,cityCode,confirmed,suspected,cured,dead];
//alldata
connection.query(addSql, addSqlParams, function (err, result) {
if (err) {
console.log('[INSERT ERROR-] - ', err.message);
return;
}
});
}else{
result.forEach(res=>{
var addSql = 'INSERT INTO alldata2(id,date,province,provinceCode,city,cityCode,confirmed,suspected,cured,dead) VALUES(0,?,?,?,?,?,?,?,?,?)';
var cityCode=res.locationId
var province=item.provinceName;
var city=res.cityName;
var confirmed=res.confirmedCount;
var suspected=res.suspectedCount;
var cured=res.curedCount;
var dead=res.deadCount;
var addSqlParams = [date,province,provinceCode,city,cityCode,confirmed,suspected,cured,dead];
//alldata
connection.query(addSql, addSqlParams, function (err, result) {
if (err) {
console.log('[INSERT ERROR-] - ', err.message);
return;
}
});
})
}
})
console.log('写入数据成功!')
})
.catch(err => {
throw err
})
}
5.第二个执行函数
1.读取之前写入alldata2数据表的数据
2.请求高德地图的api获取地理坐标
3.写入location2数据表
var spider2=function(){
var date=getToday();
var strings="SELECT * FROM `alldata2` WHERE date='"+date+"'"
connection.query(strings, function (err, result) {
if (err) {
console.log('[INSERT ERROR-] - ', err.message);
return;
}else{
//console.log(result);
const sleep = function (ms){
return new Promise(resolve => setTimeout(resolve, ms))
}
const requestData = async function(){
for(var i=0;i<result.length;i++){
var city=result[i].city;
var province=result[i].province;
var provinceCode=result[i].provinceCode;
var cityCode=result[i].cityCode;
var confirmed=result[i].confirmed;
var url='https://restapi.amap.com/v3/geocode/geo?address='+province+city+'&output=JSON&key=你申请的地址匹配的key'
//console.log(url);
request(encodeURI(url),function (error, response, body) {
var data =JSON.parse(body)
var location=data.geocodes[0].location;
//console.log(location)
var lng=location.split(',')[0];
lng=parseFloat(lng)
var lat=location.split(',')[1];
lat=parseFloat(lat)
var addSql2 = 'INSERT INTO location2(id,date,province,provinceCode,city,cityCode,confirmed,lng,lat) VALUES(0,?,?,?,?,?,?,?,?)';
var addSqlParams2 = [date,province,provinceCode,city,cityCode,confirmed,lng,lat];
connection.query(addSql2, addSqlParams2, function (err, result) {
if (err) {
console.log('[INSERT ERROR-] - ', err.message);
return;
}
});
})
await sleep(200);//每一个循环休息0.2s}
}
}
requestData();
}
});
}
6.为两个执行函数创建定时任务
var runSchedule =function (cb) {
// cron风格的配置:每天上午2点05分执行一次第一个函数
schedule.scheduleJob('0 5 2 * * *', function () {
var time=new Date();
var year=time.getFullYear();
var day=time.getDate();
var month=time.getMonth()+1;
console.log('spider定时任务执行一次'+year+'年'+month+'月'+day+'日');
cb && cb();
});
}
//可以按照cron的格式设置
var runSchedule2 =function (cb) {
// cron风格的配置:每天上午2点10分执行一次第二个函数
schedule.scheduleJob('0 10 2 * * *', function () {
var time=new Date();
var year=time.getFullYear();
var day=time.getDate();
var month=time.getMonth()+1;
console.log('spider2定时任务执行一次'+year+'年'+month+'月'+day+'日');
cb && cb();
});
}
runSchedule(spider);
runSchedule2(spider2);
console.log('定时任务已启动');
7.全部代码
// // 目标是获取网站的疫情数据
const superagent = require('superagent')
const cheerio = require('cheerio')
const mysql =require('mysql')
const path = require('path')
var schedule = require('node-schedule');
//schedule模块用来执行定时任务
const request=require('request');
// superagent.get(url).then()
var connection ;
//创建数据库连接
function handleError () {
connection = mysql.createConnection({
host:'localhost',
port:端口号,//安装数据库默认端口号为3306
user:"Mysql用户名",
password:"Mysql密码",
database:"你的数据库名称"
});
//连接错误,2秒重试
connection.connect(function (err) {
if (err) {
console.log('error when connecting to db:', err);
setTimeout(handleError , 2000);
}
});
connection.on('error', function (err) {
console.log('db error', err);
// 如果是连接断开,自动重新连接
if (err.code === 'PROTOCOL_CONNECTION_LOST') {
handleError();
} else {
throw err;
}
});
}
handleError();
//获取当天的时间
var getToday=function(){
var time=new Date();
var year=time.getFullYear();
var day=time.getDate();
if(day<10){
day='0'+day;
}
var month=time.getMonth()+1;
if(month<10){
month='0'+month;
}
var date=year+'-'+month+'-'+day;
return date
}
var spider=function(){
// 1. 请求目标网站
const url = `https://ncov.dxy.cn/ncovh5/view/pneumonia`
superagent
.get(url)
.then(res => {
// console.log(res.text) // 相应的内容
// 浏览器可以解析html 但是node端不行
// 2. 去解析html字符串从里面提取对应疫情数据
const $ = cheerio.load(res.text) // 然后后我们就可以通过jQuery的方法操作dom
// 获取全国疫情信息数据
var $getAreaStat = $('#getAreaStat').html()
// console.log($getListByCountryTypeService1)
// 使用字符切割 正则匹配 eval函数
var dataObj = {}
eval($getAreaStat.replace(/window/g, 'dataObj'))
//console.log(dataObj)
// 3. fs写入数据到本地
var date=getToday();
var getAreaStat=dataObj.getAreaStat;
var arr=[]
getAreaStat.forEach(item => {
var provinceCode=item.locationId;
var result=item.cities;
//console.log(result);
if(result.length==0){
var addSql = 'INSERT INTO alldata2(id,date,province,provinceCode,city,cityCode,confirmed,suspected,cured,dead) VALUES(0,?,?,?,?,?,?,?,?,?)';
var cityCode=provinceCode;
var province=item.provinceName;
var city=province;
var confirmed=item.confirmedCount;
var suspected=item.suspectedCount;
var cured=item.curedCount;
var dead=item.deadCount;
var addSqlParams = [date,province,provinceCode,city,cityCode,confirmed,suspected,cured,dead];
//alldata
connection.query(addSql, addSqlParams, function (err, result) {
if (err) {
console.log('[INSERT ERROR-] - ', err.message);
return;
}
});
}else{
result.forEach(res=>{
var addSql = 'INSERT INTO alldata2(id,date,province,provinceCode,city,cityCode,confirmed,suspected,cured,dead) VALUES(0,?,?,?,?,?,?,?,?,?)';
var cityCode=res.locationId
var province=item.provinceName;
var city=res.cityName;
var confirmed=res.confirmedCount;
var suspected=res.suspectedCount;
var cured=res.curedCount;
var dead=res.deadCount;
var addSqlParams = [date,province,provinceCode,city,cityCode,confirmed,suspected,cured,dead];
//alldata
connection.query(addSql, addSqlParams, function (err, result) {
if (err) {
console.log('[INSERT ERROR-] - ', err.message);
return;
}
});
})
}
})
console.log('写入数据成功!')
})
.catch(err => {
throw err
})
}
//spider();
var spider2=function(){
var date=getToday();
var strings="SELECT * FROM `alldata2` WHERE date='"+date+"'"
connection.query(strings, function (err, result) {
if (err) {
console.log('[INSERT ERROR-] - ', err.message);
return;
}else{
//console.log(result);
const sleep = function (ms){
return new Promise(resolve => setTimeout(resolve, ms))
}
const requestData = async function(){
for(var i=0;i<result.length;i++){
var city=result[i].city;
var province=result[i].province;
var provinceCode=result[i].provinceCode;
var cityCode=result[i].cityCode;
var confirmed=result[i].confirmed;
var url='https://restapi.amap.com/v3/geocode/geo?address='+province+city+'&output=JSON&key=a36e6768d9262fcb339a50ce016a5caa'
//console.log(url);
request(encodeURI(url),function (error, response, body) {
var data =JSON.parse(body)
var location=data.geocodes[0].location;
//console.log(location)
var lng=location.split(',')[0];
lng=parseFloat(lng)
var lat=location.split(',')[1];
lat=parseFloat(lat)
var addSql2 = 'INSERT INTO location2(id,date,province,provinceCode,city,cityCode,confirmed,lng,lat) VALUES(0,?,?,?,?,?,?,?,?)';
var addSqlParams2 = [date,province,provinceCode,city,cityCode,confirmed,lng,lat];
connection.query(addSql2, addSqlParams2, function (err, result) {
if (err) {
console.log('[INSERT ERROR-] - ', err.message);
return;
}
});
})
await sleep(200);//每一个循环休息0.2s}
}
}
requestData();
}
});
}
//spider2();
// 创建两个定时任务,第一个任务执行spider函数爬取数据存到数据库中
// 第二个定时任务执行spider2函数,将数据库中的爬取数据 读取出来进行处理,添加地理坐标,再次存到数据库中,获得有地理坐标的数据
var runSchedule =function (cb) {
// cron风格的配置:每天上午两点05分执行一次
schedule.scheduleJob('0 5 2 * * *', function () {
var time=new Date();
var year=time.getFullYear();
var day=time.getDate();
var month=time.getMonth()+1;
console.log('spider定时任务执行一次'+year+'年'+month+'月'+day+'日');
cb && cb();
});
}
//可以按照cron的格式设置
var runSchedule2 =function (cb) {
// cron风格的配置:每天上午2.10点执行一次
schedule.scheduleJob('0 10 2 * * *', function () {
var time=new Date();
var year=time.getFullYear();
var day=time.getDate();
var month=time.getMonth()+1;
console.log('spider2定时任务执行一次'+year+'年'+month+'月'+day+'日');
cb && cb();
});
}
runSchedule(spider);
runSchedule2(spider2);
console.log('定时任务已启动');
三、启动程序
在文件夹空白处,按住键盘ctrl键+鼠标右键 打开cmd命令行:
输入
cnmp i //安装依赖 也就是开头说的库
node spider //安装完所有依赖,执行程序,不关闭cmd就会一直每天爬取了
四、数据表格式