使用Python和地图api进行地图数据采集

来源:互联网 发布:淘宝客服打电话技巧 编辑:程序博客网 时间:2024/05/16 01:09

       当我们日常使用地图APP或者在网页上浏览地图信息的时候,会不会有一种想把地图信息直接抓取下来的想法呢?一般做分析的都想这么干啦,而地图服务商也开放了api接口,你们这些爬爬们不要再用乱七八糟的方式ping我的服务器了,老老实实的用api吧。

       本文仅以baiduMap和tencentMap为例,其他接口也大同小异,请自行处理。

       先介绍一下具体爬取的思路。

       ①先思考一下自己的需求内容,这点很重要,因为各大地图服务商给出的api请求次数是有限制的,如何简化流程,直接关系到用量问题。

       ②申请token(令牌),制作请求链接(request_url)

       ③接入后的异常处理

       ④返回值处理(主要是json格式)

       ⑤清洗及保存数据

       ⑥数据展示(echart,ExcelPowermap...ect)

       一、工作原理及优化流程。

        万事开头难,开了头什么都好办。先给出百度地图和腾讯地图的文档地址

       百度地图        点击打开链接 

       腾讯地图       点击打开链接 

      工作原理

       两个api都是基于HTTP协议的数据接口,也就是说,我们本地的客户端发出一个http请求,地图api返回一个响应报文,具体格式有josn和xml,2种格式各有用途,我们这里由于是数据采集,为了方便,直接使用json格式返回,数据格式为json的数据返回后,我们使用Python自带的json库解析数据,使之成为一个多层的字典,从而方便数据处理。

       流程优化

       在采集数据或使用api解析地址的时候,我们就要思考这样一个问题。我举个例子,大家可能就明白为什么开始想清楚设计流程很重要了。

       比如我们有10万个手工输入的地址,现在要将这些地址通过api解析成为经纬度,如果直接解析的话,同名称的地址全国可能有多个对应的值,地图api接口的返回值只可能是一个,那么就存在一个精度的问题,同时也有无法解析的问题,那就是召回的问题。可能你前期清洗数据比较好,比如有比较健全的多级地址字典,比较干净的数据库数据,但是依旧脱离不开同名的问题,就算在一个城市这样一个级别上,同名的依旧不在少数。

       针对上述的问题,我们要根据业务特点展开流程梳理,比如这10万个地址都是从仓库(固定地点)发出的,那么我们可以划定一个物流范围,比如5公里以内配送,那么我们把配送点的经纬度先得到,然后根据配送点搜索5公里范围内的PIO即可,这个范围搜索返回的是一个item,我们可以将这个item先保存下来,后续再考虑如何在item中选取最优地点。通过以上的流程梳理,我们可以大大降低对地址解析接口的依赖,以百度为例,每个地址解析接口的请求数量是3万次/天(认证后)。如果我们使用周边搜索,那么这个请求可以达到30万次/天(认证后)。

           二、地图坐标系介绍

       地图坐标系加密是为了安全考虑,国家一般采用火星坐标,百度又为了更加保密(诶,这个疙料货),又推出了百度坐标系。当然,可以一般的地图api提供了转换接口,比如腾讯地图api可以将百度坐标转换成火星坐标,然后使用在腾讯地图和Excel的powermap中(Excelpowermap使用的是bing地图,也是使用火星坐标的)。

      地图坐标系的加密算法有兴趣的可以查找相关文档,本文不讨论。

     三、前期的一些准备工作

     以下将以百度地图为例,其他地图大同小异,查阅文档即可。

      ①申请一个令牌

      令牌为一个长字符串,


      申请成功后需要创建应用,我这里使用的是服务端,名称是商户查询。至此,你的钥匙就有了,可以和百度地图的api接口亲密接触了。:D

       ②根据个人需求,进行认证。我是直接就把身份证扫描件什么的交给百度的,当然你可以打上水印。

       ③在应用配置上可以设置IP,也就是说只有限定的IP地址才能给使用此令牌访问百度地图api,建议家庭用户不要设置IP(真实大坑,联通为了省钱,会随机分配IP给用户,所以你今天写入一个IP地址,明天IP一变可能你又要去写入新的IP。)

       ④python库准备。

        pandas        数据整理,清洗必备

        urllib2          request也可以,但是我觉得urllib2在这里更方便一些,因为不需要模拟什么狗屁用户登录之类的事情。

        json             返回值就靠他解析了。当然如果你无聊想尝试一下xml,那么使用beautifulsoup解析返回HTML是个不错的选择。

        time            time.sleep(0.1)  ,因为一般的地图api都有并发上限,所以这个是备选。

      四,编写代码

        首先通过阅读文档了解一下URL参数详解,可以定义一个URL生成函数,整合不同种类的api接口,方便我们只需要几个参数就可以生成一个URL。还需要注意的是一些URL保留字和汉字的转义(通过urllib2.quote(string)来实现)。

         返回的json需要解析,那么使用json.loads方法可以解析成字典格式,然后使用dict.get方法抽取即可。

         ok,那么上代码吧~

        

# -*- coding: utf-8 -*-import pandas as pdimport urllib2import jsonimport time#search_word="中医院C座"keyword="钢铁"key="NRXxZ-KNaWG-AGSQ4-IZZDD-0000-PHBN2"#在这里输入刚才申请的token令牌city_list=pd.read_excel('C:/Users/Administrator/Desktop/china_city.xlsx')#获取城市列表for city in city_list["city"]:    try:        s=time.time()        url="http://apis.map.qq.com/ws/place/v1/search?"+"boundary=region("+urllib2.quote(city.encode("utf-8"))+",0)"+"&keyword="+urllib2.quote(keyword)+"&page_size="+str(10)+"&page_index="+str(1)+"&key="+key        html=urllib2.urlopen(url).read()        data=json.loads(html)        record_num=data.get("count")#制作翻页器        turnPage_num=int(record_num/10)+1        z=[]        for page_index in range(turnPage_num):            url="http://apis.map.qq.com/ws/place/v1/search?"+"boundary=region("+urllib2.quote(city.encode("utf-8"))+",0)"+"&keyword="+urllib2.quote(keyword)+"&page_size="+str(10)+"&page_index="+str(page_index+1)+"&key="+key            html=urllib2.urlopen(url).read()            data=json.loads(html)            data=data.get('data')            for df in data:                city_name=df.get("ad_info").get("city")                province_name=df.get("ad_info").get("province")                district_name=df.get("ad_info").get("district")                adcode=df.get("ad_info").get("adcode")                address=df.get("address")                category=df.get("category")                uid=df.get("id")                baidu_lat=df.get("location").get("lat")                baidu_lng=df.get("location").get("lng")                tel=df.get("tel")                title=df.get("title")                ad_type=df.get("type")                z.append((title,city_name,province_name,district_name,adcode,                address,tel,category,baidu_lat,baidu_lng,uid,ad_type))        df_total=pd.DataFrame(z)        df_total.to_csv('C:/Users/Administrator/Desktop/SteelInChina.csv',header=False,index=False,encoding="gbk",mode="a+")        end=time.time()        t=end-s    except Exception,e:        print e        print city    print city.encode("utf-8")+"已经搜索完毕,共有"+str(turnPage_num)+"条记录。共耗费时间:"+str(t)
        上述例子是一个简单的通过百度地图api获取全国城市相关信息点的例子,当然你也可以利用腾讯坐标的坐标转换接口在代码下方写一个转换接口,调整经纬度的数据接口,一次性10个10个的解析坐标。

       虽然腾讯和百度的地图api功能类似,而且腾讯的坐标系是火星坐标,为什么还要用百度呢?额,百度的中文预处理实在太牛了,实测在召回和精度两个指标上都是要完爆腾讯的,所以用百度去搜索PIO,然后用腾讯去解析一下坐标。当然你如果使用echart,那么直接用百度坐标就好了。excel powermap还是老老实实用火星坐标吧~!

原创粉丝点击