【问题标题】:Python sock.recv not getting all data from pagePython socket.recv 没有从页面获取所有数据
【发布时间】:2015-12-02 09:45:23
【问题描述】:

这对我学习如何进行低级套接字通信来说是非常困难的一步,但我真的很想学习这个,我遇到了困难,我似乎无法找到正确的方式。

如何获取所有数据?我已经尝试了多种方法,但只能获得部分响应。

我现在正在尝试的网址是:

http://steamcommunity.com/market/search/render/?query=&start=0&count=100&search_descriptions=0&sort_column=price&sort_dir=asc&appid=730&category_730_ItemSet%5B%5D=any&category_730_ProPlayer%5B%5D=any&category_730_TournamentTeam%5B%5D=any&category_730_Weapon%5B%5D=any&category_730_Rarity%5B%5D=tag_Rarity_Ancient_Weapon

经过研究,我尝试了这种方式,但仍然无法打印上面的完整 JSON 页面,我做错了什么吗?

        sock.send(request)
        response = ""
        first = True
        length = 0
        while True:
            partialResponse = sock.recv(65536)
            if len(partialResponse) != 0:
                #print("all %s" % partialResponse)
                # Extract content length from the first chunk
                if first:
                    startPosition = partialResponse.find("Content-Length")
                    if startPosition != -1:
                        endPosition = partialResponse.find("\r\n", startPosition+1)
                        length = int(partialResponse[startPosition:endPosition].split(" ")[1])
                    first = False
                # add current chunk to entire content
                response += partialResponse
                # remove chunksize from chunck
                startPosition = response.find("\n0000")
                if startPosition != -1:
                    endPosition = response.find("\n", startPosition+1)
                    response = response[0:startPosition-1] + response[endPosition+1:]
                if len(response[response.find("\r\n\r\n")+2:]) > length:
                    break
            else:
                break
        print response

【问题讨论】:

  • 如果你想要整个东西,你为什么要求最大 64K 字节?
  • 我应该要求的最大值是多少?
  • @ryachza 好吧,我已经尝试过打印对日志的响应,但每次响应都比 chrome 浏览器上显示的要短。
  • 嗯。就我而言 Brainfart - 考虑文件读取 :)

标签: python python-2.7 sockets python-sockets


【解决方案1】:

我能够复制该问题,并且似乎服务器没有返回内容长度标头,导致 if len(response[..]) > length 以长度 0 触发。将该语句更改为 if length > 0 and ... 似乎可以解决它。

我不得不将设置的超时时间从 0.3 秒增加到 0.5 秒,以便始终如一地获得响应。

我在 Chrome 中收到内容长度,但可能是因为内容编码是 gzip。我猜他们不会为未压缩的响应发送内容长度。

this document 的 Content-Length 部分将标头列为“应该”。

其他一般建议:我不会假设第一个块将始终包含所有标题。真的不应该打开“第一”。您可能应该阅读,直到遇到\r\n\r\n,它表示标头完成并单独处理它,后面的所有内容都是响应正文。

根据评论编辑:

对于快速而肮脏的事情,我可能会这样做:

response = ''
while True:
    chunk = sock.recv(65536)

    if len(chunk) == 0:
      break
    else:
      response += chunk

pieces = response.split('\r\n\r\n')

headers = pieces[0]
body = '\r\n\r\n'.join(pieces[1:])

print response
print body
print headers

print len(response), len(body), len(headers)

只需将套接字接收到的所有内容撕成一个字符串,根本不要尝试解释它。这将为您提供获得一切的最佳机会。

我绝对认为在这个级别上玩是一种很好的学习方式,并且完全值得每一刻。话虽如此,图书馆在这类事情上普遍受到青睐是有原因的。

HTTP 确实没有太多保证 - 它非常灵活并且有很多变数。因此,您需要从基本上没有期望/要求开始,并仔细建立不断思考“如果这个/那个”的想法。需要注意的一件事是分块可能发生在任何地方。一个块可能在标头完成之前中断,它甚至可能在\r\n 之间中断,这意味着您需要跨块解析以检测边界。对于常见用法,将整个响应读入内存可能不是问题,但当然,某些响应或其他要求可能会导致不切实际/不可能。

【讨论】:

  • 在没有我上面写的所有条件的情况下,有没有更简单或更有效的方法来接收所有页面?有点感觉工作量太大了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多