伟大的国家统计局为我们提供了省市区的信息[1],可惜不是json格式的,并不能真正用起来。为了得到我们所需要格式化的数据,笔者开发了一个将txt格式的省市区转化为json格式的python脚本。(结尾有小惊喜哦 _ )
操作系统:ubuntu mate[2],python版本:python3.4,编辑器:pluma。
国家统计局网站上的省市区信息,代码中都没有层级结构,用BeautifulSoup[3]解析也是浪费时间,笔者直接把它复制粘贴到了city.txt中。
下面开始开发脚本:
定义模型
省市区本身就是三个现成的对象,不难想到:
# province of china
class Province:
def __init__(self, code, name):
self.code = code
self.name = name
# city of province
class City:
def __init__(self, code, name):
self.code = code
self.name = name
# coutry of city
class Country:
def __init__(self, code, name):
self.code = code
self.name = name
对于省市而言,它们还有各自的下属行政区,所以要加上一个sub属性来把它们的下属囊括进来。
class Province:
def __init__(self, code, name):
# ...
self.sub = []
class City:
def __init__(self, code, name):
# ...
self.sub = []
这样,我们的省市区模型就算初步定义完成了。
创建方法
有了模型还不够,只有加上合适的方法,才能显示出面向对象的优势。
我们需要一个返回对象的方法 __repr__()
,这是一个常见的方法,只要我们提供对象的名称,就能返回必要的对象信息,便于开发和调试。
class Province:
# ...
def __repr__(self):
return '''{"code":%r ,"name": %r, "sub":%r}\n''' % (self.code, self.name, self.sub)
class City:
# ...
def __repr__(self):
return '''{"code":%r ,"name": %r, "sub":%r}\n''' % (self.code, self.name, self.sub)
class Country:
# ...
def __repr__(self):
return '''{"code":%r, "name": %r}\n''' % (self.code, self.name)
当所有的省级行政区构建完成时,输出这个对象的字符串形式就是最终的json数据。为了保证json的格式,我们的 __repr__()
方法是自定义的,输出的结果既没有类的名称,也没有 用<
和 >
括起来。
为了构建一个完整的省市级行政区,我们还需要一种归属的方法,将下属市和区加到sub数组里。可以用数组的 append()
方法来实现:
class Province:
# ...
def consist(self, city):
self.sub.append(city)
class City:
# ...
def consist(self, country):
self.sub.append(country)
此外,还需要一个函数来判断行政区的等级。简单观察一下city.txt,就不难找到这个规律。
所有的省级行政区的代码结尾都是
0000
,所有的地级市的代码结尾都是00
,其它都是区县级的行政区划。
举个栗子:江苏的代码是:320000,南京的代码是:320100,秦淮区的代码是:320104。
所以,笔者写了一个根据结尾的0来判定级别的方法:
# judge the type by code
def zero(n):
i = 1
if n <= 0:
return 0
while n % i == 0:
i *= 10
return i/10
解析文本
接下来,就按行读取city.txt中的数据,简单粗暴见效快。
def get_data(filename):
arr = []
# open the city.txt
with open(filename, "r", encoding="utf-8") as read:
print("file has been open.")
for line in read:
arr.append(line.strip())
print("reading finished")
return arr
这里唯一值得注意的是:city.txt的编码是什么,打开文件指定的编码就是什么。这里的编码是:utf-8。
输出json
还是要观察city.txt,除了省级行政区是顶行的,其它的都有数量不等的空格。get_data()
方法得到的实际上是一个数组,其中的元素是类似这样110100 市辖区
。从中我们也可以看到空格的存在。空格的utf-8编码是 \u3000
,使用 strip("\u3000")
来除去首尾的空格。然后将数字保存为code,有效字符保存为name。然后根据 zero()
方法返回的结果构建相应的对象。最后将省级的对象输出就得到了省市区json数据。
最后,揭晓这个小惊喜:源代码和抓取到的json数据可以到我的 github 上获取。链接:https://github.com/zhancongc/city_parse
附录
- 统计局网址:http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/201703/t20170310_1471429.html
- 本程序在ubuntu mate下运行正常,输出正常;window 10下运行,输出的中文会乱码,原因尚不明确。
- Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库。它能够通过你喜欢的转换器实现惯用的文档导航、查找、修改文档的方式。