【python】获取高德地图省市区县列表

摘要:
项目中需要用省市区来进行检索,原想高德地图肯定会有API来获得这些数据,结果没有找到,有一个接口好像可以用,但是会附带大量的边界坐标点。所以就不如自己把高德的省市区列表扒下来,自己写接口来完成这个功能。看到高德地图的js的demo里面有这样的展示页面:http://lbs.amap.com/api/javascript-api/example/u/2001-2/,所以我就直接利用它来分析。id=3556',}然后是根据省名获取市列表的函数:defgetCity:print"Province-˃"+provinceurl="http://restapi.amap.com/v3/config/district?

项目中需要用省市区来进行检索,原想高德地图肯定会有API来获得这些数据,结果没有找到,有一个接口好像可以用,但是会附带大量的边界坐标点。

所以就不如自己把高德的省市区列表扒下来,自己写接口来完成这个功能。

看到高德地图的js的demo里面有这样的展示页面:http://lbs.amap.com/api/javascript-api/example/u/2001-2/,所以我就直接利用它来分析。

1. 省列表

省的列表是直接写死在这个界面里的,所以我也照搬,把省都直接写死:

provinceList = ['北京市', '天津市', '河北省', '山西省', '内蒙古自治区', '辽宁省', '吉林省','黑龙江省', '上海市', '江苏省', '浙江省', '安徽省', '福建省', '江西省', '山东省','河南省', '湖北省', '湖南省', '广东省', '广西壮族自治区', '海南省', '重庆市','四川省', '贵州省', '云南省', '西藏自治区', '陕西省', '甘肃省', '青海省', '宁夏回族自治区', '新疆维吾尔自治区', '台灣', '香港特别行>政区', '澳门特别行政区'];

2. 市列表

从市列表开始,就要扒高德地图的接口了,首先模仿浏览器的访问设置几个Http头:

send_headers ={
        'Accept':'*/*',
        'Accept-Encoding':'gzip, deflate, sdch',
        'Accept-Language':'zh-CN,zh;q=0.8',
        'Connection':'keep-alive',
        'Host':'restapi.amap.com',
        'Referer':'http://lbs.amap.com/fn/iframe/?id=3556',
}

然后是根据省名获取市列表的函数:

defgetCity(province):
    print "Province->" +province
    url = "http://restapi.amap.com/v3/config/district?subdistrict=1&extensions=all&level=province&key=608d75903d29ad471362f8c58c550daf&s=rsv3&output=json&callback=jsonp_" + getJsonP() + "_&keywords=" +province;
    data =getData(url)
    item = data['districts'][0];
    if item['citycode'] ==[]:
        item['citycode'] = ''save([item['citycode'], item['adcode'], item['name'], item['center'], item['level'], ''])
    for item in data['districts'][0]['districts']:
        save([item['citycode'], item['adcode'], item['name'], item['center'], item['level'], ''])
        while 1:
            try:
                getDistrict(item)
                break
            exceptException, e:
                print 'retry:' + item['name'] + "->" + str(e)

这里有跨域访问用的getJsonP、发起网络请求的getData、存数据库的save,这三个函数的具体实现一会再说,先看其它逻辑,高德服务端返回数据是长得这个样子的:

【python】获取高德地图省市区县列表第1张

districts域就是搜索的结果,因为这是按名称进行搜索,而不是id,所以很可能会搜出来多个结果,当然省名不会重,但一样得到的是一个JSONArray,所以用data['districts'][0]来得到省的信息,除了直辖市之外,省级单位的citycode都是空的,用item['citycode'] = ''给它一个空字符串做默认值,然后调用save方法把它存入数据库,在上图中也看到了,data['districts'][0]里面还有一个districts域,这里面就是所有市的信息,同样把它们存入数据库,然后针对每个市,去获取区的列表,这里有可能会出现网络问题,所以加上了失败重试。

下面依次来看上面几个关键方法的实现:

1)getJsonP:

跨域访问是通过jsonp回调的方式进行的,函数名都是jsonp_xxxxx_()的形式,这个xxxxx是一个变化的随机数字,我采用依次递增的形式来生成这个jsonp的数字:

jsonp = 9999
defgetJsonP():
    globaljsonp
    jsonp = jsonp + 1
    if (jsonp > 99999):
        jsonp = 10000
    return str(jsonp)

这里我保证这个数字是一个5位数(理论上几位都可以),因为在图里可以看到,返回值是jsonp_xxxxx_({aaa})的形式,我们要分析json串需要把前后没用的字符去掉,如果长度固定就很好删了。

2)getData:

发起网络请求并把返回的数据转成JSONObject:

defgetDataWithEx(url):
    req = urllib2.Request(url,headers=send_headers)
    r = urllib2.urlopen(req,timeout=30)

    if r.info().get('Content-Encoding') == 'gzip':
        buf =StringIO(r.read())
        f = gzip.GzipFile(fileobj=buf)
        data =f.read()
    else:
        data =r.read()
    return json.loads(data[13:-1])

defgetData(url):
    while 1:
        try:
            response =getDataWithEx(url)
            break
        exceptException, e:
            print 'retry:' + url + "with error " +str(e)
    return response

这里也加入了失败重试,一般的数据都要用gzip进行解码,但是我忘了是哪个了,好像是有一个区的数据很特别没有用gzip,所以这里要分开判断,getJsonP里面介绍了,返回的数据前后是写无用的字符,用data[13:-1]删掉。

3)save

这是往MySQL里存数据的函数,没有特殊的点需要介绍,直接上代码:

defsave(value):
    try:
        conn=MySQLdb.connect(host='www.xxx.com',user='xxx',passwd='xxx',port=3306,charset="utf8")
        conn.select_db('test')
        cur=conn.cursor()
        cur.execute("insert into amap(citycode, adcode, name, center, level, areacode) values(%s,%s,%s,%s,%s,%s)",value)
        conn.commit()
        cur.close()
        conn.close()
    exceptMySQLdb.Error,e:
        print "Mysql Error %d: %s" % (e.args[0], e.args[1])

3. 区列表

跟获取城市列表相似:

defgetDistrict(city):
    print "->City->" + city['name']
    url = "http://restapi.amap.com/v3/config/district?subdistrict=1&extensions=all&level=city&key=608d75903d29ad471362f8c58c550daf&s=rsv3&output=json&callback=jsonp_" + getJsonP() + "_&keywords=" + city['name']
    data =getData(url)
    for possible in data['districts']:
        if possible['adcode'] == city['adcode']:
            for item in possible['districts']:
                save([item['citycode'], item['adcode'], item['name'], item['center'], item['level'], ''])
                while 1:
                    try:
                        getBusiness(item)
                        break
                    exceptException, e:
                        print 'retry:' + item['name'] + "->" +str(e)
            break

和获取市列表稍微不同的是这里不能直接data['districts'][0]了,按市、区搜就有可能重名了,所以用城市的adcode来匹配,针对匹配上的市,遍历区的信息存入数据库,然后再针对区搜索商圈。

4. 商圈列表

跟获取市列表和获取区列表没有太大的区别:

defgetBusiness(district):
    print "->->District->" + district['name']
    url = "http://restapi.amap.com/v3/config/district?subdistrict=1&extensions=all&level=district&key=608d75903d29ad471362f8c58c550daf&s=rsv3&output=json&callback=jsonp_" + getJsonP() + "_&keywords=" + district['name']
    data =getData(url)
    for possible in data['districts']:
        if possible['adcode'] == district['adcode']:
            values=[]
            for item in possible['districts']:
                values.append((item['citycode'], item['adcode'], item['name'], item['center'], item['level'], item['areacode']))
saveAll(values)
            break

唯一不同的是直接用saveAll一次性存储所有的数据而不是一条条的save:

defsaveAll(values):
    try:
        conn=MySQLdb.connect(host='www.xxx.com',user='xxx',passwd='xxx',port=3306,charset="utf8")
        conn.select_db('test')
        cur=conn.cursor()
        cur.executemany("insert into amap(citycode, adcode, name, center, level, areacode) values(%s,%s,%s,%s,%s,%s)",values)
        conn.commit()
        cur.close()
        conn.close()
    exceptMySQLdb.Error,e:
        print "Mysql Error %d: %s" % (e.args[0], e.args[1])

关键的逻辑就都介绍完了,下面是头部库的导入和编码设置:

#-*- coding: utf-8 -*-#encoding=utf-8

importurllib2
importsys, json
from StringIO importStringIO
importgzip
importMySQLdb
importdatetime

reload(sys)
sys.setdefaultencoding('utf-8')

这里要说的一点是:不知道为什么编译器会报错说setdefaultencoding方法不存在,有这个错误的话不用理会,可以正常运行,如果不设置那么在数据库插入的时候会报下面的一个错误:

UnicodeEncodeError:'latin-1' codec can't encode character

最后是上述方法的调用:

starttime =datetime.datetime.now()
for province inprovinceList:
    getCity(province)
print 'over'endtime =datetime.datetime.now()
print (endtime - starttime).seconds

扒数据的时间很长,n多小时,我忘了具体是多久了,而且为了避免出错我是把所有省分成了好几段分别扒的。

如果不想自己扒数据,想直接得到省市区的数据,可以直接下载我转存的sql文件。

也可以临时使用我的接口(都已失效):

获取省列表:http://www.yxbilu.com/sites/tools/amap/province;

获取市列表:http://www.yxbilu.com/sites/tools/amap/city?adcode=110000(省的adcode);

获取区列表:http://www.yxbilu.com/sites/tools/amap/district?adcode=110100(市的adcode)。

免责声明:文章转载自《【python】获取高德地图省市区县列表》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇IDEA安装Gitgitlab介绍与操作下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

自动化测试学习路线

首先目前的话主要可以大的可以分为两个方向,要么是基于Java的自动化,要么是基于Python的自动化,很多做培训在培训的时候也是这样去划分,不过这个倒是不重要,归根结底都是为了解决问题的。 本文从3个面向去解答这个问题: 一、自动化测试的学习步骤; 二、自动化测试需要掌握的技术能力; 三、自动化测试的认识误区 首先要说的就是自动化测试的学习步骤 1. 做...

Python中使用中文

这个问题曾在我初学Python的时候令我头疼不已,尤其是目前我们因为各种包的原因还只能使用2.x的版本。在3.x中字符编码已经统一用Unicode了。 Python 默认支持的是ASCII字符,包含了英文字母大小写以及标点符号,用一枚字节表示。中文则使用两枚字节表示。 没兴趣的同学可以绕过这段… 有人可能要问了,我擦,为神马以前说一个汉字的精度越高字节越多...

jQuery jsonp(转载)

来源:https://www.jianshu.com/p/1efe671832e0 其他文章:https://www.cnblogs.com/chiangchou/p/jsonp.html jsonp本身是专为跨域而诞生的。早期开发者面对跨域没什么好办法,突然有人想到,既然引入js文件是不受跨域限制的,可以随意跨域引入,那么,动态引入一个带有你想要的数据...

Python代码中执行curl命令查询couchbase数据

最近在优化脚本时,发现要提前执行一段curl命令才行,实际在python中可以通过HTTP Library中requests方法就能实现,如 要执行的curl命令为 curl -v 'http://172.17.9.128:8091/pools/default/buckets/meta3/docs/8024028328' -u "XX:XX"     在...

python中的各个包的安装,用pip安装whl文件

在安装之前,一直比较迷惑究竟如何用,安装完后,发现竟然如此简单 首先我一般用的是python27,官网下载python27msi安装window7 64位后,已经自带了Pip 和 easy_install 但是却不晓得如何安装 whl目录, 经过搜索后发现,把pip和easy_install加入到环境变量中,这个应该不是难事,如下: 把Scripts这个...

Django入门学习(一)

想弄一个OJ的平台,所以想学点前端的语言用来写网页 发现python可以用来写网页,所以就借此机会正好学习Python了 个人感觉python的语法确实相比于C和java这些,都要简介不少,对于新手感觉是入门要简单些 但是自我感觉python有时候也是不习惯,因为可能习惯了java的这些语法吧 下面就记录一些自己学习的Django过程吧 ---------...