调用百度地图API报错‘211’ sn 校验失败

近日在Python 3.6中尝试了一下百度地图API,遇到一些问题,已经解决,在此记录,希望能给同惑者带来帮助。

先说问题:

1,尝试百度地图API的sn计算示例,遇到错误——{'status': 240, 'message': 'APP 服务被禁用'}

2,解决上述问题后,遇到新错误——{'status': 211, 'message': 'APP SN校验失败'}

上代码,这是地理编码的请求,即通过传递参数“百度大厦”获取对应的经纬度,默认百度坐标系。

# -*- coding: utf-8 -*- 
# 第一行必须有,否则报中文字符非ascii码错误
import urllib
import hashlib

# 以get请求为例http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=yourak
queryStr = '/geocoder/v2/?address=百度大厦&output=json&ak=yourak'

# 对queryStr进行转码,safe内的保留字符不转换
encodedStr = urllib.quote(queryStr, safe="/:=&?#+!$,;'@()*[]")

# 在最后直接追加上yoursk
rawStr = encodedStr + 'yoursk'

# md5计算出的sn值7de5a22212ffaa9e326444c75a58f9a0
# 最终合法请求url是http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=yourak&sn=7de5a22212ffaa9e326444c75a58f9a0
print hashlib.md5(urllib.quote_plus(rawStr)).hexdigest()

解决方案:

问题分析:

首先检查了一下控制台,发现所有可用服务都开启了。

没看出哪里有问题,后来偶然看到别的地理编码的请求方式和这个例子有点区别。区别如下:

http://api.map.baidu.com/geocoding/v3/?address=北京市海淀区上地十街10号&output=json&ak=您的ak&callback=showLocation

这里“/geocoding/v3”和上面示例代码的[queryStr = '/geocoder/v2/?address=百度大厦&output=json&ak=yourak']开头部分"/geocoder/v2/"不一样。替换之后没有在报错——{'status': 240, 'message': 'APP 服务被禁用'}。这里应该是API自身的服务代码做了修改,即废除了“/geocoder/v2/”替换为"/geocoding/v3"。

再说说第二个问题,sn校验失败就是说url请求传送到服务器后计算出的sn和我在本地计算的sn不一样。先看本地代码。

# _*_ encoding='utf-8' _*_

from urllib.request import urlopen, quote
from urllib import parse
from bs4 import BeautifulSoup
import requests
import hashlib
import json
    
if __name__=="__main__":
    home_url=r'http://api.map.baidu.com'
    # ak 和 sk 用数字0和6替换了,非真实
    my_ak='RVh62gHLF000000000000GyrG2uf34Gb'
    my_sk='0YWDV66666666666666rSwkjvy1YYo3D'
    # 以get请求为例http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=yourak
    queryStr = r'/geocoding/v3/?address=百度大厦&output=json&ak=RVh62gHLF000000000000GyrG2uf34Gb'

    # 对queryStr进行转码,safe内的保留字符不转换
    encodedStr = quote(queryStr, safe="/:=&?#+!$,;'@()*[]")
    print(encodedStr)

    # 在最后直接追加上yoursk
    rawStr = encodedStr + my_sk
    print(rawStr.encode('utf-8'))
    print(quote(rawStr).encode('utf-8'))

    #下面这行注释过的代码会报错,因为hashlib.md5('这里是瞒足某种编码的二进制码')
    #print(hashlib.md5(parse.quote(rawStr)).hexdigest())
    md = hashlib.md5()     #获取一个md5加密算法对象
    md.update(quote(rawStr).encode('utf-8'))   #制定需要加密的字符串
    sn=md.hexdigest()

两次计算的sn不同,有两种可能的原因:

1,本地hashlib.md5()的输入与服务器端hashlib.md5()的输入不同

2,Python 2.x和3.x 版本下hashlib.md5()的计算方式不同

验证阶段:

分别向两个版本下的hashlib.md5()输入了同样的数据,所得结果一样。看来不是第一种可能。

实际上Python 3.x中urllib下没有直接的quote(),即无法使用urllib.quote()。quote('特殊字符,比如中文')可将特殊字符进行url编码,

以防传输到服务器端变成乱码。这个编码功能到了urllib的两个子模块中urllib.requesturllib.parse里面,功能一样。经过测试发现

Python 2.x中quote()会将一个中文编码为两个十六进制码,而Python 3.x中会将一个中文编码为三个十六进制码。

#Python 2.x
import urllib
print quote('百度大厦')
%B0%D9%B6%C8%B4%F3%CF%C3  #长度8


#Python 3.x
from urllib.parse import quote
print(quote('百度大厦'))
%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6  #长度12

正是这个编码的区别使得我们在本地计算sn时url的中文转码和服务器端计算sn时的中文转码不同,因而得到不同的sn

解决方法:

用Python 2.x的quote()转码结果替换3.x的转码结果,或者直接在Python 2.x中计算sn,再拿到3.x的程序中用。毕竟,

我们不能改变服务器端的计算,只好去适应它。多说一句,今天安装Python 2.7.12时看到提示,大意是2020年起,Python 2.x

版本的服务将逐步停止,也许百度地图API的服务器端很快就要用3.x的计算结果了。到时候,我们这些API调用者就可以直接使用本地

计算的sn了。

最终url【http://api.map.baidu.com/geocoding/v3/?address=%B0%D9%B6%C8%B4%F3%CF%C3&output=json&ak=RVh62gHLFZjX345Yx7MlQGyrG2uf34Gb&sn=08ae4326e1758ba537b24516815ee6fc】,将这个链接在浏览器中打开可看到:

{"status":0,"result":{"location":{"lng":116.30695597357377,"lat":40.05738753357608},"precise":1,"confidence":80,"comprehension":100,"level":"商务大厦"}}

到此,已完成本文的工作!

 

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值