【问题标题】:Why I can't get complete data from using Google Map api?为什么我无法使用 Google Map api 获取完整数据?
【发布时间】:2013-10-02 10:16:23
【问题描述】:

我创建了一个 Python 项目来测试 google map api。我在测试第一个 API 时遇到了问题:Nearby Search Requests。

我试过这个 url 官方文档提供: https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=-33.8670522,151.1957362&radius=500&types=food&name=harbour&sensor=false&key=AddYourOwnKeyHere 如果我把这个网址放在我的浏览器上,我会在浏览器上得到完美的数据。然后我什么也没做,只创建了一个 python 模块,代码如下:

if __name__ == '__main__':  

import socket
import ssl 


sock = ssl.wrap_socket(socket.socket()) 
sock.connect(('maps.googleapis.com', 443)) 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('maps.googleapis.com', 443))
sslSocket = socket.ssl(s)
uri = 'GET /maps/api/place/nearbysearch/json?location=-33.8670522,151.1957362&radius=500&sensor=false&key=MyKey HTTP/1.1\r\nHost:maps.googleapis.com\r\nContent-Type: application/json; charset=UTF-8\r\naccept-encoding:gzip,deflate,sdch\r\n\r\n'
sslSocket.write(uri)

data = sock.read()
print 'going to connect...'
print data 
s.close()

不幸的是,我在控制台上得到的结果是这样的:

going to connect...
HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
Date: Wed, 02 Oct 2013 08:05:59 GMT
Expires: Wed, 02 Oct 2013 08:10:59 GMT
Cache-Control: public, max-age=300
Vary: Accept-Language
Server: mafe
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Alternate-Protocol: 443:quic
Transfer-Encoding: chunked

560b
{
"debug_info" : [],
"html_attributions" : [
"Listings by \u003ca href=\"http://www.yellowpages.com.au/\"\u003eYellow           Pages\u003c/a\u003e"],
"next_page_token" : "ClRHAAAA4lOaMlZcUjyndIqhBsHzyyU0nD5PHarmjgmnguj3morn7Em-    ipqhSR33V__d0kjrL4PzAqY7y4TAK7Uj3XzWjhoUchLBcBs-    TNFxWIvGst8SEArmj_T7_eDZWyr8UDGy5OEaFPFaK2yHDg7Kv2U3Obsy7opkQfEw",
"results" : [
{
"geometry" : {
"location" : {
"lat" : -33.8599827,
"lng" : 151.2021282
},
"viewport" : {
"northeast" : {
"lat" : -33.8552584,
"lng" : 151.2031401
},

这个结果是不完整的,我试了很多次,结果都是一样的。那么,如何解决这个问题呢?

【问题讨论】:

  • 不知道是不是和google map api的https协议有关
  • 您为什么不使用urllibPython Requests 之类的东西来发出HTTP 请求?我从未见过有人使用套接字与 HTTP 服务通信。

标签: python http ssl https request


【解决方案1】:

问题是您正在为 HTTP 使用套接字。具体来说,sock.read()不保证能读取到对方已经发送的所有字节;相反,您必须不断询问它,直到它返回一个空字节字符串。然后你可以确定你已经收到了所有东西。但是,套接字真的很棘手,使用它们几乎从来都不是一个好主意,而选择更高级别的框架几乎总是一个好主意。例如,即使ssl_sock.write() 可能实际上甚至不会写入所有内容(或者至少sock.send() 肯定会以这种方式运行)而是返回发送的字节数,如果这小于您传递给它的数据,您必须重试其余的(未发送的)数据。

现在,对于 HTTP,我从未见过有人使用套接字。而是在urllib2 中使用urllib2.urlopen(...) 之类的东西,或者更好的Python Requests。此外,还有urllibhttplib。例如,使用 Python 请求,您的代码将变得如此简单:

import requests

response = requests.get('https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=-33.8670522,151.1957362&radius=500&sensor=false&key=MyKey')
data = response.json()  # shortcut to `import json; json.loads(response.text)`

安装 Python 请求的最简单方法是使用 pip install requests(或 easy_install requests)。或者,如果您更愿意避免依赖:

import json
import urllib

data_raw = urllib.urlopen('https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=-33.8670522,151.1957362&radius=500&sensor=false&key=MyKey').read()
data = json.loads(data_raw)

现在,data 保证包含整个响应;你永远不会得到部分回复。

P.S.如果您需要在请求中传递一些 HTTP 请求标头,您也可以这样做:

requests.get(url, headers={...})

P.P.S.如果您想了解有关原始套接字的更多信息(希望仅用于非 HTTP 用途),请参阅 The Python Socket Programming HOWTO

【讨论】:

  • 感谢您的回答。我尝试了你的方法并获得了完整的数据。我只使用socket的原因是我不能保证我使用的服务器可以很好地与其他lib一起使用。
  • @VincentWang:不需要这样的保证:如果它是 HTTP/HTTPS 服务器,它与 HTTP 客户端库一起工作,特别是因为它是 Google 服务器——没有怀疑 Google 不符合 HTTP 标准的理由。
【解决方案2】:

help(sock.read) 给出:

模块 ssl 中读取方法的帮助:

ssl.SSLSocket 实例的read(self, len=1024) 方法 最多读取 LEN 个字节并返回它们。 在 EOF 上返回零长度字符串。

您的回复接近 1024 个字符,因此请尝试:

data = '  '
while len(data) > 0:
    data = sock.read()
    print data,
print "\nDone."

【讨论】:

  • 虽然在技术上是正确的,但我认为帮助初学者使用原始套接字发出 HTTPS 请求并不是一个好主意 :) 他很快就会回来寻求有关解析标头之类的帮助;所以除非学习 HTTP 的内部结构,否则可能对他不利。
  • 确实如此但是,因为 OP 已经在提出原始请求......(这就是为什么我已经 +1 了你在发布我的答案时提出的答案)。跨度>
【解决方案3】:

数据在多次发送和接收中发送。 所以你应该运行一个循环来检查直到数据何时出现

receivedString = ""
While True:
    data = socket.recv(1024) #max length 1024
    #time.sleep(0.25)
    if(len(data) < 1):
       break
    recievedString = recievedString + data

【讨论】:

    【解决方案4】:

    第一个答案很酷。但有时你必须使用原始套接字来解决问题......

    所以我使用下面的代码尝试了我的 API 密钥

    data = '  '
    while len(data) > 0:
        data = sock.read()
        print data,
        print len(data)
    print "\nDone."
    

    虽然数据的长度有时是 1024,有时是 381,我不知道为什么。另外,程序不会跳出循环,这也让我很困惑。

    附:谁能解释一下响应内容开头的“560b”是什么意思,非常感谢。

    【讨论】:

    • -1 从现有答案 + 问题中复制粘贴 + 承认您不了解实际情况。
    猜你喜欢
    • 2019-08-01
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    • 2015-06-17
    • 2020-12-14
    • 1970-01-01
    • 2016-12-17
    • 2014-10-25
    相关资源
    最近更新 更多