Python socket发HTTP GET请求如何仅存响应正文及优化大文件接收
问题解决指南
核心问题1:去除HTTP响应头仅保存正文
标准HTTP响应结构中,响应头和正文之间通过\r\n\r\n(连续两个回车换行,对应可视化的空行)分隔,仅需要定位到该分隔符的位置,截取之后的内容即为纯正文内容。
核心问题2:大文件接收不全+缓冲区大小疑问
recv(bufsize)的参数是单次调用最多接收的字节数上限,并非必须接收满bufsize才会返回:如果当前TCP缓冲区可用数据小于bufsize,会直接返回现有数据,因此把缓冲区设为500000字节这类较大值,对2000字节的小文件没有任何负面影响。
大文件接收不全的原因是:单次recv最多只能返回bufsize大小的内容,大文件会被拆分为多个TCP包传输,必须循环调用recv才能收全所有内容。另外你使用的HTTP/1.1协议默认开启长连接,服务器发完内容不会主动断开连接,会导致最后recv进入阻塞状态,有两种常见解决思路:
- 在请求头中添加
Connection: close,通知服务器发完响应就主动断开连接,此时recv返回空字节就代表所有内容接收完成 - 解析响应头里的
Content-Length字段,按照指定的长度接收对应字节数的正文,精准度更高
修正后的完整代码
import socket clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) clientSocket.connect((host_name, server_port)) # 请求头新增Connection: close,通知服务器发完内容主动断开 request = ("GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n" % (file_name, host_name)).encode() clientSocket.send(request) # 循环接收所有响应内容,缓冲区保持4096常用值即可 received_bytes = b'' while True: chunk = clientSocket.recv(4096) if not chunk: break received_bytes += chunk clientSocket.close() received_msg = received_bytes.decode() # 定位响应头和正文的分隔符 header_sep = '\r\n\r\n' sep_pos = received_msg.find(header_sep) if received_msg.startswith("HTTP/1.1 404 Not Found"): print(index + 1, ".", url, "is not found") else: # 截取分隔符之后的纯正文内容写入文件 content = received_msg[sep_pos + len(header_sep):] with open(only_file_name, 'w', encoding='utf-8') as received_txt_file: received_txt_file.write(content)
补充说明
如果遇到乱码问题,可以根据响应头Content-Type字段里的charset参数,调整decode和文件写入时的编码格式即可。
内容的提问来源于stack exchange,提问作者Bilkent Ogrencisi
相关产品推荐
相关产品推荐

