美文网首页Python精选python爬虫小记
Python爬取国家统计局相关数据(原创)

Python爬取国家统计局相关数据(原创)

作者: 3ni | 来源:发表于2018-11-09 15:10 被阅读467次

    我们的目标网址: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'
    
        # 头部的填充
        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['k1'] = str(gettime())
    
        # 发出请求,使用get方法,这里使用我们自定义的头部和参数
        r = requests.get(url, headers=headers, params=keyvalue)
        # 打印返回过来的状态码
        print r.status_code
        # 打印我们构造的url
        print r.url
        # 打印返回的数据
        print 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
    

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

    相关文章

      网友评论

        本文标题:Python爬取国家统计局相关数据(原创)

        本文链接:https://www.haomeiwen.com/subject/jkzgxqtx.html