mumuki 发表于 2023-3-15 22:35

将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)
```

效果展示:

nullable 发表于 2023-3-18 10:44

小黄鸟右上角,分享,导出curl,直接用apifox导入curl之后,可以直接变成py / go / c 之类的运行代码。postman也不是不行,就是不喜欢那些英文设置界面

nullable 发表于 2024-9-25 09:22

土豆窝 发表于 2024-9-24 04:18
大佬你好,我按照你的方法导出Python代码,放pychar运行报了很多错误,是不是不适用所以的包呀?我的请求 ...

一般导出的错误有几种情况,需要你再检查以下里面的参数,比如时间戳或者curl里面的标点,就是英文单引号括起来的那些。如果实在不方便,你直接倒到天工里面试试

xixicoco 发表于 2023-3-16 04:51

非常不错的项目,实际出发的小工具

asd124689 发表于 2023-3-16 07:24

谢谢 这样就方便多了 省很多时间

mainblog 发表于 2023-3-16 09:05

我更喜欢直接导出curl哈哈,不错的方案,谢谢楼主分享

amtf0614 发表于 2023-3-16 09:29

只会在PC端F12 进行抓包 ,手机端的 不会 :'(weeqw

lingwushexi 发表于 2023-3-16 09:42

不错的方法,感谢分享

mumuki 发表于 2023-3-16 10:06

amtf0614 发表于 2023-3-16 09:29
只会在PC端F12 进行抓包 ,手机端的 不会

有些网页为了隐藏接口,直接返回的html,对这些网页抓取数据就会很麻烦{:1_908:}

Thinkx 发表于 2023-3-16 10:22

安卓不是自己apk没法改fest的话,不想root的情况下,可以 virtual 或 太极 + JustTrustMe抓https包

Sommuni 发表于 2023-3-17 11:25

首先感谢分享,其次为.......为啥不用cURL

mumuki 发表于 2023-3-18 10:25

Thinkx 发表于 2023-3-16 10:22
安卓不是自己apk没法改fest的话,不想root的情况下,可以 virtual 或 太极 + JustTrustMe抓https包

是virtualxpose + 太极 + justtrustme?
页: [1] 2 3
查看完整版本: 将httpcanary导出的request转换为postman可识别导入的格式