You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Scapy无法捕获完整HTML代码?技术求助

问题原因分析

你遇到的问题核心是TCP分段导致的响应不完整:

  • 当HTTP响应内容长度超过网络MTU(通常为1500字节)时,服务器会把响应拆分成多个TCP数据包发送。
  • sr1()仅能捕获第一个响应包,自然只能拿到部分HTML内容。
  • 原脚本存在冗余操作:既执行了send(getPacket)又调用sr1(getPacket),相当于重复发送两次GET请求;且发送带数据的TCP包后,未更新本地seq号,后续交互逻辑存在隐患。
修复方案

以下是两种可行的修复方式,优先推荐第一种,代码更简洁可靠:

方案1:利用Scapy自动处理TCP流

Scapy的sr()可以自动完成TCP三次握手与分段重组,无需手动实现握手逻辑:

from scapy.all import *
from scapy.layers.http import HTTP, HTTPRequest

website = input("Website (e.g www.example.com): ")

# 构造完整GET请求,指定请求路径为根目录
get_request = IP(dst=website) / TCP(dport=80, flags='PA') / HTTP() / HTTPRequest(
    Host=website,
    Method='GET',
    Path='/'
)

# 发送请求并接收所有响应包,timeout可根据网络情况调整
responses, _ = sr(get_request, timeout=5, verbose=0)

# 拼接所有响应中的Raw数据段
full_response = b""
for pkt in responses:
    if Raw in pkt[1]:
        full_response += pkt[1][Raw].load

# 提取HTML正文(跳过HTTP响应头)
html_content = full_response.split(b"\r\n\r\n", 1)[1] if b"\r\n\r\n" in full_response else full_response
print(html_content.decode('utf-8'))

方案2:手动处理TCP分段与ACK

若需手动实现三次握手,需捕获所有响应包并正确维护TCP的seq/ack号:

from scapy.all import *
from scapy.layers.http import HTTP, HTTPRequest
from scapy.layers.inet import IP, TCP

website = input("Website (e.g www.example.com): ")

# 完成TCP三次握手
syn = IP(dst=website) / TCP(dport=80, flags='S')
syn_ack = sr1(syn, verbose=0)
ack = IP(dst=website) / TCP(sport=syn_ack.dport, dport=80, flags='A', seq=syn_ack.ack, ack=syn_ack.seq + 1)
send(ack, verbose=0)

# 构造GET请求,发送后更新本地seq号
get_pkt = IP(dst=website) / TCP(sport=syn_ack.dport, dport=80, flags='PA', seq=syn_ack.ack, ack=syn_ack.seq + 1) / HTTP() / HTTPRequest(Host=website, Method='GET', Path='/')
send(get_pkt, verbose=0)

data_len = len(get_pkt[TCP].payload)
local_seq = syn_ack.ack + data_len

# 捕获所有响应包并拼接数据,同时发送ACK确认
full_data = b""
def capture_response(pkt):
    nonlocal full_data, local_seq
    if TCP in pkt and pkt[TCP].dport == syn_ack.dport and pkt[TCP].seq == local_seq - data_len + len(full_data):
        if Raw in pkt:
            full_data += pkt[Raw].load
        # 发送ACK确认已接收的数据
        ack_pkt = IP(dst=website) / TCP(sport=syn_ack.dport, dport=80, flags='A', seq=local_seq, ack=pkt[TCP].seq + len(pkt[TCP].payload))
        send(ack_pkt, verbose=0)
        # 检测FIN标志,判断是否为最后一个包
        if 'F' in pkt[TCP].flags:
            return True

sniff(prn=capture_response, timeout=5, verbose=0)

# 提取HTML正文
html_content = full_data.split(b"\r\n\r\n", 1)[1] if b"\r\n\r\n" in full_data else full_data
print(html_content.decode('utf-8'))
关键注意点
  • 避免重复发送请求:原脚本的重复发送操作会干扰响应捕获,应仅保留一次请求发送逻辑。
  • 严格维护TCP seq/ack号:每次发送数据后,seq号需加上发送的数据长度;每次接收数据后,ack号需加上接收的数据长度。
  • 使用多包捕获方法:sr1()仅能获取单个响应包,处理分段响应需用sr()或sniff()捕获所有相关数据包。

内容的提问来源于stack exchange,提问作者Flqmmable

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 04:28:17