python爬虫:地理编码

背景音乐:


背景

平时在做数据分析的时候,我们往往只能拿到地址信息,并不方便直接进行可视化。

我们需要将地址转成经纬度坐标,国内的高德、百度等地图服务商们都有提供现成的API接口,方便我们直接调用。

高德提供的Web服务


高德API

以高德为例,查看官方文档里的地理/逆地理编码部分:

请求参数

请求参数

官方文档提供了详细的说明,点赞!

可以看到,必要的参数只有key和address,其他参数都是可选的。

个人建议地址字符串前直接加上city,这样能定位得更加准确。

如何申请key可以参考文章高德地图_获取KEY的方法

返回参数

返回参数

大赞高德的说明文档,数据结构一目了然。

可以看到,发起请求后,会收到json格式的数据,里面包含了很多信息。

其中,geocoders是一个列表,里面包含了若干个较匹配的结果,按相关性排序。

大多数情况下高德解析得都准的,所以我们挑第一个数据,里面的location值正式我们要的。


地理编码

环境:python 2.7
系统:macOS 10.13.1
模块:requests

单地理编码

python脚本如下:

import requests


# 地理编码函数
def geocode(address):
    url = 'http://restapi.amap.com/v3/geocode/geo'
    params = {
        'address':address, 
        'key':'你的key', 
    }
    try:
        res = requests.get(url, params, timeout=10)
        location = res.json()['geocodes'][0]['location']
        lng, lat = map(float, location.split(','))
    except Exception, e:
        print e
        print 'address: {0:10s} can\'t be geocoded.'.format(address)
        lng = lat = None
    return lng, lat

# 处理正常地址
print geocode('上海市浦东区世纪大道1号')
# (121.500836, 31.239135)

# 处理异常地址
print geocode('几百斤鸭送到巴拿马')
# list index out of range
# address: 几百斤鸭送到巴拿马 can't be geocoded.
# (None, None)

脚本正确地解析出了给定地址的经纬度,对于我乱填的地址也做了正确的提示。


批量地址编码

如果要解析的地址比较多,最好按照官方文档所示的格式来进行批量请求。

毕竟每个key都有调用数量的限制(可以查阅流量限制说明),用for循环太浪费了。

截止到我发文章的时刻,一次请求最多同时支持10 个地址(用"|"分割)。

python脚本如下:

import requests


# 批量地理编码
def geocode_batch(address_list):
    location_list = []

    num_reqs = len(address_list) // 10 + 1
    for req_index in range(num_reqs):
        sl = slice(req_index * 10, (req_index + 1) * 10)
        address_picked = address_list[sl]  # 用slice提取列表元素
        address = '|'.join(address_picked)  # 用“|”拼接地址
        url = 'http://restapi.amap.com/v3/geocode/geo'
        params = {
            'address':address, 
            'key':'你的key', 
            'batch':True  # 要传batch参数
        }

        try:
            res = requests.get(url, params, timeout=10)
            for add, geo in zip(address_picked, res.json()['geocodes']):
                if geo['location']:  # 当地址错误时,该地址的location为空
                    location = map(float, geo['location'].split(','))
                else:
                    print 'address: {} can\'t be geocoded.'.format(add)
                    location = [None] * 2  # 异常值用None代替
                location_list.append(location)
        except Exception, e:
            print e
            location_list += [[None, None]] * len(address_picked)

        # 打印进度
        print req_index + 1, '/', num_reqs, 'done!'  

    print 'all done!'
    return location_list


# 处理正常地址列表,11个地址将会分两次请求(10+1)
address_list = [
    '上海市浦东区世纪大道1号',
    '上海虹桥火车站',
    '上海浦东国际机场',
    '上海市复旦大学',
    '上海市同济大学',
    '上海市蔚来汽车有限公司',
    '北京市海淀区学院路30号',
    '北京市奥林匹克森林公园',
    '北京市王府井大街',
    '北京市簋街',
    '北京市清华大学'
]
print geocode_batch(address_list)
# 1 / 2 done!
# 2 / 2 done!
# all done!
# [[121.500836, 31.239135],
#  [121.31895, 31.194022],
#  [121.807559, 31.140815],
#  [121.506998, 31.298877],
#  [121.221467, 31.28835],
#  [121.170009, 31.282628],
#  [116.355288, 39.987847],
#  [116.406004, 40.025139],
#  [116.41131, 39.912619],
#  [116.407526, 39.90403],
#  [116.316533, 40.000727]]

# 当列表中有异常的地址
address_list = [
    '北京市海淀区学院路30号',
    '快乐多一点',
    '北京市簋街'
]
print geocode_batch(address_list)
# address: 快乐多一点 can't be geocoded.
# 1 / 1 done!
# all done!
# [[116.355288, 39.987847], 
#  [None, None], 
#  [116.407526, 39.90403]]

测试了两个用例,脚本正确地对异常的地址进行了处理。


后记

百度地图API和高德地图API的对比

从我这一年多的使用经验来看,我一定会推荐用高德地图API。

三方面原因:

  1. 服务配额(日调用量上限)
    一般有两种类型的用户——个人型和企业型,这两种用户的服务配额是不同的。但无论是对于哪类用户,百度提供的服务配额量都比高德的要少很多,如果请求量较大的话,百度很有可能不能满足你的需求。

  2. 坐标加密
    高德提供的坐标是火星坐标(GCJ-02坐标,又称国测局坐标,谷歌、腾讯和高德都在用这个坐标体系),而百度有自己的坐标系,提供的坐标是加密过的坐标,并且不提供逆转服务,这个就很蛋疼了,这意味着如果将你的坐标投影在任何除了百度以外的地图上,都会偏离其真实的位置,以前我因为这个被坑惨了……详情可参考国内各地图API坐标系统比较与转换

  3. 开发者文档
    这个看体验,我问过的开发者都表示,高德甩百度好几条街。开发者文档友好不友好,谁用谁知道……

最后,感谢百度地图API,让我内心变得强大 T T

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,079评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,094评论 4 62
  • 用到的组件 1、通过CocoaPods安装 2、第三方类库安装 3、第三方服务 友盟社会化分享组件 友盟用户反馈 ...
    SunnyLeong阅读 14,613评论 1 180
  • 刻意与不舍之间有太多不确定项,虽然,彪悍的过往在梦中也无济于事,顺带被人打死。 确切来说,并不可笑,抱着那具尸体,...
    huizM阅读 358评论 0 0
  • 这次心得我想谈谈我自我的剖析,从二月开始萱宝开始咳嗽到四月底我跟萱宝都在医院转,医生开了一大堆药,但是没有什么效果...
    虾米82阅读 231评论 2 0