我想在 python 中重播任意原始 HTTP 请求。 例如,让我们使用从我的 Chromium 浏览器到 Google 的任意 GET 请求:
GET / HTTP/1.1
Host: google.de
Cookie: CONSENT=PENDING+071; AEC=ARSKqsKvfEvPS9Vp1bDM6YMPdHpVOoH357W-7q3cqtdDwYeHf3MqPEO1xA; SOCS=CAISHAgBEhJnd3NfMjAyMzAyMjMtMF9SQzEaAmRlIAEaBgiAn-WfBg; NID=511=N6YvXcWd_hnVVnV8w6JK4jscqE2pEt8MuTrw3yZJp-84ZxV6RJLee_yj2DEo2UJuOse0sqLjdnAD7qgPw9al7aEJqsQOCAQPIs21rLy5HQ5IAoObj7icI7ayKJttejI9Va2jDFkk0ZLvUC7P_VPJuxRJyhvLspqU1YVUcYCThrYizbo; 1P_JAR=2023-2-25-20
Sec-Ch-Ua: "Not A(Brand";v="24", "Chromium";v="110"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Linux"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.78 Safari/537.36
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.7
X-Client-Data: CO3/ygE=
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close
因为我希望我的请求看起来与上面完全一样,一个明显的方法是使用套接字库:
def send(host, port, message):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((host, port))
s.sendall(message)
print("%s" % message.decode('us-ascii'))
data = s.recv(1024)
print("%s" % data)
但是,那样的话,我显然不能使用 TLS 或代理(不编写我自己的库)。
所以,我认为请求库值得一试,因为它已经支持开箱即用的 TLS 和代理。但是我不知道如何加载我想重播的 HTTP 请求。 我想图书馆不是为此而设计的。
我可以尝试这样的事情(来自文档):
from requests import Request, Session
s = Session()
req = Request('POST', url, data=data, headers=headers)
prepped = req.prepare()
# do something with prepped.body
prepped.body = 'No, I want exactly this as the body.'
# do something with prepped.headers
del prepped.headers['Content-Type']
resp = s.send(prepped,
stream=stream,
verify=verify,
proxies=proxies,
cert=cert,
timeout=timeout
)
print(resp.status_code)
但我仍然必须首先手动解析请求的标头。 如果有图书馆可以解决这个问题?
感谢您的参与!
TLS 可以与套接字一起使用;你只需要将它包裹在
ssl
库套接字中。
但是,有 很多 库可以做到这一点,所以你不必自己使用 TLS。
您可以使用 aioreq 库,这是一个简单的异步 HTTP 客户端,可用于发送原始 HTTP 请求消息。
Aioreq
不支持原始请求的代理,但它确实允许您做很多有趣的事情,看看 HTTP 协议是如何工作的。
这是你的要求(没有
Cookie
标题,它很大:D)。
import asyncio
import aioreq
import socket
async def main():
hostname = "google.de"
transport = aioreq.Transport()
await transport.make_connection(
ip=socket.gethostbyname(hostname),
port=443,
ssl=True, # True if you want to use SSL/TLS
server_hostname=hostname
)
raw_request_bytes = ("GET / HTTP/1.1\r\n"
"Host: google.de\r\n"
'Sec-Ch-Ua: "Not A(Brand";v="24", "Chromium";v="110"\r\n'
"Sec-Ch-Ua-Mobile: ?0\r\n"
'Sec-Ch-Ua-Platform: "Linux"\r\n'
"Upgrade-Insecure-Requests: 1\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.78 Safari/537.36\r\n"
'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.7\r\n'
"X-Client-Data: CO3/ygE=\r\n"
"Sec-Fetch-Site: none\r\n"
"Sec-Fetch-Mode: navigate\r\n"
"Sec-Fetch-User: ?1\r\n"
"Sec-Fetch-Dest: document\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"Accept-Language: en-US,en;q=0.9\r\n"
"Connection: close\r\n\r\n"
).encode("ascii")
status_line, headers_line, content = await transport.send_http_request(
raw_request_bytes
)
resp = aioreq.parsers.ResponseParser.parse(status_line, headers_line, content)
print(resp)
asyncio.run(main())
因此,我们有变量
resp
,这是我们的 HTTP 响应及其所有必需的属性,例如(.headers,.content,.status,...)