1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > python调用百度地图API爬取西安市POI数据

python调用百度地图API爬取西安市POI数据

时间:2019-08-09 06:50:57

相关推荐

python调用百度地图API爬取西安市POI数据

任务前提

做该项目之前,首先得有基础知识:

编程语言:python

编译工具:PyCharm

网络爬虫相关知识,xpath库,numpy,pandas等库。

任务准备:

去百度地图开放平台申请密匙:/

步骤:

登录----->控制台----->注册登录成为开发者(已成为则跳过该步骤)----->创建应用------>填写应用名称----->应用类型选择浏览器端---->refer白名单输入“*”—>创建应用成功----->得到密匙(AK)

我的密匙:************************************

任务目的:

爬取西安市各种兴趣点的POI数据(以西安市所有中学为例)

选取方法:由于我们需要爬取西安市所有兴趣点,区域较大,数据较多,我们采用矩形区域检索来进行,具体可参考:/index.php?title=webapi/guide/webservice-placeapi 来进行选择。

爬取关键字:城市:西安(以西安经纬度来表示)兴趣点:中学(其他兴趣点同理)

西安市经纬度范围:

URL模板:

http://api./place/v2/search?query=中学& bounds=33.699374,107.671067,34.746103,109.82715&page_size=20&page_num=0&output=json&ak=9toMp2Wls5la******************88fiX (此处填写自己申请的AK)

功能详解:

其实调用百度地图API来爬取没什么难度,基本都是静态页面,和爬取普通的静态页面没什么区别,都是以下几个步骤:

第一步:构建需要访问的URL

第二步:构建请求头(防止反爬手段有很多:伪造UA,代理IP,多进程延迟爬取等)

第三步:访问URL,获取数据

第四步:解析网页数据(xpath,bs4,lxml等)

第五步:存储数据(存入excel,数据库等)

通过调用百度地图API,爬取西安市所有数据,也是通过以上步骤完成的,唯一需要注意的就是我们构造目的URL时根据区域来构建URL的,但是每个URL所爬取到的数据有限,所以我们需要对区域进行合理的划分,来构造跟多的目的URL,这样才能爬取到更多的API数据。有几种不同的方法,圆形区域分割,矩形区域分割等,具体参考官方文档:/index.php?title=webapi/guide/webservice-placeapi

因为由于百度的限制每一个区域只有20个url,即page_num从0–19,每一个url最多只有20条数据,所以哪怕该区域有成千上万条数据,最多只能获得400条数据,因此我们要用bound对应区域的经纬度进行网格划分,将西安市通过经纬度进行划分,为了计算简便,我们就切成正方形。(类似于数学中的微分思想)

坐标范围:

西安市经纬度:

左下角:107.671067,33.699374 右上角:109.82715,34.746103

lat_1 = 33.699374 ; lat_2 = 34.746103 ;lon_1 = 107.671067 ; lon_2 = 109.82715

纬度差:lat_2 - lat_1 = 1.046729

经度差:lon_2 - lon_1 = 2.156083

设切割的小正方形的边长为:las;则lat_count = int((lat_2 - lat_1) / las)+1计算的是在纬度上能够分割出多少个小正方形;lon_count = int((lon_2 - lon_1) / las )+1计算的是在经度上能够分割出多少个小正方形;二者乘积就是总共能够分割出多少个小正方形。为了简便计算,取las值为1

编写代码获取每一个小正方形的坐标范围:

代码如下:

lat_1=33.699374lon_1=107.671067lat_2=34.746103lon_2=109.82715 #坐标范围las=1 #给las一个值1lat_count=int((lat_2-lat_1)/las+1)lon_count=int((lon_2-lon_1)/las+1)for lat_c in range(0,lat_count):lat_b1=lat_1+las*lat_cfor lon_c in range(0,lon_count):lon_b1=lon_1+las*lon_cprint(str(lat_b1)+','+str(lon_b1)+','+str(lat_b1+las)+','+str(lon_b1+las))#这段代码生成的是小正方形的范围坐标运行结果:33.699374,107.671067,34.699374,108.67106733.699374,108.671067,34.699374,109.67106733.699374,109.671067,34.699374,110.67106734.699374,107.671067,35.699374,108.67106734.699374,108.671067,35.699374,109.67106734.699374,109.671067,35.699374,110.671067

由以上结果看出,可以分为六个小正方形,当然要想更加精细,可以缩小las的值,使划分的区域更小。

待访问的URL由参数bounds和page_num决定,page_num取值为range(0,20)。

具体参考代码如下:

import requestsimport timefrom urllib.parse import urlencodeimport csv"""要想爬取所有兴趣点的信息,对下面代码稍加修改,将所有兴趣点列为一个列表,然后keyeord从列表中遍历获取来构造URL即可,即增加一层循环若要将该区域分割的更加细致,则修改las的值,值越小,分的越细改进方案:由于每个密匙访问次数有限,可以使用代理池加上多进程来进行爬取大量数据"""'''计算纬度上能分割几次'''def get_lat_count(lat_2,lat_1,las):lat_count = int((lat_2 - lat_1) / las + 1)return lat_count'''计算经度上能分割几次'''def get_lon_count(lon_2,lon_1,las):lon_count = int((lon_2 - lon_1) / las + 1)return lon_count'''计算每个分区的经纬度'''def get_latLonList(lat_2,lat_1,lon_2,lon_1,las):'''得到所有小正方形的经纬度范围:param lat_2:右上纬度:param lat_1:左下纬度:param lon_2:右上经度:param lon_1:左下经度:param las:一个分割正方形的边长:return:latLonList:含有所有小正方形的经纬度列表。'''lat_count = get_lat_count(lat_2,lat_1,las)lon_count = get_lon_count(lon_2,lon_1,las)latLonList = []for lat_c in range(0,lat_count):lat_b1=lat_1+las*lat_cfor lon_c in range(0,lon_count):lon_b1=lon_1+las*lon_clat_lon = str(lat_b1) + ',' + str(lon_b1) + ',' + str(lat_b1 + las) + ',' + str(lon_b1 + las)latLonList.append(lat_lon)return latLonList'''拼接url'''def get_urlList(oldurl,keyword,lat_2,lat_1,lon_2,lon_1,las):''':param oldurl: 不完整的url:param keyword: 兴趣点:param lat_2:右上纬度:param lat_1:左下纬度:param lon_2:右上经度:param lon_1:左下经度:param las:一个分割正方形的边长:return: list'''latLonList = get_latLonList(lat_2,lat_1,lon_2,lon_1,las)urlList = []for bounds in latLonList:for num in range(0,1):#此处修改为(0,20)就是每个url爬取20页parameter = {"query":keyword,"bounds": bounds,"page_size": 20,"page_num": num,"output":'json',"ak": ak}data = urlencode(parameter)url = oldurl + dataurlList.append(url)return urlList'''爬取数据'''def getDataFromHtml():'''# 示例数据:{'name': '周至中学', 'location': {'lat': 34.168176, 'lng': 108.248956}, 'address': '陕西省西安市周至县五合村一零八国道北', 'province': '陕西省', 'city': '西安市', 'area': '周至县', 'telephone': '(029)87161124', 'detail': 1, 'uid': '593850fb6bcfc45dde1e52b0'}:return: list'''urlList = get_urlList(oldurl=oldurl, keyword=keyword, lat_2=lat_2, lat_1=lat_1, lon_2=lon_2, lon_1=lon_1, las=las)# for i in urlList:#print(i)# print(len(urlList))json_data_list = []for url in urlList:response = requests.get(url=url)json_data = response.json()# 去重if json_data not in json_data_list:json_data_list.append(json_data)time.sleep(10)# print(json_data_list)result_dict = []for data in json_data_list:if data['results']:for result in data['results']:result_dict.append(result)return result_dict'''将数据写入excel'''def export_excel(result_dict):with open('西安所有中学.csv','a',encoding='utf8') as f:for mydict in result_dict:w = csv.DictWriter(f, mydict.keys())w.writerow(mydict)def main():result_dict = getDataFromHtml()# 将分析完成的列表导出为csvexport_excel(result_dict)if __name__ == "__main__":lat_1=33.699374lon_1=107.671067lat_2=34.746103lon_2=109.82715 #坐标范围las=1 #给las一个值1oldurl = "http://api./place/v2/search?"ak = '9toMp2Wls5la**************fiX' #自己申请的AKkeyword = '中学'main()

最后具体爬取到的数据如下,数据量过大,此处展示部分截图:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。