socket下载网页时gzip编码HTTP响应解压失败问题咨询
问题原因
你遇到的报错是两个操作错误共同导致的:
- 响应头存在
Transfer-Encoding: chunked字段,说明返回的响应体是分块传输格式,你看到的272b是当前分块的十六进制长度标识,并非gzip内容的一部分,你直接将这部分和gzip内容一起保存,自然会触发gzip格式校验失败。 - 你使用
decode("utf-8", "ignore")处理包含gzip二进制的响应数据,会直接破坏gzip的二进制结构,就算提前剥离分块标识也无法正常解压,整个处理流程必须基于原始二进制数据完成,不能随意转字符串。
正确处理步骤
- 全程接收
socket返回的原始二进制数据,不要执行任何decode操作 - 以
b'\r\n\r\n'为分隔符切割二进制数据,前半部分为HTTP响应头,后半部分为带分块标识的响应体 - 解析分块格式,提取纯gzip压缩数据:
分块传输的格式规则为:[十六进制块长度]\r\n[对应长度的二进制内容]\r\n,重复该结构直到遇到长度为0的终止块。你需要循环读取每块的长度,截取对应长度的二进制内容拼接,得到的就是完整的gzip压缩数据。 - 直接用gzip或者zlib模块解压提取到的纯gzip数据即可得到原始HTML内容。
示例修复代码
import socket import zlib port = 80 # 假设ip、path、website变量已赋值 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip, port)) http_message = "GET /" + path + " HTTP/1.1\r\n" http_message += "Host: " + website + "\r\n" http_message += "Accept: text/html\r\n" http_message += "Accept-Language: en-US,en;q=0.9\r\n" http_message += "Accept-Encoding: gzip, deflate\r\n" http_message += "User-Agent: Chrome/92.0.4515.131 Mozilla/5.0 (X11; Linux x86_64)\r\n" http_message += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n" # 不需要长连接建议直接设为close,避免接收多余数据 http_message += "Connection: close\r\n" http_message += "\r\n" sock.send(http_message.encode()) # 接收完整二进制响应 raw_data = b'' while True: chunk = sock.recv(4096) if not chunk: break raw_data += chunk sock.close() # 拆分响应头和响应体 header_end = raw_data.find(b'\r\n\r\n') response_header = raw_data[:header_end].decode('utf-8') response_body = raw_data[header_end+4:] # 解析分块内容 gzip_data = b'' offset = 0 while True: # 读取分块长度行 line_end = response_body.find(b'\r\n', offset) if line_end == -1: break # 转换十六进制长度为十进制 chunk_len = int(response_body[offset:line_end].decode('utf-8'), 16) if chunk_len == 0: break # 截取当前块的gzip内容 gzip_data += response_body[line_end+2 : line_end+2+chunk_len] # 移动偏移到下一个块 offset = line_end + 2 + chunk_len + 2 # 解压gzip内容,16+zlib.MAX_WBITS参数用于识别gzip格式 html_content = zlib.decompress(gzip_data, 16+zlib.MAX_WBITS).decode('utf-8') print(html_content)
内容的提问来源于stack exchange,提问作者Aditya Verma
相关产品推荐
相关产品推荐

