关于chunked gzip,socket下载网页内容.

分类: Python Spider 2009-08-05 19:21 1496人阅读 评论(0) 收藏 举报

socket 服务器 浏览器 python firefox 搜索引擎

 

在利用底层socket下载html网页的时候,java,python都有很方面的类库操作,可以如果是利用c++来写,就必须要利用socket,底层的操作,首先建立socket,然而,发送响应的request header,模拟浏览器的请求也可,只需将user-agent,修改浏览器的名称,比如ie,比如firefox,也可以是rober,比如搜索引擎的名称,这些东西网上很多,不再写了,这里只写关于chunked的数据提取与解压.

 

 

 

如果我们请求的头之中,有Accept-Encoding, gzip, deflate,并且对方的服务器支持gzip方式的数据话,服务器就会以gzip的方式为客户端传输数据,在客户端浏览器会为我们解压,通过情况下,服务器都会带上Content-Length代表所需要求发送的数据的长度,客户的socket从响应头之中取出这个数据,作为一个标准,需要从服务器接收多少字节的数据,但是,有时候,服务器不会带上这个响应头,但是却带上了另一个响应头Transfer-encoding: chunked,代表数据是以chunk的方式进行传输的。

 

所谓的chunk是如下的格式:

第一个chunk数据的字节数+/r/n+第一个chunk的数据+第二个chunk的数据的字节数+/r/n+数据+n个chunk+/r/n+0+/r/n。

 

因此,接收的时候,需要首先获取每一个字节的长度,然后,跳过2个字节,取出数据,然后,再跳过2个字节,获取下一个chunk的长度,直到最后一个chunk,最后一个chunk一定是0,并且字节的长度都是十六进制形式传输,需要进行相应的转化成十进制,如果是gzip格式的数据,那么,在最后完成所有数据组合之后,需要再解压,如果不是以chunk方式的传输,直接解压即可.

 

在网上google了半天,转载最多的是下面的一篇http://www.donevii.com/post/468.html,但是,并没有相应的处理代码,在此记下我的处理的代码.

 

 

[python] view plain copy print ?

1. if(chunk==True):  
2. '/r')  
3. '/n')  
4. #获取第一个chunk的十六进制长度str,以/r/n结束.
5. '/r/n')  
6. 0:temp]  
7. 16)#转化成十进制
8. ''
9. 2
10. 2
11. ''
12. #循环处理所有的chunk
13. while(readbytes>0):  
14. #获取这一部分数据,与以前数据拼加.
15.         newcont+=content[offset:readbytes+offset]  
16.         offset+=readbytes  
17. '/r/n',offset+2)  
18. if(endtemp>-1):  
19. 2:endtemp]  
20. 16)  
21. if(readbytes==0):  
22. break
23. else:  
24. 2
25. #代替以前的数据.
26.     content=newcont  
27. #print 'adfafa'+content
28. print
29. try:  
30. #如果是gzip方式的数据,需要解压,如果是chunked的数据,不进行上面的操作,直接解压是不能正
31. #常解压的.
32. if(contentType=='gzip'):  
33.         compressedstream = StringIO.StringIO(content)  
34.         gzipper = gzip.GzipFile(fileobj=compressedstream)   
35.         content=gzipper.read()  
36.           
37. except
38. print

 if(chunk==True): content=content.lstrip('/r') content=content.lstrip('/n') #获取第一个chunk的十六进制长度str,以/r/n结束. temp=content.find('/r/n') strtemp=content[0:temp] readbytes=int(strtemp,16)#转化成十进制 newcont='' start=2 offset=temp+2 newcont='' #循环处理所有的chunk while(readbytes>0): #获取这一部分数据,与以前数据拼加. newcont+=content[offset:readbytes+offset] offset+=readbytes endtemp=content.find('/r/n',offset+2) if(endtemp>-1): strtemp=content[offset+2:endtemp] readbytes=int(strtemp,16) if(readbytes==0): break else: offset=endtemp+2 #代替以前的数据. content=newcont #print 'adfafa'+content print contentType try: #如果是gzip方式的数据,需要解压,如果是chunked的数据,不进行上面的操作,直接解压是不能正 #常解压的. if(contentType=='gzip'): compressedstream = StringIO.StringIO(content) gzipper = gzip.GzipFile(fileobj=compressedstream) content=gzipper.read() except IOError,e: print e


 

 

以上就是部分python的socket的下载数据部分代码,关于在于需要提取每一个chunk的长度,然后,提取数据,如果还有下一个chunk,接着处理,直到最后的一个chunk以/r/n+0+/r/n结束,代表所有的chunk已经传递完毕.









 

在利用底层socket下载html网页的时候,java,python都有很方面的类库操作,可以如果是利用c++来写,就必须要利用socket,底层的操作,首先建立socket,然而,发送响应的request header,模拟浏览器的请求也可,只需将user-agent,修改浏览器的名称,比如ie,比如firefox,也可以是rober,比如搜索引擎的名称,这些东西网上很多,不再写了,这里只写关于chunked的数据提取与解压.

 

 

 

如果我们请求的头之中,有Accept-Encoding, gzip, deflate,并且对方的服务器支持gzip方式的数据话,服务器就会以gzip的方式为客户端传输数据,在客户端浏览器会为我们解压,通过情况下,服务器都会带上Content-Length代表所需要求发送的数据的长度,客户的socket从响应头之中取出这个数据,作为一个标准,需要从服务器接收多少字节的数据,但是,有时候,服务器不会带上这个响应头,但是却带上了另一个响应头Transfer-encoding: chunked,代表数据是以chunk的方式进行传输的。

 

所谓的chunk是如下的格式:

第一个chunk数据的字节数+/r/n+第一个chunk的数据+第二个chunk的数据的字节数+/r/n+数据+n个chunk+/r/n+0+/r/n。

 

因此,接收的时候,需要首先获取每一个字节的长度,然后,跳过2个字节,取出数据,然后,再跳过2个字节,获取下一个chunk的长度,直到最后一个chunk,最后一个chunk一定是0,并且字节的长度都是十六进制形式传输,需要进行相应的转化成十进制,如果是gzip格式的数据,那么,在最后完成所有数据组合之后,需要再解压,如果不是以chunk方式的传输,直接解压即可.

 

在网上google了半天,转载最多的是下面的一篇http://www.donevii.com/post/468.html,但是,并没有相应的处理代码,在此记下我的处理的代码.

 

 



[python] view plain copy print ?

1. if(chunk==True):  
2. '/r')  
3. '/n')  
4. #获取第一个chunk的十六进制长度str,以/r/n结束.
5. '/r/n')  
6. 0:temp]  
7. 16)#转化成十进制
8. ''
9. 2
10. 2
11. ''
12. #循环处理所有的chunk
13. while(readbytes>0):  
14. #获取这一部分数据,与以前数据拼加.
15.         newcont+=content[offset:readbytes+offset]  
16.         offset+=readbytes  
17. '/r/n',offset+2)  
18. if(endtemp>-1):  
19. 2:endtemp]  
20. 16)  
21. if(readbytes==0):  
22. break
23. else:  
24. 2
25. #代替以前的数据.
26.     content=newcont  
27. #print 'adfafa'+content
28. print
29. try:  
30. #如果是gzip方式的数据,需要解压,如果是chunked的数据,不进行上面的操作,直接解压是不能正
31. #常解压的.
32. if(contentType=='gzip'):  
33.         compressedstream = StringIO.StringIO(content)  
34.         gzipper = gzip.GzipFile(fileobj=compressedstream)   
35.         content=gzipper.read()  
36.           
37. except
38. print

if(chunk==True): content=content.lstrip('/r') content=content.lstrip('/n') #获取第一个chunk的十六进制长度str,以/r/n结束. temp=content.find('/r/n') strtemp=content[0:temp] readbytes=int(strtemp,16)#转化成十进制 newcont='' start=2 offset=temp+2 newcont='' #循环处理所有的chunk while(readbytes>0): #获取这一部分数据,与以前数据拼加. newcont+=content[offset:readbytes+offset] offset+=readbytes endtemp=content.find('/r/n',offset+2) if(endtemp>-1): strtemp=content[offset+2:endtemp] readbytes=int(strtemp,16) if(readbytes==0): break else: offset=endtemp+2 #代替以前的数据. content=newcont #print 'adfafa'+content print contentType try: #如果是gzip方式的数据,需要解压,如果是chunked的数据,不进行上面的操作,直接解压是不能正 #常解压的. if(contentType=='gzip'): compressedstream = StringIO.StringIO(content) gzipper = gzip.GzipFile(fileobj=compressedstream) content=gzipper.read() except IOError,e: print e

 

以上就是部分python的socket的下载数据部分代码,关于在于需要提取每一个chunk的长度,然后,提取数据,如果还有下一个chunk,接着处理,直到最后的一个chunk以/r/n+0+/r/n结束,代表所有的chunk已经传递完毕.