kwork-api/scripts/mitmproxy-to-har.py
Claw 7b01544802 Add mitmproxy to HAR conversion tools
- scripts/mitmproxy-to-har.py: Конвертер mitm → HAR
- MITMPROXY.md: Инструкция по записи и конвертации
- Два способа: mitmweb (GUI) и mitmdump + скрипт
2026-03-22 22:36:34 +00:00

98 lines
3.7 KiB
Python

#!/usr/bin/env python3
"""
Convert mitmproxy flow dump to HAR format
Usage: mitmproxy-to-har.py <input.mitm> <output.har>
"""
import json
import sys
from datetime import datetime
from mitmproxy import io
from mitmproxy.http import HTTPFlow
def flow_to_har_entry(flow: HTTPFlow) -> dict:
"""Convert single flow to HAR entry."""
if not flow.request or not flow.response:
return None
entry = {
"startedDateTime": datetime.fromtimestamp(flow.request.timestamp_start).isoformat() + "Z",
"time": int((flow.response.timestamp_end - flow.request.timestamp_start) * 1000) if flow.response.timestamp_end else 0,
"request": {
"method": flow.request.method,
"url": flow.request.url,
"httpVersion": flow.request.http_version,
"headers": [{"name": k, "value": v} for k, v in flow.request.headers.items()],
"queryString": [{"name": k, "value": v} for k, v in flow.request.query.items()],
"cookies": [{"name": k, "value": v} for k, v in flow.request.cookies.items()],
"headersSize": -1,
"bodySize": len(flow.request.content) if flow.request.content else 0,
},
"response": {
"status": flow.response.status_code,
"statusText": flow.response.reason,
"httpVersion": flow.response.http_version,
"headers": [{"name": k, "value": v} for k, v in flow.response.headers.items()],
"cookies": [{"name": k, "value": v} for k, v in flow.response.cookies.items()],
"content": {
"size": len(flow.response.content) if flow.response.content else 0,
"mimeType": flow.response.headers.get("Content-Type", "unknown").split(";")[0],
"text": flow.response.get_text() if flow.response.content else ""
},
"redirectURL": flow.response.headers.get("Location", ""),
"headersSize": -1,
"bodySize": len(flow.response.content) if flow.response.content else 0,
},
"cache": {},
"timings": {
"send": 0,
"wait": int((flow.response.timestamp_start - flow.request.timestamp_end) * 1000) if flow.response.timestamp_start and flow.request.timestamp_end else 0,
"receive": int((flow.response.timestamp_end - flow.response.timestamp_start) * 1000) if flow.response.timestamp_end and flow.response.timestamp_start else 0,
}
}
# Add POST data if present
if flow.request.method == "POST" and flow.request.content:
entry["request"]["postData"] = {
"mimeType": flow.request.headers.get("Content-Type", "application/octet-stream"),
"text": flow.request.get_text() if flow.request.content else ""
}
return entry
def convert_mitm_to_har(input_file: str, output_file: str):
"""Convert mitmproxy dump to HAR."""
har = {
"log": {
"version": "1.2",
"creator": {
"name": "mitmproxy-to-har",
"version": "1.0"
},
"entries": []
}
}
with open(input_file, 'rb') as f:
reader = io.FlowReader(f)
for flow in reader.read():
if isinstance(flow, HTTPFlow):
entry = flow_to_har_entry(flow)
if entry:
har["log"]["entries"].append(entry)
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(har, f, indent=2, ensure_ascii=False)
print(f"Converted {len(har['log']['entries'])} flows to {output_file}")
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: mitmproxy-to-har.py <input.mitm> <output.har>")
sys.exit(1)
convert_mitm_to_har(sys.argv[1], sys.argv[2])