前言:我最近对国家人口走势比较感兴趣,想看看未来人口发展趋势之类的,看了很多文章都不是我想要的东西,最后发现国家数据 这个网站,我想要的数据它都有,所有我想把数据全部爬下来,然后自己再图形化它。
下面记录下用node.js爬取数据的过程
先F12看看它的接口
const axios = require('axios');
const commonCfg = {
method: 'get',
url: 'http://data.stats.gov.cn/easyquery.htm',
headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)' }
}
let params = {
m: 'QueryData',
dbcode: 'hgnd',
rowcode: 'zb',
colcode: 'sj',
wds: '[]',
k1: Date.now() + '',
}
/**总人口 男女 城乡 */
async function getTotal(year) {
const response = await axios({
...commonCfg,
params: { ...params, dfwds: `[{"wdcode":"sj","valuecode":"${year}"}]` }
})
let result = []
const { datanodes } = response.data.returndata
datanodes.forEach(item => {
result.push(item.data.data)
})
return dealRes(result)
}
/**格式化 */
function fmtNum(num) {
return Math.floor(num * 10000)
}
/**result[0]总人口,result[1]男,result[2]女,result[3]城,result[4]乡,*/
function dealRes(result) {
return {
total: fmtNum(result[0]),
manCount: fmtNum(result[1]),
womanCount: fmtNum(result[2]),
cityCount: fmtNum(result[3]),
villageCount: fmtNum(result[4]),
}
}
// 执行
getTotal(2011).then(res => {
console.log(res)
})
node 启动~~
我又去搜索了一圈,发现有人用python爬过这个网站并完整的记录下来了, Python爬取国家统计局相关数据(原创) 把这位大佬的代码看了一遍,我知道问题在哪了
我们是每一次都进行一次请求,得到数据后就断了,如果要进行搜索,我们必须要建立一个对话(Session),然后在这个对话中把dfwds改成上图中的内容就可以成功获取。
原来这样! 搜索一圈找到 axios-cookiejar-support 这个包,重新改造,把出生率和死亡率也爬出来了, 区别就在valuecode字段,
- 总人口 valuecode=A0301
- 出生率 valuecode=A0302
其他诸如Gdp、居民消费水平,工业、农业数据 也都是valuecode值不同。
直接上完整代码吧
const axios = require('axios');
const tough = require('tough-cookie');
const axiosCookieJarSupport = require('axios-cookiejar-support').default;
axiosCookieJarSupport(axios);
const cookieJar = new tough.CookieJar();
axios.defaults.jar = cookieJar;
axios.defaults.withCredentials = true;
/**
* 爬取目标网址 http://data.stats.gov.cn/easyquery.htm?cn=C01
* 参考python爬虫 https://www.jianshu.com/p/9827a052da91
* 上边的依赖主要是为了建立一个session
* 每一次真实请求请都要先请求一次以建立session 传参:总人口的valuecode=A0301 出生率的valuecode=A0302
*/
const commonCfg = {
method: 'get',
url: 'http://data.stats.gov.cn/easyquery.htm',
headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)' }
}
let params = {
m: 'QueryData',
dbcode: 'hgnd',
rowcode: 'zb',
colcode: 'sj',
wds: '[]',
k1: Date.now() + '',
}
/**总人口 请求前建立session */
async function initTotal(year) {
await axios({
...commonCfg,
params: { ...params, dfwds: '[{"wdcode":"zb","valuecode":"A0301"}]' }
})
return await getTotal(year)
}
/**总人口 男女 城乡 */
async function getTotal(year) {
const response = await axios({
...commonCfg,
params: { ...params, dfwds: `[{"wdcode":"sj","valuecode":"${year}"}]` }
})
let result = []
const { datanodes } = response.data.returndata
datanodes.forEach(item => {
result.push(item.data.data)
})
return dealRes(result)
}
/**格式化 */
function fmtNum(num) {
return Math.floor(num * 10000)
}
/**result[0]总人口,result[1]男,result[2]女,result[3]城,result[4]乡,*/
function dealRes(result) {
return {
total: fmtNum(result[0]),
manCount: fmtNum(result[1]),
womanCount: fmtNum(result[2]),
cityCount: fmtNum(result[3]),
villageCount: fmtNum(result[4]),
}
}
/**出生率 死亡率 请求前建立session */
async function initRate(year) {
await axios({
...commonCfg,
params: { ...params, dfwds: '[{"wdcode":"zb","valuecode":"A0302"}]' }
})
return await getRate(year)
}
/**出生率 死亡率 */
async function getRate(year) {
const response = await axios({
...commonCfg,
params: { ...params, dfwds: `[{"wdcode":"sj","valuecode":"${year}"}]` }
})
let result = []
const { datanodes } = response.data.returndata
datanodes.forEach(item => {
result.push(item.data.data)
})
return {
bornRate: result[0],
deathRate: result[1]
}
}
/**执行 */
const YEAR = 2011
Promise.all([initTotal(YEAR), initRate(YEAR)]).then(res => {
const sql = { year: YEAR, ...res[0], ...res[1] }
console.log(sql)
});
打印出
获取到了总人口、男女人口、城乡人口、出生率、死亡率 完美 ؏؏☝ᖗ乛◡乛ᖘ☝؏؏