吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2824|回复: 20
收起左侧

[Python 原创] 将httpcanary导出的request转换为postman可识别导入的格式

[复制链接]
mumuki 发表于 2023-3-15 22:35
本帖最后由 mumuki 于 2023-3-15 22:48 编辑

最近在抓包分析数据的过程中,因为Android7以后对用户证书做了进一步限制,导致charles无法再抓取https的数据,无奈只能通过虚拟机和httpcanary在手机上抓包。
但在分析请求的时候还是在pc上比较方便,并且通过postman方便统一管理接口。但是httpcanary导出的request.json无法被postman识别,于是便写了一个脚本来方便转化数据格式。
(贴下项目的github地址:https://github.com/LaytonLee/hc2pm ,欢迎大家star~~)

使用示例:

python hc2pm.py -i ~/Downloads/hc-req -c postman_collection -o ~/Downloads/b.json

参数:

  • -h: 查看帮助
  • -i: 待转换文件/目录,必须
  • -c: postman中的collection名称,必须
  • -o: 结果输出文件,必须

下面直接贴代码:

#! /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("://")[0]
                self.host = raw.split("://")[1].split("/")[0].split(".")
                self.path = raw.split("://")[1].split("?")[0].split("/")[1:]

                self.query = list(map(lambda x: {"key": x.split("=")[0], "value": x.split("=")[1]}, raw.split("?")[1].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[HeaderItem] = 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[PMRequest] = 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[PostmanData.PMRequest.HeaderItem()] = []
    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[PostmanData.PMRequest] = []

    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(".")[0])

            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)

效果展示:


截屏2023-03-15 下午10.31.17.png

免费评分

参与人数 5吾爱币 +11 热心值 +5 收起 理由
wushaominkk + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
萌新与小白 + 1 + 1 热心回复!
phoenixtien + 1 我很赞同!
xixicoco + 1 + 1 粗略看了下,做了键值的转换,不知道有没有处理gzip的情况??
uzcool + 2 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

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 进行抓包 ,手机端的 不会
lingwushexi 发表于 2023-3-16 09:42
不错的方法,感谢分享
 楼主| mumuki 发表于 2023-3-16 10:06
amtf0614 发表于 2023-3-16 09:29
只会在PC端F12 进行抓包 ,手机端的 不会

有些网页为了隐藏接口,直接返回的html,对这些网页抓取数据就会很麻烦
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?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-1-10 00:44

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表