HiSEN

百度地图 API - 地址 转 经纬度

0. 背景

某做科研的朋友
需要对一些地点的坐标
然后在 WGS-84 坐标系的底图上呈现相关内容

BD09 vs WGS84
北京韩美林艺术馆,BD09:116.68347847243588,39.88148624000483
北京韩美林艺术馆,WGS84:116.67097966259838,39.87446583754102

1. 准备

1.1 寻找成品

找了几个网址,反馈说之前用过坐标不准确

1.2 使用百度地图 API

1.2.1 注册百度地图开放平台

服务免费
需要实名认证
网址:lbsyun.baidu.com

1.2.2 创建应用

我没有选择 IP 白名单
选择的是 SN 签名
获取 AK、SK

1.2.3 文档

接口文档
之前 V2 版本的接口已经停用了
地址:地理编码文档
SN 生成
注意文档的生成方式还是 V2 的例子
地址:SN 生成文档

2. 代码

简单说明
地址文件格式一行一个
转换后会输出文件:地址,精度,纬度

CoordinateTransformUtil 在参考文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/**
* Baidu.com Inc.
* Copyright (c) 2022 All Rights Reserved.
*/
package com.hisen.api.baidu.map;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.joda.time.DateTime;
import org.springframework.util.DigestUtils;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
* @author hisenyuan
* @date 2022/5/28 10:55
*/
public class SnCal {
private static final String URL = "https://api.map.baidu.com";
private static final String PATH = "/geocoding/v3/?";
/**
* 百度地图 AK
*/
private static final String AK = "your ak";
/**
* 百度地图 SK
*/
private static final String SK = "your sk";
private static final String LINE_BREAK = "\n";
private static final String FORMAT = "yyyyMMdd_HH_mm_ss_SSS";

public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
// 需要转换的文件,一行一个
String file = "/Users/hisenyuan/Downloads/address.txt";
// 结果输出文件夹
String resDir = "/Users/hisenyuan/Downloads/";
File resFile = getResFile(resDir);
// 读取文件
List<String> addressList = getAddressList(file);
for (int i = 0; i < addressList.size(); i++) {
convertLocation(resFile, addressList, i);
System.out.println("current line:" + (i + 1));
}
long use = System.currentTimeMillis() - start;
// 打印耗时
System.out.println("time us(ms):" + use);
}

private static void convertLocation(File resFile, List<String> addressList, int index) throws IOException {
String address = addressList.get(index);
String reqUrl = getReqUrl(address);
// 返回结果
String res = sendUrlGet(reqUrl);
double[] doubles = getWgs84(res);
String wgsRes = address + "," + doubles[0] + "," + doubles[1];
Files.append(wgsRes + LINE_BREAK, resFile, Charsets.UTF_8);
}

private static List<String> getAddressList(String file) throws IOException {
List<String> addressList = Files.readLines(new File(file), StandardCharsets.UTF_8);
System.out.println("sum line:" + addressList.size());
return addressList;
}

private static File getResFile(String resDir) throws IOException {
DateTime dateTime = new DateTime();
File resFile = new File(resDir + "处理结果_" + dateTime.toString(FORMAT) + ".txt");
if (!resFile.exists()) {
boolean newFile = resFile.createNewFile();
System.out.println("create file, result:" + (newFile ? "success" : "fail"));
}
return resFile;
}

private static double[] getWgs84(String res) {
JSONObject jsonObject = JSON.parseObject(res);
JSONObject result = jsonObject.getJSONObject("result");
JSONObject location = result.getJSONObject("location");
Double lng = location.getDouble("lng");
Double lat = location.getDouble("lat");
return CoordinateTransformUtil.bd09towgs84(lng, lat);
}

private static String getReqUrl(String address) throws UnsupportedEncodingException {
Map<String, String> paramsMap = new LinkedHashMap<>();
paramsMap.put("address", address);
paramsMap.put("output", "json");
paramsMap.put("ak", AK);
// 参数值转为 UTF-8
String paramsStr = toQueryString(paramsMap);
// 参与 MD5 计算的参数
String wholeStr = PATH + paramsStr + SK;
// UTF-8
String tempStr = URLEncoder.encode(wholeStr, "UTF-8");
// Md5 摘要( SN 计算)
String md5 = md5(tempStr);
// 请求地址
return URL + PATH + paramsStr + "&sn=" + md5;
}

/**
* 值 UTF-8
*/
public static String toQueryString(Map<?, ?> data)
throws UnsupportedEncodingException {
StringBuilder queryString = new StringBuilder();
for (Map.Entry<?, ?> pair : data.entrySet()) {
queryString.append(pair.getKey()).append("=");
queryString
.append(URLEncoder.encode((String) pair.getValue(), StandardCharsets.UTF_8.name()))
.append("&");
}
if (queryString.length() > 0) {
queryString.deleteCharAt(queryString.length() - 1);
}
return queryString.toString();
}

/**
* md5 摘要
*/
public static String md5(String str) {
return DigestUtils.md5DigestAsHex(str.getBytes(StandardCharsets.UTF_8));
}

/**
* 发起 http 请求
*
* @param url 请求地址
* @return 返回数据
*/
public static String sendUrlGet(String url) {
String responseContent = null;
try {
CloseableHttpClient client = HttpClientBuilder.create().build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = client.execute(httpGet);
HttpEntity resEntity = response.getEntity();
responseContent = EntityUtils.toString(resEntity, StandardCharsets.UTF_8);
// close resources
response.close();
client.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
return responseContent;
}
}

3. 参考

注意,第一个文档的接口已经过时,新申请的用户无法使用