2012-08-24 54 views
1

我正在尝试向网站发送HTTP请求并读取它返回的数据。我尝试成功的第一个网站。它返回了大约4个数据包,然后返回了一个脚本捕获并终止的0包。如何阅读Python套接字recv

但是,试图加载http://www.google.com/不能这样工作。相反,它返回大约10个相同长度的数据包,最后一个较小的数据包,然后继续超时。这是否正常?这一切都取决于主机正在使用的服务器?

如果任何人都可以推荐一种用socket.recv()读取的替代方法,它会考虑到并不总是发送最终的空数据包,这将不胜感激。谢谢。

try: 
     data = s.recv(4096) 

     while True: 
      more = s.recv(4096) 
      print len(more) 
      if not more: 
       break 
      else: 
       data += more 
    except socket.timeout: 
     errMsg = "Connection timed-out while connecting to %s. Request headers were as  follows: %s", (parsedUrl.netloc, rHeader.headerContent) 
     self.logger.exception(errMsg) 
     raise Exception 
+0

你能用上面的代码编辑你的问题来查看你的请求吗? – sean

回答

2

对于HTTP,请使用requests而不是自己写。

> ipython 

In [1]: import requests 

In [2]: r = requests.get('http://www.google.com') 

In [3]: r.status_code 
Out[3]: 200 

In [4]: r.text[:80] 
Out[4]: u'<!doctype html><html itemscope="itemscope" itemtype="http://schema.org/WebPage">' 

In [5]: len(r.text) 
Out[5]: 10969 
3

TCP不给你“包”,但连续字节从对方发送。 这是一个流recv()为您提供当前可用的流的块。你将它们缝合在一起,并且解析的流内容。

HTTP是相当牵涉到协议手工,所以你可能想要开始一些现有的库,如httplib而不是。

+0

谢谢,但我不在寻找替代品。我想用套接字来解决这个问题。 –

+2

然后阅读这些HTTP RFC,找出如何解析头文件,计算响应体长度,处理不同的编码,管理持久连接等等。这很不容易,但已经完成了好几次。 –

+0

我明白这一点。我的一个问题是我无法完全掌握如何获取内容长度并使用它来获取其余内容。 –

2

可能是因为Google使用Keep-Alive来保持套接字处于打开状态以便提供进一步的请求。这需要解析报头并读取确切的字节数。

根据您使用的HTTP版本,您必须将Connection: Keep-Alive添加到您的头文件中。 (这可能是最简单的解决办法:只使用1.1 HTTP/1.0来代替。)

如果您使用该功能尽管如此,你必须接受你的数据的第一个块和

  1. 解析,如果有一个'\r\nContent-Length: '里面,如果是的话,取这个和下一个'\r\n'之间的字节并将它们转换为一个数字。那是你的尺寸。
  2. 看看您的数据中是否有'\r\n\r\n'。如果是这样,那就是你的头部结束了。从这里开始,您必须阅读上面提到的确切的字节数。

实施例:

import socket 
s = socket.create_connection(('www.google.com', 80)) 
s.send("GET/HTTP/1.1\r\n\r\n") 
x = s.recv(10000) 
poscl = x.lower().find('\r\ncontent-length: ') 
poseoh = x.find('\r\n\r\n') 
if poscl < poseoh and poscl >= 0 and poseoh >= 0: 
    # found CL header 
    poseocl = x.find('\r\n',poscl+17) 
    cl = int(x[poscl+17:poseocl]) 
    realdata = x[poseoh+4:] 

现在,必须在cl内容长度和在有效载荷realdata数据(开始)。该请求丢失的字节数是missing = cl - len(realdata)。如果是0,那么你已经拥有了一切;如果没有,则执行s.read(missing)并重新计算missing,直到它为零。

上面的代码是要完成的工作的simppe开始;还有一些地方你可能需要在recv()之前继续进行。

这是相当compliated。更简单的方法将是

  1. 使用HTTP 1。1的Connection: close标头请求
  2. 使用HTTP 1.0,
  3. 使用为此任务制作的库之一,而不是重新发明轮子。
+0

什么是读取字节的最佳方式?只需使用len()? –

+0

再想一想:'len()'你会使用什么?这没有道理......不,你必须解析答案并采取适当的行动。我会更新答案。 – glglgl