node.js 爬取国家人口数据

699 阅读2分钟

前言:我最近对国家人口走势比较感兴趣,想看看未来人口发展趋势之类的,看了很多文章都不是我想要的东西,最后发现国家数据 这个网站,我想要的数据它都有,所有我想把数据全部爬下来,然后自己再图形化它。


下面记录下用node.js爬取数据的过程

先F12看看它的接口

感觉很简单嘛,就2 个变量dfwds和k1, valuecode就是年份参数,那个k1猜一下就知道是时间戳,直接撸代码:

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'[]',
  k1Date.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'[]',
  k1Date.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)
});

打印出

获取到了总人口、男女人口、城乡人口、出生率、死亡率 完美 ؏؏☝ᖗ乛◡乛ᖘ☝؏؏