将httpcanary导出的request转换为postman可识别导入的格式
本帖最后由 mumuki 于 2023-3-15 22:48 编辑最近在抓包分析数据的过程中,因为Android7以后对用户证书做了进一步限制,导致charles无法再抓取https的数据,无奈只能通过虚拟机和httpcanary在手机上抓包。
但在分析请求的时候还是在pc上比较方便,并且通过postman方便统一管理接口。但是httpcanary导出的request.json无法被postman识别,于是便写了一个脚本来方便转化数据格式。
(贴下项目的github地址:https://github.com/LaytonLee/hc2pm ,欢迎大家star~~)
使用示例:
```shell
python hc2pm.py -i ~/Downloads/hc-req -c postman_collection -o ~/Downloads/b.json
```
参数:
- `-h`: 查看帮助
- `-i`: 待转换文件/目录,必须
- `-c`: postman中的collection名称,必须
- `-o`: 结果输出文件,必须
下面直接贴代码:
```python
#! /usr/bin/python3
# -*- coding: UTF-8 -*-
"""hc2pm.
@Project : 将 HttpCanary App 导出的request.json转换为Postman可识别导入的json格式
@Author : layton
"""
import os
import logging
import json
from urllib.parse import unquote
import argparse
parser = argparse.ArgumentParser(
prog="hc2pm",
description="transform HttpCanary export request json format into postman import reqest format")
parser.add_argument("--input", "-i", help="待转换的文件或目录", required=True)
parser.add_argument("--collection", "-c", help="postman的collection名称", required=True)
parser.add_argument("--output", "-o", help="输出文件名(*.json)", required=True)
args = parser.parse_args()
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
log = logger = logging
SCHEMAS = {
"v2": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
}
class PostmanData():
class PMRequest():
class HeaderItem():
def __init__(self, key:str = None, value:str = None, type:str = None):
self.key = key
self.value = value
self.type = type
def __repr__(self) -> str:
return f"{{ key={self.key}, value={self.value}, type={self.type} }}"
class Url():
def __init__(self, raw:str = None):
self.raw = raw
self.protocal = raw.split("://")
self.host = raw.split("://").split("/").split(".")
self.path = raw.split("://").split("?").split("/")
self.query = list(map(lambda x: {"key": x.split("="), "value": x.split("=")}, raw.split("?").split("&")))
def __repr__(self) -> str:
return f"{{ raw={self.raw}, protocal={self.protocal}, host={self.host}, path={self.path}, query={self.query} }}"
def __init__(self, name:str = None, method:str = None, headers:list = None, url:Url = None):
self.name = name
self.request: dict() = {}
self.request["method"] = method
self.request["header"] = headers
self.request["url"] = url
self.response = list()
def __repr__(self) -> str:
return f"name={self.name}, request={self.request}, url={self.request['url']}"
def __init__(self, collection_name:str = None, scheme_version:str = "v2", items:list = None):
self.info: dict() = {}
self.info["_postman_id"] = "aaa"
self.info["name"] = collection_name
self.info["schema"] = SCHEMAS.get(scheme_version)
self.item = items
def __repr__(self) -> str:
return f"{{ info={self.info}, item={self.item} }}"
def to_json(self):
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=False, indent=4)
def hc2pm_file(file_path: str, request_name: str) -> PostmanData.PMRequest:
if not os.path.exists(file_path):
raise IOError(f"No such file: {file_path}")
return
hc_str = ""
with open(file_path, 'r') as f:
hc_str = f.read()
hc_json = json.loads(hc_str)
headers: list = []
for i_key, i_value in hc_json.get("headers").items():
header_item = PostmanData.PMRequest.HeaderItem(i_key, unquote(i_value), "default")
headers.append(header_item)
url = PostmanData.PMRequest.Url(unquote(hc_json.get("url")))
method = hc_json.get("method")
return PostmanData.PMRequest(request_name, method, headers, url)
def hc2pm_dir(dir):
pm_reqs: list = []
for item in os.listdir(dir):
sub_path = os.path.join(dir, item)
tmp_item: dict() = {}
if os.path.isdir(sub_path):
tmp_item["name"] = item
tmp_item["item"] = hc2pm_dir(sub_path)
pm_reqs.append(tmp_item)
if sub_path[-4:] == "json":
pm_req = hc2pm_file(sub_path, item.split("."))
pm_reqs.append(pm_req)
return pm_reqs
def hc2pm_collection(collection_name, hc_path):
if not os.path.exists(hc_path):
raise IOError(f"No such path: {hc_path}")
pm_req_data:list = None
if os.path.isfile(hc_path):
file_path, file_fullname = os.path.split(hc_path)
file_name, file_ext = os.path.splitext(file_fullname)
pm_req_data = hc2pm_file(hc_path, file_name)
if os.path.isdir(hc_path):
pm_req_data = hc2pm_dir(hc_path)
pm_coll_data = PostmanData(collection_name, "v2", pm_req_data)
return pm_coll_data
if __name__ == "__main__":
try:
pm_coll_data = hc2pm_collection(args.collection, args.input)
with open(args.output, 'w') as f:
f.write(pm_coll_data.to_json())
except Exception as e:
logger.error(e)
```
效果展示:
小黄鸟右上角,分享,导出curl,直接用apifox导入curl之后,可以直接变成py / go / c 之类的运行代码。postman也不是不行,就是不喜欢那些英文设置界面 土豆窝 发表于 2024-9-24 04:18
大佬你好,我按照你的方法导出Python代码,放pychar运行报了很多错误,是不是不适用所以的包呀?我的请求 ...
一般导出的错误有几种情况,需要你再检查以下里面的参数,比如时间戳或者curl里面的标点,就是英文单引号括起来的那些。如果实在不方便,你直接倒到天工里面试试 非常不错的项目,实际出发的小工具 谢谢 这样就方便多了 省很多时间 我更喜欢直接导出curl哈哈,不错的方案,谢谢楼主分享 只会在PC端F12 进行抓包 ,手机端的 不会 :'(weeqw 不错的方法,感谢分享 amtf0614 发表于 2023-3-16 09:29
只会在PC端F12 进行抓包 ,手机端的 不会
有些网页为了隐藏接口,直接返回的html,对这些网页抓取数据就会很麻烦{:1_908:} 安卓不是自己apk没法改fest的话,不想root的情况下,可以 virtual 或 太极 + JustTrustMe抓https包 首先感谢分享,其次为.......为啥不用cURL Thinkx 发表于 2023-3-16 10:22
安卓不是自己apk没法改fest的话,不想root的情况下,可以 virtual 或 太极 + JustTrustMe抓https包
是virtualxpose + 太极 + justtrustme?