題目要求:根據單位名稱獲取具體位置(精確到區縣)以及地域行政代碼等信息
解決方法:利用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