我想使用HTTP协议(当然还有套接字)中定义的方法从HTTP服务器下载示例图像。
我试图实现它,但似乎我的代码不会下载整个图像,无论我是否有while
循环。
示例图片在这里:https://httpbin.org/image/png。
我的代码只下载部分图片,我不知道如何修复它。我不想使用任何库,例如urllib
,我只想使用套接字。
有什么想法吗?
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('httpbin.org', 80))
s.sendall('GET /image/png HTTP/1.1\r\nHOST: httpbin.org\r\n\r\n')
reply = ""
while True:
data = s.recv(2048)
if not data: break
reply += data
# get image size
size = -1
tmp = reply.split('\r\n')
for line in tmp:
if "Content-Length:" in line:
size = int(line.split()[1])
break
headers = reply.split('\r\n\r\n')[0]
image = reply.split('\r\n\r\n')[1]
# save image
f = open('image.png', 'wb')
f.write(image)
f.close()
答案 0 :(得分:2)
import socket
import select
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('httpbin.org', 80))
s.sendall(b'GET /image/png HTTP/1.1\r\nHOST: httpbin.org\r\n\r\n')
reply = b''
while select.select([s], [], [], 3)[0]:
data = s.recv(2048)
if not data: break
reply += data
headers = reply.split(b'\r\n\r\n')[0]
image = reply[len(headers)+4:]
# save image
f = open('image.png', 'wb')
f.write(image)
f.close()
注意这个例子并不完美。优雅的方法应该是检查Content-Length
标题和recv
确切的数据长度。 (而不是将3
秒硬编码为超时。)如果服务器可以使用分块编码,则会变得更加复杂。)
-
示例在python 3中
答案 1 :(得分:2)
您正在执行HTTP / 1.1请求。此HTTP版本隐式表现为Connection: keep-alive
已设置。这意味着服务器可能无法在您的代码中按预期发送响应后立即关闭TCP连接,但可能会保持连接处于打开状态以等待更多HTTP请求。
当用HTTP / 1.0替换版本时,服务器在请求完成后关闭连接并且图像完成,因为HTTP / 1.0暗示Connection: close
。
除此之外:HTTP比你想象的要复杂得多。如果您真的想要自己实施HTTP,请不要在您已经看到的某些示例消息之后设计代码,但实际上是在阅读并按照 standards进行设计。