使用Python Socket仅返回响应头而非JS内容的问题求助
问题
我想要从网站的JS文件中提取链接,用Python的Socket模块获取该JS文件,但始终只拿到响应头,无法获取实际的JS内容。我的代码如下:
import socket import ssl sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) cont = ssl.create_default_context() sock.connect(('blog.clova.line.me', 443)) sock = cont.wrap_socket(sock, server_hostname = 'blog.clova.line.me') sock.sendall('GET /hs/hsstatic/HubspotToolsMenu/static-1.138/js/index.js HTTP/1.1\r\nHost: blog.clova.line.me\r\n\r\n'.encode()) resp = sock.recv(2048) print(resp.decode('utf-8'))
返回内容只有响应头:
HTTP/1.1 200 OK Date: Tue, 06 Sep 2022 12:02:38 GMT Content-Type: application/javascript Transfer-Encoding: chunked Connection: keep-alive CF-Ray: 74670e8b9b594c2f-SIN Age: 3444278 ...
我试过两种方法:
- 设置
Content-Type: text/plain; charset=utf-8请求头 - 将请求头修改为
GET https://blog.clova.line.me/hs/hsstatic/HubspotToolsMenu/static-1.138/js/index.js HTTP/1.1
别人用Socket能拿到响应头后的HTML/JS数据,但我不行。用requests模块却能正常获取内容:
resp = requests.get('https://blog.clova.line.me/hs/hsstatic/HubspotToolsMenu/static-1.138/js/index.js') print(resp.text)
不想用第三方模块,怎么用原生Socket实现类似requests的效果?
解决方法
问题核心在于**分块传输编码(Transfer-Encoding: chunked)**和单次recv仅读取了部分数据。服务器返回的响应头标注了Transfer-Encoding: chunked,说明内容是分块返回的,而你只调用了一次recv(2048),只能拿到响应头和少量(或完全拿不到)正文数据。
要完整获取JS内容,需要:
- 循环调用
recv直到接收完所有数据 - 解析分块编码的内容,拼接成完整的JS代码
修正后的代码如下:
import socket import ssl def parse_chunked_data(sock): full_data = b'' while True: # 读取块大小(十六进制格式) chunk_size_line = b'' while b'\r\n' not in chunk_size_line: chunk_size_line += sock.recv(1) chunk_size = int(chunk_size_line.strip(), 16) if chunk_size == 0: # 读取结束标记后的空行 sock.recv(2) break # 读取对应大小的块内容 chunk_content = b'' while len(chunk_content) < chunk_size: chunk_content += sock.recv(chunk_size - len(chunk_content)) full_data += chunk_content # 读取块末尾的换行符 sock.recv(2) return full_data # 建立SSL连接 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ssl_context = ssl.create_default_context() sock.connect(('blog.clova.line.me', 443)) sock = ssl_context.wrap_socket(sock, server_hostname='blog.clova.line.me') # 发送HTTP请求,添加Connection: close让服务器主动关闭连接 request = ( 'GET /hs/hsstatic/HubspotToolsMenu/static-1.138/js/index.js HTTP/1.1\r\n' 'Host: blog.clova.line.me\r\n' 'Connection: close\r\n' '\r\n' ) sock.sendall(request.encode()) # 循环接收全部响应数据 response = b'' while True: received_part = sock.recv(4096) if not received_part: break response += received_part # 分离响应头和正文 header_separator = response.find(b'\r\n\r\n') response_headers = response[:header_separator].decode('utf-8') body_start = response[header_separator + 4:] # 根据编码类型处理正文 if 'Transfer-Encoding: chunked' in response_headers: # 先处理已接收的分块数据,再读取剩余部分 temp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) temp_sock = ssl_context.wrap_socket(temp_sock, server_hostname='blog.clova.line.me') temp_sock.connect(('blog.clova.line.me', 443)) temp_sock.sendall(request.encode()) # 跳过响应头 while b'\r\n\r\n' not in temp_sock.recv(4096): pass js_content = parse_chunked_data(temp_sock).decode('utf-8') temp_sock.close() else: js_content = body_start.decode('utf-8') print(js_content) sock.close()
关键细节说明:
- 添加
Connection: close请求头,让服务器发送完数据后主动关闭连接,便于判断接收结束 - 循环调用
recv直到没有数据返回,确保获取完整响应 - 实现
parse_chunked_data函数解析分块编码:先读取每个块的十六进制大小,再读取对应长度的内容,直到遇到大小为0的结束块 - 分离响应头和正文,根据是否为分块编码选择对应的解析逻辑
内容的提问来源于stack exchange,提问作者user19219732
相关产品推荐
相关产品推荐

