Python服务商上传微信图片获取MediaID

新建一个微信相关的文件,例如we_chat.py

# 标准库
import json
import random
import hashlib
import time
import os

# 第三方库
import requests
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as signature_pkcs_v1_5
from Crypto.Cipher import PKCS1_v1_5 as cipher_pkcs_v1_5
import base64



class WeChat(object):
    """ 微信通用类 """

    def __init__(self):
        self.sp_appid = "你的appid"  # 服务商申请的公众号appid
        self.sp_mchid = "你的服务商户号"  # 服务商户号,由微信支付生成并下发
        self.sub_mchid = "你的子商户的商户号"  # 子商户的商户号,由微信支付生成并下发
        self.notify_url = "https://www.xxxxxxx.com"  # 通知地址
        self.mchid = "服务商户号"  # 服务商户号
        self.serial_no = "xxxxxxxxxxxxx"  # 商户号证书序列号

    def upload_image(self, image, filename, sha256):
        """
        # 图片上传
        # 官方文档: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter2_1_1.shtml
        :param file: 图片文件  将媒体图片进行二进制转换,得到的媒体图片二进制内容,在请求body中上传此二进制内容。
        媒体图片只支持JPG、BMP、PNG格式,文件大小不能超过2M
        :param filename: 文件名称  商户上传的媒体图片的名称,商户自定义,必须以JPG、BMP、PNG为后缀。示例值:filea.jpg
        :param sha256: 文件摘要  图片文件的文件摘要,即对图片文件的二进制内容进行sha256计算得到的值。示例值:hjkahkjsjkfsjk78687dhjahdajhk
        :return:
        {
        "media_id": "H1ihR9JUtVj-J7CJqBUY5ZOrG_Je75H-rKhTG7FUmg9sxNTbRN54dFiUHnhg
        rBQ6EKeHoGcHTJMHn5TAuLVjHUQDBInSWXcIHYXOeRa2OHA"
        }
        """
        url = "https://api.mch.weixin.qq.com/v3/merchant/media/upload"
        time_stamps = str(int(time.time()))
        random_str = self.nonce_str()
        meta_raw = json.dumps(
            {
                "filename": filename,
                "sha256": sha256
            }
        )
        data_list = []
        boundary = 'boundary'
        data_list.append(('--' + boundary).encode('utf-8'))
        data_list.append(('Content-Disposition: form-data; name="meta";').encode('utf-8'))
        data_list.append(('Content-Type: multipart/form-data;').encode('utf-8'))
        data_list.append(('').encode('utf-8'))
        data_list.append((meta_raw).encode('utf-8'))
        data_list.append(('--' + boundary).encode('utf-8'))
        data_list.append(('Content-Disposition: form-data; name="file"; filename="' + filename + '"').encode('utf-8'))
        data_list.append(('Content-Type: ' + "image/jpg").encode('utf-8'))
        data_list.append(('').encode('utf-8'))
        data_list.append(image)
        data_list.append(('--' + boundary + '--').encode('utf-8'))
        data_list.append(('').encode('utf-8'))
        body = b'\r\n'.join(data_list)
        method = 'POST'
        url_ = '/v3/merchant/media/upload'
        sign_str = method + "\n" + url_ + "\n" + time_stamps + "\n" + random_str + "\n" + meta_raw + "\n"
        sign = self.RSA_sign(sign_str)
        Authorization = 'WECHATPAY2-SHA256-RSA2048 mchid="' + self.mchid + '",nonce_str="' + random_str + '",signature="' + sign + '",timestamp="' + time_stamps + '",serial_no="' + self.serial_no + '"'
        headers = {
            'Authorization': Authorization,
            'Content-Type': 'multipart/form-data; boundary=' + boundary
        }
        response = requests.post(url, data=body, headers=headers).json()
        print(response)
        return response

    def Sha256(self, image):
        """ 对二进制进行加密 """
        hash = hashlib.sha256()
        hash.update(image)
        return hash.hexdigest()

    def nonce_str(self):
        # 生成随机字符
        chars = 'abcdefghigklmnopqrstuvwxyz0123456789'
        strs = []
        for x in range(32):
            strs.append(chars[random.randrange(0, len(chars))])
        return "".join(strs).upper()

    def RSA_sign(self, data):
        # 使用私钥构建签名
        basedir = os.path.abspath(os.path.dirname(__file__))
        priKey = RSA.importKey(open(f'{basedir}/你的私钥文件.pem').read())
        signer = signature_pkcs_v1_5.new(priKey)
        hash_obj = SHA256.new(data.encode('utf-8'))
        signature = base64.b64encode(signer.sign(hash_obj)).decode('utf8')
        return signature

we_chat_pay_merchant_sign_in = WeChat()

下面是获取图片并返回MediaId的逻辑

首先从前端得到图片,然后保存到服务器某个地址中,然后读取出来转为二进制(从前端直接将图片转二进制也可以,直接将取到的 image.read() 就可以)

# 下面是伪代码,只是简介逻辑
from 你上面新建的we_chat文件 import we_chat_pay_merchant_sign_in
# 从前端获取图片文件
image = request.FILES.get("image")
image_name = image.name

# 保存图片的操作,并且拿到图片路径

# image_media就是获取到的MediaID
image_media = get_media_id(保存的图片路径, image_name)

def get_media_id(保存的图片路径, image_name):
    with open(保存的图片路径, "rb") as f:
        image = f.read()
    sha256 = we_chat_pay_merchant_sign_in.Sha256(image)
    image_media = we_chat_pay_merchant_sign_in.upload_image(image, image_name, sha256)
    return image_media

上面的we_chat.py 文件内容是主要的获取逻辑,我也是参照文档中PHP的示例摸索过来的。

如果会报签名错误的问题,只要是按照文件中的逻辑写就不会有问题,一般都是请求报文body内的排版有问题

 

posted @ 2022-11-30 10:13  SlookUP  阅读(134)  评论(0编辑  收藏  举报