[原创]python爬取百度地图361个城市最短公路距离

这里只有作者精心编写的研究经历!
回复
头像
hellohappy
网站管理员
网站管理员
帖子: 299
注册时间: 2018年11月18日, 14:27
Been thanked: 5 time

#1 [原创]python爬取百度地图361个城市最短公路距离

未读文章 hellohappy » 2019年2月23日, 13:22

目录:
    前言:
    目的:
    方法:
        离线的方法(不用联网):
        在线的方法:
    使用百度地图api步骤:
        1,2,3,4步:
        结果:中国361个城市两两公路最短距离结果
            txt版结果:
            excel版结果:
        python程序源码:



前言:

    有时候我们会用到两两城市之间的距离。但是现在很多人都是图方便,直接用两个城市之间的经纬度计算两个点的弧线距离,甚至有些计算方法干脆连地球的弧度都忽略了。虽然大多数时候,这些忽略都不会对结果造成极大的影响。但是毕竟能精确就精确嘛,模型比较大或复杂的时候,这些影响可能还是会改变结论的!
    所以,我在研究 空间计量 时候,对构建 空间距离权重矩阵 的时候,就保持这种严谨的思想,直接采用了最为准确的矩阵构建方法--找到两两城市的最短公路距离来构建矩阵。

目的:

    用python爬取(严格来说不算爬虫)百度地图361个城市(包含地级市和部分县级市)之间最短公路距离

方法:

    首先我们看一下有哪些方法得到公路最短城市距离
        离线的方法(不用联网):
            比如直接下载shp格式或者其他格式的地图,放到arcgis软件上,利用软件自带的各种功能直接获取(由于对arcgis理解不深,这个方法我没试过,但是大概知道它应该是可行的,因为地图里面包含了城市名称和道路信息,而且还有一些两点距离工具什么的?应该也有程式化的方法获取这些距离信息吧!)
        在线的方法:
            比如去百度地图,谷歌地图之类的地图网站,你发现你输入两个城市之间的名字就会返回城市之间的距离和规划路线,我们随便选一个最短或者最快都没关系,只要我们整个结果是一致的(比如a和b城市为最短距离,那么测量b和c城市就不能是最快路线的距离,反正要一致,一视同仁)就可以。既然手工能输入,那么电脑就一定能!只是根据不同网站的反爬手段的不同,爬取难度和速度可能不同。
            由于百度地图本身就有合法的爬取渠道,其实我们没有必要和他较劲,直接使用百度地图api去获取城市距离数据即可。

使用百度地图api步骤:

    1.注册 百度地图开发者中心 的一个帐号,可以不需要上传身份证,当然如果你愿意实名认证,则可以获得每日更高的次数的免费调用次数。
    2.熟悉api开发文档的内容(当年我用的是v1的文档,但是现在不知道还是否支持v1,建议还是自己研究一下v2,然后改用v2的api吧,新版的功能好像更加丰富),开发文档的地址为:
        https://lbsyun.baidu.com/index.php?titl ... ion-api-v2
    3.创建应用,申请对应的ak。(源码里面有我的api方便你们测试)
    4.根据自己的要爬取的城市名字,写python程序,自动根据api的返回的两城市距离结果,生成我们想要的数据。

    下面我给出我当年用到的所有程序源代码、城市名、结果供参考,其中部分源代码是为了应付2000单次限额才这么复杂的,不然应该很短,也很简单
        城市名字:
city_361.txt
(3.17 KiB)
city_361.txt
(3.17 KiB) 尚未被下载

        结果:中国361个城市两两公路最短距离结果
            (我相信对于大多数人来说,有这个结果就够了,没必要再去爬一次,一共大约有 361*361/2 个请求,一天只能爬2000个,也差不多要爬一个半月)
            txt版结果:
CITY_distance.txt
(2.38 MiB)
CITY_distance.txt
(2.38 MiB) 尚未被下载

            excel版结果:
城市距离.xlsx
(1.95 MiB)
城市距离.xlsx
(1.95 MiB) 尚未被下载

结果展示.png
结果展示.png (46.04 KiB) 查看 1909 次
结果展示.png
结果展示.png (46.04 KiB) 查看 1909 次

        python程序源码:
            我这里源代码里面只展示我自己的ak 给你们,方便你们做测试,请不要在真正使用的时候用我的ak 。
python源码.zip
(572 Bytes)
python源码.zip
(572 Bytes) 尚未被下载

Code: 全选

def get_distant(origins,destinations,ak):
    distant=0
    url1="http://api.map.baidu.com/direction/v1/routematrix?output=json&origins=%s&destinations=%s&coord_type=gcj02&ak=%s"%(origins,destinations,ak)
    #pdb.set_trace()
    try:
        req=requests.get(url1)                                
        content= req.content
        data=json.loads(content)
    except:
        print ("请求超时或出错!")
        return "请求超时或出错!"
    if data['status']!=0:
        print ("爬取失败,该位点是:\n起点:%s\n终点:%s\
            \n"%(origins,destinations))                
    else:
        distant=data['result']['elements'][0]['distance']['value']
    return distant

def run():
    num1=319
    num2=360
    last=1999
    ak1='4T5a10aPRSgU8pl52SFZs4CRw31FbNTg'#我的ak只用于测试
    ak2='????????'#这里写你的ak,再改下面ak=ak2;
    ak=ak1
    print ("complete percent:\n")
    num_percent=0
    num_percent_c=0
    num=0
    num_city=361
    file_r = open('.\\city_361.txt','r+')
    city_name = file_r.readlines()
    file_r.close()
    file_w = open('.\\baidu.txt','a')
    #file_w.write("次数,city,city,distance 单位:m\n")
    #开头:
    i = num1-1 #i 记得减1,j为最后本身
    for j in range(num2,num_city):
        num=num+1
        origins=city_name[i]
        origins=origins.replace('\n','')
        destinations=city_name[j]
        destinations=destinations.replace('\n','')
        try:
            distant=get_distant(origins,destinations,ak)
        except:
            print ("出错1!\n")
            return "出错1!\n"
        #下面这句用来显示城市名字,需要就删除#
        file_w.write("%s\t%s\n"%(origins,destinations))
        file_w.write("%d\t%d\t%d\t%d\n"%(num,i+1,j+1,distant))
        if num > last :
            print ("1200单次限额已到!")
            file_w.close()
            exit(0) # 无错误退出
            
    for i in range(num1,num_city-1):
        for j in range(i+1,num_city):
            num_percent=100.0*num/last
            if (num_percent-num_percent_c)>0.9:
                num_percent_c=num_percent
                print ("%4.1f%%    "%num_percent,end=" ")
            num=num+1
            origins=city_name[i]
            origins=origins.replace('\n','')
            destinations=city_name[j]
            destinations=destinations.replace('\n','')
            try:
                distant=get_distant(origins,destinations,ak)
            except:
                print ("出错2!\n")
                return "出错2!\n"
            #下面这句用来显示城市名字,需要就删除#
            try:
                file_w.write("%s\t%s\n"%(origins,destinations))
                file_w.write("%d\t%d\t%d\t%d\n"%(num,i+1,j+1,distant))
            except:
                print ("又打印出错!气死我了!!!")
                file_w.close()
                exit(0) # 无错误退出
            if num > last :
                print ("2000单次限额已到!")
                file_w.close()
                exit(0) # 无错误退出
    file_w.close()

if __name__=='__main__':
    import requests
    import json
    #import pdb
    run()
#url = "http://api.map.baidu.com/direction/v1/routematrix?output=json&origins=天安门|鸟巢\
#    &destinations=北京大学|东方明珠&coord_type=gcj02&ak=4T5a10aPRSgU8pl52SFZs4CRw31FbNTg"
#me:
#4T5a10aPRSgU8pl52SFZs4CRw31FbNTg

 

Link:
Hide post links
Show post links


回复