使用高德地图API根据地址名称获取经纬度(Go语言)
天地图、腾讯地图、高德地图等都提供对外开放的API,这里主要针对高德地图,进行地理编码接口的调用。
高德地图web API官方文档链接,根据文档的步骤,构造对应的请求URLhttps://restapi.amap.com/v3/geocode/geo?parameters
背景
地理编码表:共五级行政区域,分别为省/直辖市、区/县、街道/镇、社区/乡村
地理编码表中各地理编码和高德地图提供的地理编码不完全相同
方法
按级别分批获取地理编码表中的地址名称,根据pcode构造结构化地址信息,作为参数address的值,默认返回格式为json,判断返回的地理信息匹配级别是否对应,将匹配正确的经纬度信息插入数据库。
匹配级别和五级行政区域名称相差,但是返回数据合理的,可以将该匹配级别加入ignore list
Go语言代码如下:
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"strings"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// Area 地理编码表结构
type Area struct {
ID int `json:"id" gorm:"column:id; PRIMARY_KEY; AUTO_INCREMENT"`
Code int64 `json:"code" gorm:"column:code;type:bigint(12)"`
Name string `json:"name" gorm:"column:name; type:varchar(50); default:''"`
Pcode int64 `json:"pcode" gorm:"column:pcode;type:bigint(12)"`
ProvinceCode int64 `json:"province_code" gorm:"column:province_code;type:bigint(12)"`
CityCode int64 `json:"city_code" gorm:"column:city_code;type:bigint(12)"`
AreaCode int64 `json:"area_code" gorm:"column:area_code;type:bigint(12)"`
StreetCode int64 `json:"street_code" gorm:"column:street_code;type:bigint(12)"`
CommitteeCode int64 `json:"committee_code" gorm:"column:committee_code;type:bigint(12)"`
CommitteeType int64 `json:"committee_type" gorm:"column:committee_type;type:bigint(12)"`
Sort int `json:"sort" gorm:"column:sort; type:int(2); default:1"`
Level int `json:"level" gorm:"column:level; type:int(2); default:1"`
Longitude float64 `json:"longitude" gorm:"column:longitude; type:decimal(10); default:NULL"`
Latitude float64 `json:"latitude" gorm:"column:latitude; type:decimal(10); default:NULL"`
}
// TableName return table name
func (Area) TableName() string {
return "tbl_area"
}
// GetAreaMapByIDS 根据地区id获取 map[id]area结构
func GetAreaMapByIDS(db *gorm.DB, IDS []int) (map[int]Area, error) {
var res []Area
r := db.Model(&Area{}).Where("id in (?)", IDS).Find(&res)
if r.Error != nil {
return nil, r.Error
}
areaMap := make(map[int]Area)
for _, val := range res {
areaMap[val.ID] = Area{
ID: val.ID,
Name: val.Name,
Code: val.Code,
Pcode: val.Pcode,
Level: val.Level,
Longitude: val.Longitude,
Latitude: val.Latitude,
}
}
return areaMap, nil
}
// GetAreaNameMapByCodeS 根据地区code获取 mapd[code]name 结构
func GetAreaNameMapByCodeS(db *gorm.DB, codeS []int64) (map[int64]string, error) {
var res []Area
r := db.Model(&Area{}).Where("code in (?)", codeS).Find(&res)
if r.Error != nil {
return nil, r.Error
}
areaMap := make(map[int64]string)
for _, val := range res {
areaMap[val.Code] = val.Name
}
return areaMap, nil
}
// GetProvinceNameMapByCodeS 根据省code获取 map[id]name 结构
func GetProvinceNameMapByCodeS(db *gorm.DB, codeS []int64) (map[int64]string, error) {
var res []Area
r := db.Model(&Area{}).Where("code in (?)", codeS).Find(&res)
if r.Error != nil {
return nil, r.Error
}
areaMap := make(map[int64]string)
for _, val := range res {
areaMap[val.ProvinceCode] = val.Name
}
return areaMap, nil
}
// GetCityNameMapByCodeS 根据市code获取 map[id]name 结构
func GetCityNameMapByCodeS(db *gorm.DB, codeS []int64) (map[int64]string, error) {
var res []Area
r := db.Model(&Area{}).Where("code in (?)", codeS).Find(&res)
if r.Error != nil {
return nil, r.Error
}
areaMap := make(map[int64]string)
for _, val := range res {
areaMap[val.CityCode] = val.Name
}
return areaMap, nil
}
// GetAreaNameMapByCodeS2 根据区县code获取 map[id]name 结构
func GetAreaNameMapByCodeS2(db *gorm.DB, codeS []int64) (map[int64]string, error) {
var res []Area
r := db.Model(&Area{}).Where("code in (?)", codeS).Find(&res)
if r.Error != nil {
return nil, r.Error
}
areaMap := make(map[int64]string)
for _, val := range res {
areaMap[val.AreaCode] = val.Name
}
return areaMap, nil
}
// RequetForFile request for file
func RequetForFile(url string) (string, error) {
var bodyStr string
// Get the data
resp, err := http.Get(url)
if err != nil {
return bodyStr, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return bodyStr, err
}
bodyStr = string(body)
return bodyStr, nil
}
func main() {
var province string
var areaLevel string
var areaName string
var areaNick string
flag.StringVar(&province, "p", "", "省") //五级需要
flag.StringVar(&areaLevel, "l", "", "地区级别")
flag.StringVar(&areaName, "n", "", "地区级别名称")
flag.StringVar(&areaNick, "k", "", "地区级别名称别名")
// 解析
flag.Parse()
dsn := fmt.Sprintf(
"%s:%s@tcp(%s)/%s?parseTime=True&loc=Local",
LocalUser,
LocalPassword,
LocalHost,
LocalDatabase,
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println(err)
}
var res []Area
//省、直辖市
//sqlStr := fmt.Sprintf("select * from %s where level=%s and longitude is null ", Table, areaLevel)
//市
//sqlStr := fmt.Sprintf("select * from %s where level=%s and name not in('市辖区','省直辖县级行政区划','县') ", Table, areaLevel)
//区、县
//sqlStr := fmt.Sprintf("select * from %s where level=%s and name not in('市辖区') and longitude is null", Table, areaLevel)
//街道、镇
//sqlStr := fmt.Sprintf("select * from %s where level=%s and longitude is null", Table, areaLevel)
//社区、乡村
sqlStr := fmt.Sprintf("select * from %s where level=%s and longitude is null and province_code = %s", Table, areaLevel, province)
fmt.Println("--this is sqlstr--")
fmt.Println(sqlStr)
db.Raw(sqlStr).Scan(&res)
pCodeList := make([]int64, 0, len(res))
// provinceList := make([]int64, 0, len(res))
cityList := make([]int64, 0, len(res))
areaList := make([]int64, 0, len(res))
for _, v := range res {
cityTemp := ZeroFillByStr(strconv.FormatInt(v.CityCode, 10), 12, false)
cityTempInt, _ := strconv.ParseInt(cityTemp, 10, 64)
cityList = append(cityList, cityTempInt)
areaTemp := ZeroFillByStr(strconv.FormatInt(v.AreaCode, 10), 12, false)
areaTempInt, _ := strconv.ParseInt(areaTemp, 10, 64)
areaList = append(areaList, areaTempInt)
pCodeList = append(pCodeList, v.Pcode)
}
pAreaMap, err := GetAreaNameMapByCodeS(db, pCodeList)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("--this is p map--")
fmt.Println(pAreaMap)
provinceCode := ZeroFillByStr(province, 12, false)
tempInt, _ := strconv.ParseInt(provinceCode, 10, 64)
proAreaMap, err := GetProvinceNameMapByCodeS(db, []int64{tempInt})
if err != nil {
fmt.Println(err)
return
}
cityAreaMap, err := GetCityNameMapByCodeS(db, cityList)
if err != nil {
fmt.Println(err)
return
}
areaMap, err := GetAreaNameMapByCodeS2(db, areaList)
if err != nil {
fmt.Println(err)
return
}
for _, val := range res {
fmt.Println(val)
urlString := fmt.Sprintf(AmapApi, proAreaMap[val.ProvinceCode]+cityAreaMap[val.CityCode]+areaMap[val.AreaCode]+pAreaMap[val.Pcode]+val.Name, Key)
fmt.Println("---this is request url--")
fmt.Println(urlString)
bodyResp, err := RequetForFile(urlString)
if err != nil {
fmt.Println(err)
}
var dataInfo map[string]interface{}
var location string
if err := json.Unmarshal([]byte(bodyResp), &dataInfo); err != nil {
fmt.Println(err)
}
fmt.Println("--this is resp---")
fmt.Println(dataInfo)
for idx, value := range dataInfo {
if idx == "status" {
if value.(string) != "1" {
return
}
}
if idx == "geocodes" {
mapTemp := value.([]interface{})
temp := mapTemp[0].(map[string]interface{})
// && temp["level"].(string) != LevelFour && temp["level"].(string) != DevLevel
if temp["level"].(string) != areaName && temp["level"].(string) != areaNick{
return
}
location = temp["location"].(string)
}
}
locationList := strings.Split(location, ",")
fmt.Println("----this is location --")
updateSql := fmt.Sprintf("UPDATE %s SET longitude = %s, latitude = %s where id = %d ", Table, locationList[0], locationList[1], val.ID)
fmt.Println("---this is sql str---")
fmt.Println(updateSql)
db.Exec(updateSql)
if db.Error != nil {
fmt.Println(db.Error)
}
}
}
const (
AmapApi = "https://restapi.amap.com/v3/geocode/geo?address=%s&key=%s"
LocalHost = "127.0.0.1"
LocalDatabase = "xxx"
LocalPort = "3306"
LocalUser = "xxx"
LocalPassword = "xxx"
Key = "xxx"
)
// ZeroFillByStr 字符串前置/后置补零
func ZeroFillByStr(str string, resultLen int, reverse bool) string {
if len(str) > resultLen || resultLen <= 0 {
return str
}
if reverse {
return fmt.Sprintf("%0*s", resultLen, str) //不足前置补零
}
result := str
for i := 0; i < resultLen-len(str); i++ {
result += "0"
}
return result
}
版权声明:本博客所有文章除特别声明外,均采用 CC BY 4.0许可协议,转载请注明出处
本文链接:https://blog.redamancy.tech/technique/16