注:以下文章原文来自于Dr Charles Severance 的 《Python for Informatics》
12.3 用HTTP协议获取一张图片
在上一节的例子中,我们获取的是一个有换行符的文本文件,并简单的把它显示在屏幕上。同样我们可以用一个小程序通过HTTP协议获取图片。下面这个程序运行时,不是直接在屏幕上显示数据,而是剔除头信息,然后将收到的数据合并保存为一个图片文件。具体代码如下:
import socket import time mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mysock.connect((‘www.py4inf.com‘, 80)) mysock.send(b‘GET http://www.py4inf.com/cover.jpg HTTP/1.0\n\n‘) count = 0 picture = b"" while True: data = mysock.recv(5120) if ( len(data) < 1 ) : break # time.sleep(0.25) count = count + len(data) print(len(data), count) picture = picture + data mysock.close() # Look for end of the header (2 CRLF) pos = picture.find(b"\r\n\r\n") print(‘Header length‘, pos) print(picture[:pos].decode("utf-8")) # Skip past the header and save the picture picture = picture[pos+4:] fhand = open("stuff.jpg", "wb") fhand.write(picture) fhand.close()
运行程序,输出如下:
5120 5120
5120 10240
5120 15360
5120 20480
5120 25600
5120 30720
960 31680
5120 36800
5120 41920
2384 44304
3752 48056
5120 53176
5120 58296
5120 63416
5120 68536
1767 70303
Header length 242
HTTP/1.1 200 OK
Date: Sat, 23 Apr 2016 06:51:38 GMT
Server: Apache
Last-Modified: Fri, 04 Dec 2015 19:05:04 GMT
ETag: "b294001f-111a9-526172f5b7cc9"
Accept-Ranges: bytes
Content-Length: 70057
Connection: close
Content-Type: image/jpeg
正如你看到的,它的内容类型头信息表明这个文档的主体是一张图片。一旦程序运行结束,你就可以用图片查看器打开stuff.jpg文件,你会发现这是本书的封面。
从程序运行过程中,可以看到我们并不是每次都接收到5120个字符。在我们调用recv()方法的那个时刻,我们收到的字符数和网页服务器发给我们的一样多。在这个例子中有960,2384到最多5120个字符。因为你的网速会有所不同,所以你的输出也会不同。同时要注意的是我们收到的最后一批码流是1767个,下一次调用recv()我们将收到零长度的字符串,这告诉我们服务器已调用close()关闭了它那端的套接字,并且不会再有数据发送过来。
我们可以取消time.sleep()的注释,减缓我们连续调用recv()的时间间隔。通过这种方式,我们在每次调用前等待1/4秒,从而让服务器赶上我们在调用recv()之前发送更多的数据。添加延时后程序的运行结果如下:
5120 5120
5120 10240
....
5120 66560
3743 70303
Header length 242
HTTP/1.1 200 OK
Date: Sat, 23 Apr 2016 07:38:55 GMT
Server: Apache
Last-Modified: Fri, 04 Dec 2015 19:05:04 GMT
ETag: "b294001f-111a9-526172f5b7cc9"
Accept-Ranges: bytes
Content-Length: 70057
Connection: close
Content-Type: image/jpeg
现在除了最后一次调用少于5120外,其它我们每次都接收到5120个(注:可能是网速的原因,译者的第一次接收也是5120个,而原文中第一次也小于5120)。这是服务器的发送和我们的接收共同约定的缓冲区容量。当我们采用延时接收时,在某些时刻服务器的发送可能填满这个缓冲区,从而不得不停止发送,只到我们的程序清空缓冲区。这个在发送和接收程序间的停顿被叫做流量控制。