题目要求:根据单位名称获取具体位置(精确到区县)以及地域行政代码等信息
解决方法:利用python,调用百度地图API:
①通过地理编码服务由得到的单位名称得到经纬度;
②再通过逆地理编码服务,由①中得到的经纬度得到单位的具体地理信息(位置,行政代码等)
一.准备工作
认证,添加应用,百度地图API注册
二.根据需要选取服务接口(这里选取地理编码服务API以及逆地理编码服务)
在文档中查看如何获取url,以及返回的Json数据格式;
三.代码实现
1.根据单位名称获取经纬度

#!/usr/bin/env python # -*- coding: utf-8 -*- # @File : paqu_area_info.py # @Author: 田智凯 # @Date : 2020/3/12 # @Desc :根据完成单位名称(取第一个)爬取得到省市县以及行政代码 import urllib.request, urllib.parse, urllib.error import json import hashlib MyAK = '###' MySK = '###' #处理得到url def get_url(name): #GET请求 http://api.map.baidu.com/geocoding/v3/?address=北京市海淀区上地十街10号&output=json&ak=您的ak&callback=showLocation queryStr = '/geocoding/v3/?address={}&output=json&ak={}'.format(name,MyAK) # 对queryStr进行转码,safe内的保留字符不转换 encodedStr = urllib.parse.quote(queryStr, safe="/:=&?#+!$,;'@()*[]") # 在最后追加sk rawStr = encodedStr + MySK # 计算sn sn = (hashlib.md5(urllib.parse.quote_plus(rawStr).encode("utf8")).hexdigest()) #由于URL里面含有中文,所以需要用parse.quote进行处理,然后返回最终可调用的url url = urllib.parse.quote("http://api.map.baidu.com" + queryStr + "&sn=" + sn, safe="/:=&?#+!$,;'@()*[]") print('URL:', url) return url #得到json数据 def get_json(url): # 从API读取数据 req = urllib.request.urlopen(url) res = req.read().decode() # 解析数据 try: # 将 JSON 对象转换为 Python 字典 json_data = json.loads(res) except: json_data = None if not json_data or 'status' not in json_data or json_data['status'] != 0: print('json数据获取失败') else: #输出Json数据 print(json.dumps(json_data, indent=4, ensure_ascii=False)) return json_data # 获取经纬度坐标 def get_lnglat(json_data): lat = json_data["result"]["location"]["lat"] lng = json_data["result"]["location"]["lng"] print('纬度', lat, '经度', lng) if __name__ == '__main__': #得到经纬度 url=get_url('清华大学') json_data=get_json(url) lnglat=get_lnglat(json_data)
代码分析:
①处理URL:
#处理得到url def get_url(name):#GET请求 http://api.map.baidu.com/geocoding/v3/?address=北京市海淀区上地十街10号&output=json&ak=您的ak&callback=showLocation queryStr = '/geocoding/v3/?address={}&output=json&ak={}'.format(name,MyAK) # 对queryStr进行转码,safe内的保留字符不转换 encodedStr = urllib.parse.quote(queryStr, safe="/:=&?#+!$,;'@()*[]") # 在最后追加sk rawStr = encodedStr + MySK # 计算sn sn = (hashlib.md5(urllib.parse.quote_plus(rawStr).encode("utf8")).hexdigest()) #由于URL里面含有中文,所以需要用parse.quote进行处理,然后返回最终可调用的url url = urllib.parse.quote("http://api.map.baidu.com" + queryStr + "&sn=" + sn, safe="/:=&?#+!$,;'@()*[]") print('URL:', url) return url
②通过url得到Json数据:
#得到json数据 def get_json(url): # 从API读取数据 uh = urllib.request.urlopen(url) data = uh.read().decode() #print('Retrieved', len(data), 'characters') # 解析数据 try: # 将 JSON 对象转换为 Python 字典 json_data = json.loads(data) except: json_data = None if not json_data or 'status' not in json_data or json_data['status'] != 0: print('json数据获取失败') else: #输出Json数据 print(json.dumps(json_data, indent=4, ensure_ascii=False)) return json_data
Json样例:
③解析Json数据,得到经纬度:
# 获取经纬度坐标 def get_longlat(json_data): lat = json_data["result"]["location"]["lat"] lng = json_data["result"]["location"]["lng"] print('纬度', lat, '经度', lng)
2.根据经纬度获取详细地理信息
完整代码:

#!/usr/bin/env python # -*- coding: utf-8 -*- # @File : paqu_area.py # @Author: 田智凯 # @Date : 2020/3/12 # @Desc :根据完成单位名称(取第一个)爬取得到省市县以及行政代码 import urllib.request, urllib.parse, urllib.error import json import hashlib MyAK = '###' MySK = '###' lat=0.0 lng=0.0 #处理得到url def get_url(name): #GET请求 http://api.map.baidu.com/geocoding/v3/?address=北京市海淀区上地十街10号&output=json&ak=您的ak&callback=showLocation queryStr = '/geocoding/v3/?address={}&output=json&ak={}'.format(name,MyAK) # 对queryStr进行转码,safe内的保留字符不转换 encodedStr = urllib.parse.quote(queryStr, safe="/:=&?#+!$,;'@()*[]") # 在最后追加sk rawStr = encodedStr + MySK # 计算sn sn = (hashlib.md5(urllib.parse.quote_plus(rawStr).encode("utf8")).hexdigest()) #由于URL里面含有中文,所以需要用parse.quote进行处理,然后返回最终可调用的url url = urllib.parse.quote("http://api.map.baidu.com" + queryStr + "&sn=" + sn, safe="/:=&?#+!$,;'@()*[]") #print('URL:', url) return url #得到json数据 def get_json(url): # 从API读取数据 req = urllib.request.urlopen(url) res = req.read().decode() # 解析数据 try: # 将 JSON 对象转换为 Python 字典 json_data = json.loads(res) except: json_data = None if not json_data or 'status' not in json_data or json_data['status'] != 0: print('json数据获取失败') '''else: #输出Json数据 print(json.dumps(json_data, indent=4, ensure_ascii=False))''' return json_data # 获取经纬度坐标 def get_lnglat(json_data): #Python中定义函数时,若想在函数内部对函数外的变量进行操作,就需要在函数内部声明其为global global lat,lng lat = json_data["result"]["location"]["lat"] lng = json_data["result"]["location"]["lng"] #print('纬度', lat, '经度', lng) def get_url2(lat,lng): #GET请求 http://api.map.baidu.com/reverse_geocoding/v3/?ak=您的ak&output=json&coordtype=wgs84ll&location=31.225696563611,121.49884033194 queryStr = '/reverse_geocoding/v3/?ak={}&output=json&coordtype=wgs84ll&location={},{} '.format(MyAK,str(lat),str(lng)) # 对queryStr进行转码,safe内的保留字符不转换 encodedStr = urllib.parse.quote(queryStr, safe="/:=&?#+!$,;'@()*[]") # 在最后追加sk rawStr = encodedStr + MySK # 计算sn sn = (hashlib.md5(urllib.parse.quote_plus(rawStr).encode("utf8")).hexdigest()) #由于URL里面含有中文,所以需要用parse.quote进行处理,然后返回最终可调用的url url = urllib.parse.quote("http://api.map.baidu.com" + queryStr + "&sn=" + sn, safe="/:=&?#+!$,;'@()*[]") #print('URL:', url) return url # 解析Json数据 def get_info(json_data): province=json_data["result"]["addressComponent"]["province"] city=json_data["result"]["addressComponent"]["city"] district=json_data["result"]["addressComponent"]["district"] adcode=json_data["result"]["addressComponent"]["adcode"] print("地理:",province+city+district) print("行政代码:"+adcode) if __name__ == '__main__': #得到经纬度 url=get_url('南开大学') json_data=get_json(url) lnglat=get_lnglat(json_data) #获取详细信息 url2=get_url2(lat, lng) json_data = get_json(url2) get_info(json_data)
代码分析:(与第一步同理)
①处理得到URL
②得到Json,样例:
③解析Json数据
④运行结果:
四.结合SQL server数据库:读取数据库单位名,将由单位名所得到的行政代码以及具体地理信息加入到数据库中
解决思路:
- 新建area实体,属性:id,单位名称,地理信息,行政代码
- 将数据库读取到的id和单位名以及由单位名得到的具体地理信息和行政代码(利用百度API实现)保存在area对象中, 将对象保存在一个list列表中
- main中使用多进程运行;迭代list(适用于数据量偏大的)
我这里八千多条数据开四个进程用时十分钟:
注:
- 有的地点,百度地图上是没有的;这里异常处理选择continue;跳过继续读取下一条
- 还有就是读取数据库中文乱码问题:
conn = pymssql.connect("127.0.0.1", "sa", "###", "test", charset="GBK")
- 写入数据库中文乱码问题
conn = pymssql.connect("127.0.0.1", "sa", "###", "test", charset="utf8")
最后上完整代码:

#!/usr/bin/env python # -*- coding: utf-8 -*- # @File : paqu_area.py # @Author: 田智凯 # @Date : 2020/3/12 # @Desc :根据完成单位名称(取第一个)爬取得到省市县以及行政代码 import urllib.request, urllib.parse, urllib.error import json import hashlib import pymssql import time from multiprocessing import Pool from paqu.area import Area MyAK = '###' MySK = '###' lat=0#记录纬度 lng=0#记录经度 str_area=0#记录具体地理信息 adcode=0#记录行政代码 err=0#记录JSON获取失败数 #百度API地理服务接口;处理得到url def get_url(name): #GET请求 http://api.map.baidu.com/geocoding/v3/?address=北京市海淀区上地十街10号&output=json&ak=您的ak&callback=showLocation queryStr = '/geocoding/v3/?address={}&output=json&ak={}'.format(name,MyAK) # 对queryStr进行转码,safe内的保留字符不转换 encodedStr = urllib.parse.quote(queryStr, safe="/:=&?#+!$,;'@()*[]") # 在最后追加sk rawStr = encodedStr + MySK # 计算sn sn = (hashlib.md5(urllib.parse.quote_plus(rawStr).encode("utf8")).hexdigest()) #由于URL里面含有中文,所以需要用parse.quote进行处理,然后返回最终可调用的url url = urllib.parse.quote("http://api.map.baidu.com" + queryStr + "&sn=" + sn, safe="/:=&?#+!$,;'@()*[]") #print('URL:', url) return url #根据url得到json数据 def get_json(url): global err # 从API读取数据 req = urllib.request.urlopen(url) res = req.read().decode() # 解析数据 try: # 将 JSON 对象转换为 Python 字典 json_data = json.loads(res) except: json_data = None if not json_data or 'status' not in json_data or json_data['status'] != 0: err=err+1 '''else: #输出Json数据 print(json.dumps(json_data, indent=4, ensure_ascii=False))''' return json_data #百度API地理服务接口;获取经纬度坐标 def get_lnglat(json_data): #Python中定义函数时,若想在函数内部对函数外的变量进行操作,就需要在函数内部声明其为global global lat,lng lat = json_data["result"]["location"]["lat"] lng = json_data["result"]["location"]["lng"] #print('纬度', lat, '经度', lng) #百度API逆地理服务接口;处理得到url def get_url2(lat,lng): #GET请求 http://api.map.baidu.com/reverse_geocoding/v3/?ak=您的ak&output=json&coordtype=wgs84ll&location=31.225696563611,121.49884033194 queryStr = '/reverse_geocoding/v3/?ak={}&output=json&coordtype=wgs84ll&location={},{} '.format(MyAK,str(lat),str(lng)) # 对queryStr进行转码,safe内的保留字符不转换 encodedStr = urllib.parse.quote(queryStr, safe="/:=&?#+!$,;'@()*[]") # 在最后追加sk rawStr = encodedStr + MySK # 计算sn sn = (hashlib.md5(urllib.parse.quote_plus(rawStr).encode("utf8")).hexdigest()) #由于URL里面含有中文,所以需要用parse.quote进行处理,然后返回最终可调用的url url = urllib.parse.quote("http://api.map.baidu.com" + queryStr + "&sn=" + sn, safe="/:=&?#+!$,;'@()*[]") #print('URL:', url) return url # 百度API地理服务接口;解析Json数据;获取行政代码等具体信息 def get_info(json_data): global str_area,adcode province=json_data["result"]["addressComponent"]["province"] city=json_data["result"]["addressComponent"]["city"] district=json_data["result"]["addressComponent"]["district"] adcode=json_data["result"]["addressComponent"]["adcode"] str_area=province+city+district #print("地理:",str_area) #print("行政代码:",adcode) #汇总 def get_area_main(danwei): #得到经纬度 url=get_url(danwei) json_data=get_json(url) get_lnglat(json_data) #获取详细信息 url2=get_url2(lat, lng) json_data = get_json(url2) get_info(json_data) #查询数据库,返回list def get_dbdata(): conn = pymssql.connect("127.0.0.1", "sa", "tzk19991029", "test", charset="GBK") cursor = conn.cursor() list = [] try: cursor.execute('SELECT id,wc_danwei FROM kettle2') for row in cursor: area=Area() id=row[0] danwei=row[1].split()[0] try: get_area_main(danwei) except: #有的地点百度地图上没有,这时选择跳过去 continue area.set_id(id) area.set_danwei(danwei) area.set_area(str_area) area.set_adcode(adcode) list.append(area) cursor.close() except: # 发生错误时回滚 conn.rollback() return list #修改数据库表 def update_dbdata(area): conn = pymssql.connect("127.0.0.1", "sa", "tzk19991029", "test", charset="utf8") cursor = conn.cursor() sql="UPDATE kettle2 SET area='{}',adcode='{}' WHERE id='{}'".format(area.get_area(),area.get_adcode(),area.get_id()) #print(sql) try: cursor.execute(sql) # 提交到数据库执行 conn.commit() cursor.close() except: # 发生错误时回滚 conn.rollback() if __name__ == '__main__': start = time.time() list=get_dbdata() print(len(list)) #多进程 pool = Pool(processes=4) # 创建进程池 pool.map(update_dbdata, list) pool.close() end = time.time() print('json数据获取失败数 ', err) print("程序用时",end-start)

#!/usr/bin/env python # -*- coding: utf-8 -*- # @File : area.py # @Author: 田智凯 # @Date : 2020/3/12 # @Desc :描述 # 定义类 class Area: # 定义私有变量 __id= 0 __danwei=0 __area=0 __adcode=0 # 定义get方法,返回私有变量的值 def get_id(self): return self.__id def get_area(self): return self.__area def get_danwei(self): return self.__danwei def get_adcode(self): return self.__adcode # 定义set方法,设置私有变量的值 def set_id(self, id): self.__id = id def set_danwei(self, danwei): self.__danwei = danwei def set_area(self, area): self.__area= area def set_adcode(self, adcode): self.__adcode = adcode