利用Python爬虫,只需要会requests + re 即可抓取中国国家统计局70w+城乡数据信息

技术路线:requests + re正则表达式

初始网站:http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/index.html

爬虫信息:2009年统计用区划代码和城乡划分代码,

爬取前用 http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/index.html/robots.txt  Robots协议查看,发现网站并未限制爬虫。

数据量:70w+

所用Python版本:Python3.5

源代码如下:

import re
import requests
import operator
from functools import reduce
import csv

class TongJi(object):
    def GetUrls1(self):
        url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/index.html'
        kv = {'user-agent': 'Mozilla/5.0'}
        r = requests.get(url, headers=kv)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        pattern = re.compile("<a href='(.*?)'>")
        result = list(set(re.findall(pattern, r.text)))
        for i in result:
            yield i

    def GetUrls2(self):
        result1 = []
        for i in self.GetUrls1():
            try:
                url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/' + i
                kv = {'user-agent': 'Mozilla/5.0'}
                r = requests.get(url, headers=kv)
                r.raise_for_status()
                r.encoding = r.apparent_encoding
                pattern = re.compile("<a href='(.*?)'>")
                result = list(set(re.findall(pattern, r.text)))
                result1.append(result)
                result2 = reduce(operator.add, result1)
            except:
                print(url, '爬取失败')
                continue
        for i in result2:
            yield i

    def GetUrls3(self):
        result1 = []
        for i in self.GetUrls2():
            try:
                url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/' + i
                kv = {'user-agent': 'Mozilla/5.0'}
                r = requests.get(url, headers=kv)
                r.raise_for_status()
                r.encoding = r.apparent_encoding
                pattern = re.compile("<a href='(.*?)'>")
                result = list(set(re.findall(pattern, r.text)))
                result1.append(result)
                result2 = reduce(operator.add, result1)
                result2 = reduce(operator.add, result1)
            except:
                print(url, '爬取失败')
                continue
        for i in result2:
            yield i

    def GetUrls4(self):
        result1 = []
        for i in self.GetUrls3():
            try:
                url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/' + i[3:5] + '/' + i
                kv = {'user-agent': 'Mozilla/5.0'}
                r = requests.get(url, headers=kv)
                r.raise_for_status()
                r.encoding = r.apparent_encoding
                pattern = re.compile("<a href='(.*?)'>")
                result = list(set(re.findall(pattern, r.text)))
                result1.append(result)
                result2 = reduce(operator.add, result1)
            except:
                print(url, '爬取失败')
                continue
        for i in result2:
            yield i

    def GetUrls5(self):
        result1 = []
        for i in self.GetUrls4():
            try:
                url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/' + i[3:5] + '/' + i[5:7] + '/' + i
                kv = {'user-agent': 'Mozilla/5.0'}
                r = requests.get(url, headers=kv)
                r.raise_for_status()
                r.encoding = r.apparent_encoding
                pattern = re.compile("<a href='(.*?)'>")
                result = list(set(re.findall(pattern, r.text)))
                result1.append(result)
                result2 = reduce(operator.add, result1)
            except:
                print(url, '爬取失败')
                continue
        for i in result2:
            yield i

    def GetDates(self):
        Dates1 = []
        for i in self.GetUrls5():
            try:
                url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/' + i
                kv = {'user-agent': 'Mozilla/5.0'}
                r = requests.get(url, headers=kv)
                r.raise_for_status()
                r.encoding = r.apparent_encoding
                html = r.text
                pattern = re.compile(r"<tr class='villagetr'><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td></tr>")
                Date = re.findall(pattern, html)
                Dates1.append(Date)
                Dates = reduce(operator.add, Dates1)
            except:
                print(url, '爬取失败')
                continue
        for i in Dates:
            yield i

    def DateImport(self):
        headers = ['代码', '城乡分类', '名称']
        with open('数据1.csv', 'w') as f:
            f_csv = csv.writer(f)
            f_csv.writerow(headers)
            for i in self.GetDates():
                f_csv.writerows(i)

tongji = TongJi()
tongji.DateImport()

代码解析:

1.首先导入我们需要的5个模块,这5个模块均为Python3.5自带的,所以不需要pip下载。

2.创建 Class TongJi 类,把它当做一个项目。接下来就是编写类中的函数。

3.GetUrls1()函数返回一个生成器类型(用关键字yield定义,读者可自行百度查看有关该关键字的运用!),里面的元素是列表result中的元素,而result是什么呢? result = list(set(re.findall(pattern, r.text))) 是集合元素 set(re.findall(pattern, r.text)) 转化而成的列表。set(re.findall(pattern, r.text)) 是 re.findall(pattern, r.text) 转化而成的集合,那么re.findall(pattern, r.text)又是什么呢? re.findall()是正则表达式中的一个函数,返回一个列表。参数 pattern = re.compile("<a href='(.*?)'>") 是一个匹配模式,r.text 是一个由 r = requests.get(url, headers=kv) 获取的Html内容,相当于在网站任一个空白地点击右键->查看网页源代码,弹出的网站内容。我们的

url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/index.html'

kv = {'user-agent': 'Mozilla/5.0'}

因为有些网站设置反爬虫,我们要将网站的头部字段改为 kv 来模拟浏览器登录,才可以获取到Html内容,即 r.text 。在刚刚查看网页源代码的网站中,我们发现,你想打开的各省份的链接包含在 <a href='...'>这个标签中,我们用正则表达式re.compile()函数  pattern = re.compile("<a href='(.*?)'>")即可得到获得各省份链接的匹配模式,用re.findall()函数找到所有一样的匹配模式返回一个列表,但是!返回的列表中同一个链接元素会出现2次,所以我们先用集合set()将重复元素删去,只保留一个,然后再用list()函数转换回列表形式。此时我们可以获得 形式为  ['11.html','12.html',.......]   这样一个列表。

4.为什么要获得上述的列表呢?因为我们要循环访问每个省的网页链接,而每个省下面又有每个市级的网页链接,每个市级的网页下面又有每个区的网页链接,每个区下面又有每个街道办事处的网页链接,最后进入每个街道办事处网页才是我们需要爬取的信息。所以我们总共要进行5次循环才能获得我们需要的信息。

5.查看上述列表,我们知道,我们并未完整的获得每个省的网页链接,但是我们获得了每个省网页链接的最后一部分字符串内容,我们只需要用一个循环,获得

url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/' + i 

此时的 i 是每个省级网站的最后部分内容。形式为 '11.html'

即可得到每个省完整的网页链接。爬取各省完整链接,又得到一个类似3.中得到的列表 ['11/11.html','11/12.html',.......] ,元素为每个市级中最后一部分的字符串内容。我们再次用循环,获得

url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/' + i 

此时的 i 是每个市级网站的最后部分内容。形式为 '11/11.html'

即可得到每个市完整的网页链接。循环下去,爬取各市完整链接,获得各街道办事处网站最后一部分的字符串内容,但是!!此时如果我们用 

url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/' + i 

此时的 i 是每个街道办事处网站的最后部分内容,形式为 01/110101.html

用该链接爬取的时候,是爬取不到的。为什么??

因为我们进入街道办事处的原网站,会发现网址是这样的

http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/11/01/110101.html

而我们获得的最后部分内容,即 i  的形式是 01/110101.html,所以如果我们用

url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/' + i

则url会变成是 http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/01/110101.html 这种形式,

我们比较原网站,发现在   '2009/01/'  里少了   '11/'  所以我们 GetUrls4() 函数中用的是

url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/' + i[3:5] + '/' + i

相当于 把少了的 '11/' 补上。同理 GetUrls5() 函数中用的是

url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2009/' + i[3:5] + '/' + i[5:7] + '/' + i

爬取各区完整链接,爬取各街道办事处完整链接,最后在各街道办事处网站爬取的是  代码、城乡、名称 三个信息,GetDates() 函数即返回一个元素为元组的列表,形式为 

[('110101001001','111','多福巷社区居委会'),('110101001002','111','银闸社区居委会'),...]


6.最后用DateImport()函数将上述获得的列表数据依次导入 数据1.csv 文件中。


7.有些初学读者对程序中的一些语句不理解,可以自行百度相关函数用法。


8.观察我们的原始网址,可以发现。在 2009 处改成 2010 或 2011 -2018 ,有各年份的统计数据。此处有兴趣的朋友可以用类似的方法写个循环,爬取2009-2018的所有城乡数据,不过这时我们爬取的数据量就很大了,要导入到SQL数据库中。有兴趣的朋友可以查阅相关资料试一试。提醒一下,爬取的时间可能要挺久!






猜你喜欢

转载自blog.csdn.net/weixin_42060681/article/details/80093438