Python 爬取国家统计局相关数据

我们的目标网址:http://data.stats.gov.cn/easyquery.htm?cn=C01
里面可以查询国家统计局发布的各种数据,这里我们针对人口进行爬取,其它项方法都是一样。
提示:看之前需要了解 HTTP 协议和 XMLHttpRequest 方法。
推荐用谷歌浏览器
首先进入下面这个页面:

图 1

然后按 F12,出现下面这个页面:
图 2

再次刷新页面,看看有什么新的东西:
图 3

注意图中选择 XHR
然后看到有三条记录
按顺序点开看看:
图 4

可以看到里面有一些信息:
Request URL: 请求的网址
Request Method: 请求方法
Status Code: 状态码等等
在 Headers 里面下滑到最后面,看到以下几个字段:
图 5

这个 Form Data 里面的东西很重要,以后要用到,现在只要记得有这个东西就行。然后看 m 对应着 getTree,然后应该可以猜到这个请求应该是获取一些目录结构的。
然后我们直接看第三个 (你也可以看看第二个)
图 6

看第三个的 m 对应的 QueryData,其实这里表示这是用来获取数据的,如何验证呢,我们点开 Preview (预览),这里你可以看见请求过来的信息。
图 7

可以看见请求过来的是一个 json 格式 (简单来说就是字典里面套字典的一种格式)
然后可以看到非常清楚的信息对应着网页上的数据
所以现在只要我们请求这个地址,就会给我们返回这些信息,那么这个地址是什么。这时,我们要回到 Headers 里面查看
图 8

在 Request URL:后面就是我们要请求的地址,还可以看到这是用 get 方法获取的。
仔细分析这个 url,我把这个 url 拆成 2 个部分,一个是问号之前另一个是问号之后
图 9

懂 http 协议的应该都明白,问号之后的是传的一些参数给服务器的,突然发现问号之后就是一个 m,好像在哪见过不是吗,滑倒最下面
图 10

其实对应的就是上面那些参数,这里我只解释一个 k1 是什么东西 (因为其它的我还没有完成弄明白),k1 后面跟的数字其实是一个时间戳 (不懂的百度搜下就明白啦)
在 Python 里面可以用 time 库来获取

import time
ntime = int(round(time.time() * 1000))

来段代码结合来说:

# 我采用requests库
import requests
import time

# 用来获取 时间戳
def gettime():
return int(round(time.time() * 1000))

if name == main:
# 用来自定义头部的
headers = {}
# 用来传递参数的
keyvalue = {}
# 目标网址(问号前面的东西)
url = http://data.stats.gov.cn/easyquery.htm

<span class="hljs-comment"># 头部的填充</span>
headers[<span class="hljs-string">'User-Agent'</span>] = <span class="hljs-string">'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14) '</span> \
                        <span class="hljs-string">'AppleWebKit/605.1.15 (KHTML, like Gecko) '</span> \
                        <span class="hljs-string">'Version/12.0 Safari/605.1.15'</span>

<span class="hljs-comment"># 下面是参数的填充,参考图10</span>
keyvalue[<span class="hljs-string">'m'</span>] = <span class="hljs-string">'QueryData'</span>
keyvalue[<span class="hljs-string">'dbcode'</span>] = <span class="hljs-string">'hgnd'</span>
keyvalue[<span class="hljs-string">'rowcode'</span>] = <span class="hljs-string">'zb'</span>
keyvalue[<span class="hljs-string">'colcode'</span>] = <span class="hljs-string">'sj'</span>
keyvalue[<span class="hljs-string">'wds'</span>] = <span class="hljs-string">'[]'</span>
keyvalue[<span class="hljs-string">'dfwds'</span>] = <span class="hljs-string">'[]'</span>
keyvalue[<span class="hljs-string">'k1'</span>] = str(gettime())

<span class="hljs-comment"># 发出请求,使用get方法,这里使用我们自定义的头部和参数</span>
r = requests.get(url, headers=headers, params=keyvalue)
<span class="hljs-comment"># 打印返回过来的状态码</span>
<span class="hljs-keyword">print</span> r.status_code
<span class="hljs-comment"># 打印我们构造的url</span>
<span class="hljs-keyword">print</span> r.url
<span class="hljs-comment"># 打印返回的数据</span>
<span class="hljs-keyword">print</span> r.text

好像没有什么问题,但是如果你仔细看看返回过来的数据就会发现有问题,根本不是我们想要的数据,虽然也是 json 结构,但是里面的数据完全是错的。所以如何获取到我们想要的呢,返回到谷歌浏览器,进行如下操作。


图 11

先在如上的页面刷新一次,然后下面会有三条记录,然后依次点击人口 -> 总人口,然后又会多出两条记录。


图 12

很明显,多出来的第一条是第一次点击得到,多出来的第二条是第二次点击得到,由于我们是想查看总人口,也就是第二次点击传来的数据,所以点击多出来的第二条,查看它的详细信息。
图 13

滑到最下面,可以看到 dfwds 字段有东西了,之前的都没有的 (参考图 10),原来还要传参数。修改代码:

# 我采用requests库
import requests
import time

# 用来获取 时间戳
def gettime():
    return int(round(time.time() * 1000))

if __name__ == '__main__':
    # 用来自定义头部的
    headers = {}
    # 用来传递参数的
    keyvalue = {}
    # 目标网址(问号前面的东西)
    url = 'http://data.stats.gov.cn/easyquery.htm'

    # 头部的填充
    headers['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14) ' \
                            'AppleWebKit/605.1.15 (KHTML, like Gecko) ' \
                            'Version/12.0 Safari/605.1.15'

    # 下面是参数的填充,参考图10
    keyvalue['m'] = 'QueryData'
    keyvalue['dbcode'] = 'hgnd'
    keyvalue['rowcode'] = 'zb'
    keyvalue['colcode'] = 'sj'
    keyvalue['wds'] = '[]'
    # keyvalue['dfwds'] = '[]'
    # 上面那个修改成下面这个
    keyvalue['dfwds'] = '[{"wdcode":"zb","valuecode":"A0301"}]'
    keyvalue['k1'] = str(gettime())

    # 发出请求,使用get方法,这里使用我们自定义的头部和参数
    r = requests.get(url, headers=headers, params=keyvalue)
    # 打印返回过来的状态码
    print r.status_code
    # 打印我们构造的url
    print r.url
    # 打印返回的数据
    print r.text

再来看看结果
如果耐心点可以看出,我们获取了从 2008 到 2017 的所有数据,然后我们就可以从里面进行解析数据进行存储来。但是如果要找 2000 年的呢,看下面。


图 14

从上图可以看见这个页面还提供搜索功能,于是我们也可以进行搜索。比如 2000 年。


图 15

点击确定
图 16

然后我们发现又多了一条记录,然后查看 Headers 里面,滑到最下面看,dfwds 的内容又变了,于是如果我们想要用程序模拟搜索功能,把代码中的 dfwds 改成图片里面的就可以了呢。我帮你们已经测试过了,会返回数据,但是数据会跟第一次一样,有数据,但不是我们想要的,那怎么办。

经过我几个小时到摸索,我终于搞出来了,针对于目前的情况,我们是每一次都进行一次请求,得到数据后就断了,如果要进行搜索,我们必须要建立一个对话 (Session),然后在这个对话中把 dfwds 改成上图中的内容就可以成功获取。
代码修改:

# 我采用requests库
import requests
import time

# 用来获取 时间戳
def gettime():
    return int(round(time.time() * 1000))

if __name__ == '__main__':
    # 用来自定义头部的
    headers = {}
    # 用来传递参数的
    keyvalue = {}
    # 目标网址(问号前面的东西)
    url = 'http://data.stats.gov.cn/easyquery.htm'

    # 头部的填充
    headers['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14) ' \
                            'AppleWebKit/605.1.15 (KHTML, like Gecko) ' \
                            'Version/12.0 Safari/605.1.15'

    # 下面是参数的填充,参考图10
    keyvalue['m'] = 'QueryData'
    keyvalue['dbcode'] = 'hgnd'
    keyvalue['rowcode'] = 'zb'
    keyvalue['colcode'] = 'sj'
    keyvalue['wds'] = '[]'
    keyvalue['dfwds'] = '[{"wdcode":"zb","valuecode":"A0301"}]'
    keyvalue['k1'] = str(gettime())

    # 发出请求,使用get方法,这里使用我们自定义的头部和参数
    # r = requests.get(url, headers=headers, params=keyvalue)
    # 建立一个Session
    s = requests.session()
    # 在Session基础上进行一次请求
    r = s.get(url, params=keyvalue, headers=headers)
    # 打印返回过来的状态码
    print r.status_code
    # 修改dfwds字段内容
    keyvalue['dfwds'] = '[{"wdcode":"sj","valuecode":"2000"}]'
    # 再次进行请求
    r = s.get(url, params=keyvalue, headers=headers)
    # 此时我们就能获取到我们搜索到的数据了
    print r.text

至此一次完整获取数据的过程就结束了,上面代码进行修改就可以获取很多东西的数据,当然如果弄清各个字段的意思就更好了。如有错误请及时告知。

      </div>

转自:https://www.jianshu.com/p/9827a052da91

  • 1
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值