谷歌地图的地理译码(Geocoding)和行车路线(Directions)解析
九月 5, 2007 by 花老鼠 · 9 Comments
其实对于谷歌地图的地理译码(Geocoding),在英文 Maps 的API里面已经支持了,现在可以使用中文地理名称来定位地图了(目前好像详细到县级)。说到底谷歌地图的地图使用的是 Mapabc 的,那他的 Geocoding 以及 Directions 也就是用的 Mapabc 的。
地理译码(Geocoding)
首先,我们在 ditu.google.com 请求一个地址。例如“南通”。
http://ditu.google.com/maps?f=q&hl=zh_CN&q=南通&output=js 注意后面的 output=js 这个表明是以JS的形式输出请求。查看源代码我们找到下来 Js 代码:
function onLoad() { var w = window.parent; w = w.parent; w.loadVPage({ title:"南通 - Google 地图", vartitle:"", url:"/maps?f=q\x26hl=zh_CN\x26q=%E5%8D%97%E9%80%9A\x26ie=UTF8", urlViewport:false, ei:"yzzeRoiHMaeKjQPc1YD_Ag", form:{selected:"q",q:{q:"南通"},l:{q:"",near:"南通"},d:{saddr:"",daddr:"南通"},geocode:"",g:{q:"南通"},k:{q:"南通"}}, query:{type:"g"}, stickyFlags:{hl:"zh_CN"}, viewport:{center:{lat:0,lng:0},span:{lat:0,lng:0},mapType:""}, resolvedPOIID:false, mabcCenter:{id:"BE000005CB",title:"江苏省南通",gridcode:"4820061911",bottomLeftId:"BF00000B96",topRightId:"BF00000B97",zoom:"9"}, modules:[""], overlays:{sxcar:false,markers:[{id:"addr",mapabcPoiid:"BE000005CB",lat:0,lng:0,image:"http://www.google.com/intl/zh-CN_cn/mapfiles/arrow.png",adr:true,elms:[3,2,6],laddr:"江苏省南通",svaddr:"江苏省南通",dtlsUrl:"/maps?f=q\x26hl=zh-CN\x26q=%E5%8D%97%E9%80%9A\x26ie=UTF8\x26sll=32.011111,120.866667\x26sspn=1.700295,2.005194\x26latlng=\x26ei=yzzeRoiHMaeKjQPc1YD_Ag\x26sig2=Zh9HY_QRjVimYbylM8abVw",addressLines:["江苏省南通"],log:"EAMQBg",icon:"addr",infoWindow:{type:"html",basics:"\x3cdiv transclude=\"iw\"\x3e\x3c/div\x3e",_:0},geocode:"",ofid:"0x35b178472e21ea0b:0x96250a629064a256"}]}, panel:"......", panelStyle:"", panelId:0, printheader:"......", addressbook:{......}, signed_in:true
}, "state"); }
这里我们主要要得到 overlays 这个属性的里 markers 这个列队,如果查询没结果那就不存在这个列队。但是你可能发现这里并没有我们需要的经纬度,里面都是 lat:0,lng:0 ,不过没关系一般来说每个 Marker 对象里面都有个 mapabcPoiid 属性。这是一个 Mapabc 的地理译码,我们将通过这个编号去 Mapabc 那里得到经纬度。
在这个例子里面我们得到了 “BE000005CB” 。 下面我们将用到一个 Mapabc 的接口 http://mapgoogle.mapabc.com/mapabcpoi?pco=a;BE000005CB&cburl=ditu.google.com%2Fmapfiles%2Fmapabc_poiid_callback.html 这个接口里的 pco 参数就是我们刚才得到的那个编码。看看会得到什么结果!对得我们得到了一个 notpcoStrbase64 = MTIwLjg3MDQzNCwzMi4wMTE2MjM= 这样的字面。notpcoStrbase64 的值是一个base64编码。这个编码就是我们要的经纬度,经过base64解码后就是 120.870434,32.011623 我们想要的经纬度。
行车路线(Directions)
这个的原理基本上和 Geocoding 一样。同样是在 ditu.google.com 做一个 Get 请求。http://ditu.google.com/maps?f=d&hl=zh_CN&geocode=&saddr=江苏省南通通州市&daddr=江苏省南通&output=js 这个就是 f 的值不同,还有就是多了起始点(saddr)和终点(daddr ),同样需要 output=js 。我们得到如下Js代码
function onLoad() { var w = window.parent; w = w.parent; w.loadVPage( { title:"from: 江苏省南通通州市 to: 江苏省南通 - Google 地图", vartitle:"", url:"/maps?f=d\x26hl=zh_CN\x26geocode=\x26saddr=%E6%B1%9F%E8%8B%8F%E7%9C%81%E5%8D%97%E9%80%9A%E9%80%9A%E5%B7%9E%E5%B8%82\x26daddr=%E6%B1%9F%E8%8B%8F%E7%9C%81%E5%8D%97%E9%80%9A\x26ie=UTF8", urlViewport:false, ei:"nkneRojXN6OcjQPXyL2FAw", form:{selected:"d",q:{q:"from: 江苏省南通通州市 to: 江苏省南通"},l:{q:"",near:"江苏省南通"},d:{saddr:"江苏省南通通州市",daddr:"江苏省南通",mabc_saddr:"BE0000020F",mabc_daddr:"BE000005CB"},geocode:"",g:{q:"from: 江苏省南通通州市 to: 江苏省南通"},k:{q:"from: 江苏省南通通州市 to: 江苏省南通"}}, query:{type:"d"}, stickyFlags:{hl:"zh_CN"}, viewport:{center:{lat:37.649034,lng:106.435547},span:{lat:23.730996999999999,lng:39.902343999999999},mapType:""}, resolvedPOIID:true, modules:[""], overlays:{sxcar:false}, panel:"正在计算行车路线,请稍候......", panelStyle:"", panelId:0, printheader:"......", addressbook:{......}, signed_in:true }, "state"); }
这段代码其所要得到的是也可以使用 Geocoding 得到的起点和终点的 Mapabc 编码“ mabc_saddr:“BE0000020F”,mabc_daddr:“BE000005CB” ” 。接下来我们就使用 Mapabc 的另外一个接口http://mapgoogle.mapabc.com/mapabc/mapabcrouting?param=BE0000020F;BE000005CB&url= 这个接口的 param 参数里的两个编码很明确就是我们刚才得到的起始点和终点。打开这个链接的源代码,发现Js里有 routetext 和 polyline 这两个变量,代码太长就不贴出来了。这两个变量的值都是base64编码,我们把他还原看看。routetext 就是一个路线的文本描述,是一个 Xml 文件形式。
<?xml version="1.0" encoding="UTF-8"?> <RoutingJ OK="T"> <Count>7</Count> <Item> <Turn></Turn> <Road>石江线</Road> <Dire>南</Dire> <Dist>2046</Dist> </Item> <Item> <Turn>进入环岛</Turn> <Road>335省道</Road> <Dire>西</Dire> <Dist>10433</Dist> </Item> <Item> <Turn>减速行驶</Turn> <Road>335省道</Road> <Dire>西</Dire> <Dist>2538</Dist> </Item> <Item> <Turn>左转</Turn> <Road>外环东路</Road> <Dire>南</Dire> <Dist>2137</Dist> </Item> <Item> <Turn>右转</Turn> <Road>人民东路</Road> <Dire>西</Dire> <Dist>3136</Dist> </Item> <Item> <Turn>左转</Turn> <Road>濠东路</Road> <Dire>南</Dire> <Dist>683</Dist> </Item> <Item> <Turn>右转</Turn> <Road>濠南路</Road> <Dire>西</Dire> <Dist>275</Dist> </Item> </RoutingJ>
怎么用这个就不用说了。还有个参数是地图上的画的 polyline ,这个还原有应该是Js代码,但我还原后总是乱码,应该是我的转换程序的编码问题,而且这段代码应该是直接可以套用在 Google API 上的。

[Comment ID #266965 Will Be Quoted Here]
是啊,这个问题感觉很怪,能不能给个具体的例子啊,3q。
[Comment ID #266872 Will Be Quoted Here]
能否给个程序例子参考,如何获得这些参数?在js里如何访问这2个http接口获得返回数据呢?还是不太明白。
[Comment ID #266736 Will Be Quoted Here]
既然out js 那我们就当成一个JS文件好了。直接调用onLoad这个函数,获得里面的参数岂不是就OK了。
如何从 http://ditu.google.com/maps?f=q&hl=zh_CN&q=南通&output=js 返回的HTML代码中获取到 overlays 属性???难道用正则表达式实现???
老鼠XD,http://ditu.google.com/maps?f=q&hl=zh_CN&q=南通&output=js 获取到的是 html 代码,用JS怎么去解析 html 代码,又没有具体的层次结构,难道用 正则表达式??
是这样的,“|” 所分割的代码的段数是和 routetext 里面的item的数量是相对应的。关于中文的问题,可以看看这个。http://dev.csdn.net/article/27/27056.shtm
祝你好运,如果成功回来告诉一下。关键是对polyline的解码。
polyline应该是用来画折线的,虽然节点数量与routetext中的线路数量一致,但与地图中实际的折线数量并不相当.地图上的折线要复杂得多.那么这个polyline中所记录的应该是线状的道路的信息.就”|”所分隔的代码长度来看不可能是所有关键点经纬度值对,应该是某条道路的编码之类.
另:有没有支持中文的base64解码工具,我还原的routetext值中的中文是乱码.
[Comment ID #214527 Will Be Quoted Here]
这个“|”是polyline列队的分隔符,你了解一下 base64 的编码所包含的字符就会知道这个是不可能有 “|” 的。而且这个列队的长度是和 ditu 返回的线路数量符合的。至于怎么还原我也没找到具体的办法,总是乱码,估计是编码的问题,或者是谷歌加密了。
polyline的值中包含有”|”,那么它是base64编码吗?用什么方式可以还原呢?能否解答一二?谢谢了.