python 调用百度地图api接口获取地理详细信息行政代码等

题目要求:根据单位名称获取具体位置(精确到区县)以及地域行政代码等信息

解决方法:利用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数据库:读取数据库单位名,将由单位名所得到的行政代码以及具体地理信息加入到数据库中

解决思路:

  1. 新建area实体,属性:id,单位名称,地理信息,行政代码
  2. 将数据库读取到的id和单位名以及由单位名得到的具体地理信息和行政代码(利用百度API实现)保存在area对象中, 将对象保存在一个list列表中
  3. main中使用多进程运行;迭代list(适用于数据量偏大的)

      我这里八千多条数据开四个进程用时十分钟:

    

注:

  1. 有的地点,百度地图上是没有的;这里异常处理选择continue;跳过继续读取下一条
  2. 还有就是读取数据库中文乱码问题:
    conn = pymssql.connect("127.0.0.1", "sa", "###", "test", charset="GBK")
  3. 写入数据库中文乱码问题

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
area实体

 

posted @ 2020-03-12 15:31  田智凯  阅读(5941)  评论(0编辑  收藏  举报