init
This commit is contained in:
188
README.md
188
README.md
@@ -1,92 +1,104 @@
|
|||||||
# kunpengFalsk
|
#bhrs_KPWXBotDemo
|
||||||
|
|
||||||
|
##安装依赖
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
|
||||||
|
##项目说明
|
||||||
|
|
||||||
|
1.基于 flask 框架 ,直观易懂,上手成本低
|
||||||
|
|
||||||
|
2.目前仅支持 http 通信方式
|
||||||
|
|
||||||
|
|
||||||
|
##项目文件说明
|
||||||
|
|
||||||
|
###WXBotService.py
|
||||||
|
1.封装了全部httpapi
|
||||||
|
|
||||||
|
2.提供了unicode转emoji方法
|
||||||
|
|
||||||
|
3.所有方法发送请求时自动emoji转unicode,自动添加鉴权
|
||||||
|
|
||||||
|
4.提供了本地下载图片和解密图片的方法(非httpapi)
|
||||||
|
|
||||||
|
###WXBotDemo.py
|
||||||
|
1.对绝大部分event类型判断
|
||||||
|
|
||||||
|
2.自动同意好友请求
|
||||||
|
|
||||||
|
3.自动下载表情包
|
||||||
|
|
||||||
|
4.自动解密图片
|
||||||
|
|
||||||
|
##提供的api列表
|
||||||
|
|
||||||
|
| HTTPAPI接口 | WXBotService方法 |
|
||||||
|
|--------------------|-------------------------------------|
|
||||||
|
| 初始化[K10001] | initialize |
|
||||||
|
| 添加日志[K10002] | add_log |
|
||||||
|
| 关注公众号[K10003] | follow_official_account |
|
||||||
|
| 转账收款[K10004] | transfer_receipt |
|
||||||
|
| 转账退款[K10005] | transfer_refund |
|
||||||
|
| 同意群聊邀请[K10006] | agree_group_invite |
|
||||||
|
| 消息免打扰[K10007] | message_not_disturb |
|
||||||
|
| 置顶聊天[K10008] | set_chat_top |
|
||||||
|
| 切换当前聊天对象[K10009] | change_chat |
|
||||||
|
| 获取群成员列表[K10010] | get_group_members_list |
|
||||||
|
| 获取企业群成员列表[K10011] | get_wecom_group_members_list |
|
||||||
|
| 创建群聊[K10012] | create_group |
|
||||||
|
| 修改群聊名称[K10013] | update_group_name |
|
||||||
|
| 发布群公告[K10014] | publish_group_announcement |
|
||||||
|
| 邀请群成员40人以上[K10015] | add_group_members_40_more |
|
||||||
|
| 添加群成员40人以下[K10016] | add_group_members_40_less |
|
||||||
|
| 删除群成员[K10017] | drop_group_member |
|
||||||
|
| 退出群聊[K10018] | quit_group |
|
||||||
|
| 获取群内昵称[K10019] | get_group_member_nickname |
|
||||||
|
| 修改群内昵称[K10020] | update_nickname_in_group |
|
||||||
|
| 显示或隐藏群成员昵称[K10021] | hide_group_member_nickname |
|
||||||
|
| 保存到通讯录[K10022] | save_to_address |
|
||||||
|
| 获取群成员邀请信息[K10023] | get_group_member_invite_information |
|
||||||
|
| 获取通讯录列表[K10024] | get_address_list |
|
||||||
|
| 获取企业好友列表[K10025] | get_wecom_friend_list |
|
||||||
|
| 获取指定好友信息[K10026] | get_friend_info |
|
||||||
|
| 网络获取指定好友信息[K10027] | get_net_friend_info |
|
||||||
|
| 删除好友[K10028] | del_friend |
|
||||||
|
| 修改好友备注[K10029] | update_friend_remark |
|
||||||
|
| 同意好友请求[K10030] | agree_friend_request |
|
||||||
|
| 好友状态检测[K10031] | friend_status_detection |
|
||||||
|
| 拉黑好友[K10032] | add_blacklist |
|
||||||
|
| 发送文本信息[K10033] | send_text_message |
|
||||||
|
| 发送图片信息[K10034] | send_image_message |
|
||||||
|
| 发送文件信息[K10035] | send_file_message |
|
||||||
|
| 发送GIF信息[K10036] | send_gif_message |
|
||||||
|
| 发送艾特信息[K10037] | send_at_message |
|
||||||
|
| 发送名片信息[K10038] | send_card_message |
|
||||||
|
| 发送链接信息[K10039] | send_link_message |
|
||||||
|
| 发送小程序信息[K10040] | send_applet_message |
|
||||||
|
| 转发信息[K10041] | relay_message |
|
||||||
|
| 取登录状态[K10042] | get_login_status |
|
||||||
|
| 撤回信息[K10043] | withdraw_message |
|
||||||
|
| 获取个人信息[K10044] | get_personal_info |
|
||||||
|
| 取登录账号列表[K10045] | get_login_list |
|
||||||
|
| 下载图片[K10046] | download_image |
|
||||||
|
| 解密图片[K10047] | decrypt_image |
|
||||||
|
| 发送XML信息[K10048] | send_xml_message |
|
||||||
|
| 刷新朋友圈[K10049] | refresh_moments |
|
||||||
|
| 获取朋友圈下一页[K10050] | get_moments_next_page |
|
||||||
|
| 获取个人朋友圈[K10051] | get_personal_moments |
|
||||||
|
| 朋友圈点赞[K10052] | moments_like |
|
||||||
|
| 朋友圈取消点赞[K10053] | moments_cancel_like |
|
||||||
|
|
||||||
|
##新增方法
|
||||||
|
|
||||||
|
| 说明 | WXBotService方法 |
|
||||||
|
|-------------------|----------------------|
|
||||||
|
| 本地下载图片 | local_download_image |
|
||||||
|
| 本地解密dat图片 | local_decrypt_image |
|
||||||
|
| emoji表情转unicode | emoji_to_unicode |
|
||||||
|
| unicode格式转emoji表情 | unicode_to_emoji |
|
||||||
|
| 鉴权计算 | crypt_md5 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Getting started
|
|
||||||
|
|
||||||
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
|
|
||||||
|
|
||||||
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
|
|
||||||
|
|
||||||
## Add your files
|
|
||||||
|
|
||||||
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
|
|
||||||
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd existing_repo
|
|
||||||
git remote add origin http://gitlab.yidooplanet.com/gitlab-instance-0a899031/kunpengfalsk.git
|
|
||||||
git branch -M main
|
|
||||||
git push -uf origin main
|
|
||||||
```
|
|
||||||
|
|
||||||
## Integrate with your tools
|
|
||||||
|
|
||||||
- [ ] [Set up project integrations](http://gitlab.yidooplanet.com/gitlab-instance-0a899031/kunpengfalsk/-/settings/integrations)
|
|
||||||
|
|
||||||
## Collaborate with your team
|
|
||||||
|
|
||||||
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
|
|
||||||
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
|
|
||||||
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
|
|
||||||
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
|
|
||||||
- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
|
|
||||||
|
|
||||||
## Test and Deploy
|
|
||||||
|
|
||||||
Use the built-in continuous integration in GitLab.
|
|
||||||
|
|
||||||
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
|
|
||||||
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
|
|
||||||
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
|
|
||||||
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
|
|
||||||
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
# Editing this README
|
|
||||||
|
|
||||||
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
|
|
||||||
|
|
||||||
## Suggestions for a good README
|
|
||||||
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
|
|
||||||
|
|
||||||
## Name
|
|
||||||
Choose a self-explaining name for your project.
|
|
||||||
|
|
||||||
## Description
|
|
||||||
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
|
|
||||||
|
|
||||||
## Badges
|
|
||||||
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
|
|
||||||
|
|
||||||
## Visuals
|
|
||||||
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
|
|
||||||
|
|
||||||
## Support
|
|
||||||
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
|
|
||||||
|
|
||||||
## Roadmap
|
|
||||||
If you have ideas for releases in the future, it is a good idea to list them in the README.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
State if you are open to contributions and what your requirements are for accepting them.
|
|
||||||
|
|
||||||
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
|
|
||||||
|
|
||||||
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
|
|
||||||
|
|
||||||
## Authors and acknowledgment
|
|
||||||
Show your appreciation to those who have contributed to the project.
|
|
||||||
|
|
||||||
## License
|
|
||||||
For open source projects, say how it is licensed.
|
|
||||||
|
|
||||||
## Project status
|
|
||||||
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
|
|
||||||
|
|||||||
245
WXBotDemo.py
Normal file
245
WXBotDemo.py
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
from flask import request, Flask
|
||||||
|
try:
|
||||||
|
import xml.etree.cElementTree as ET
|
||||||
|
except ImportError:
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
import WXBotService
|
||||||
|
from planet import planetXml
|
||||||
|
from lxml import etree
|
||||||
|
import xml.etree.ElementTree as ETree
|
||||||
|
|
||||||
|
wxbot = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@wxbot.route("/wxbot", methods=['get', 'post'])
|
||||||
|
def hello():
|
||||||
|
data = request.get_json()
|
||||||
|
t = threading.Thread(target=kp, args=(data, )) # 通过当前线程开启新的线程去执行
|
||||||
|
t.start()
|
||||||
|
return json.dumps({"Code": 0})
|
||||||
|
|
||||||
|
|
||||||
|
def kp(event_data):
|
||||||
|
# unicode [\\uxxxxx] 转 emoji 表情
|
||||||
|
event_data = json.loads(
|
||||||
|
WXBotService.unicode_to_emoji(
|
||||||
|
json.dumps(event_data, ensure_ascii=False), 'json'))
|
||||||
|
|
||||||
|
kp_log = '' # 定义鲲鹏日志消息
|
||||||
|
event_type = event_data.get('event_type')
|
||||||
|
account_wxid = event_data.get('account_wxid')
|
||||||
|
data = event_data.get('data')
|
||||||
|
msg_type = data.get('msgtype')
|
||||||
|
msg = data.get('content')
|
||||||
|
to_wxid = data.get('to_wxid')
|
||||||
|
to_name = data.get('to_name')
|
||||||
|
filepath = data.get("filepath")
|
||||||
|
subtype = data.get('subtype')
|
||||||
|
|
||||||
|
wxid = data.get('final_from_wxid')
|
||||||
|
wx_name = data.get('final_from_name')
|
||||||
|
group = None if data.get('from_wxid') == wxid else data.get('from_wxid')
|
||||||
|
group_name = None if data.get('from_name') == wx_name else data.get(
|
||||||
|
'from_name')
|
||||||
|
'''event类型判断'''
|
||||||
|
if event_type == 1001: # 1001 创建WeChat进程成功,通讯连接成功
|
||||||
|
kp_log = f'创建WeChat进程成功,通讯连接成功'
|
||||||
|
elif event_type == 1002: # 1002 登录成功
|
||||||
|
kp_log = f'登录成功 {data.get("nickname")}({data.get("wxid")})'
|
||||||
|
elif event_type == 1003: # 1003 账号注销登录
|
||||||
|
kp_log = f'账号注销登录 {data.get("wxid")} {data.get("reason")}'
|
||||||
|
elif event_type == 1004: # 1004 切换聊天对象事件
|
||||||
|
kp_log = f'切换聊天对象事件 {data.get("nickname")}({data.get("wxid")})'
|
||||||
|
elif event_type == 1005: # 1005 切换联系人事件
|
||||||
|
kp_log = f'切换联系人事件 {data.get("nickname")}({data.get("wxid")})'
|
||||||
|
elif event_type == 1007: # 1005 二维码刷新事件
|
||||||
|
kp_log = f'二维码刷新事件 {data.get("qrcode")}'
|
||||||
|
elif event_type == 1008: # 1008 连接断开
|
||||||
|
kp_log = f'连接断开'
|
||||||
|
elif event_type == 1009: # 1009 群员退群通知
|
||||||
|
member_list = []
|
||||||
|
for member in data.get('memberlist'):
|
||||||
|
member_list.append(
|
||||||
|
f'{member.get("nickname")}({member.get("wxid")})')
|
||||||
|
kp_log = f'群员退群通知 {",".join(member_list)} 退出了群聊 {data.get("roomname")}({data.get("roomid")}) ' \
|
||||||
|
f'人数:{data.get("membercount")}'
|
||||||
|
elif event_type == 1010: # 1010 群员进群通知
|
||||||
|
member_list = []
|
||||||
|
for member in data.get('memberlist'):
|
||||||
|
member_list.append(
|
||||||
|
f'{member.get("nickName")}({member.get("userName")})')
|
||||||
|
kp_log = f'群员进群通知 {",".join(member_list)} 加入了群聊 {data.get("roomname")}({data.get("roomid")})'
|
||||||
|
elif event_type == 1011: # 1011 收款消息
|
||||||
|
pay_msg = ET.fromstring(msg).find('paymsg')
|
||||||
|
pay_msg_type = pay_msg.findtext('PayMsgType')
|
||||||
|
if pay_msg_type == '9': # 二维码收款
|
||||||
|
status = pay_msg.findtext('status')
|
||||||
|
username = pay_msg.findtext('username')
|
||||||
|
display_name = pay_msg.findtext('displayname')
|
||||||
|
fee = pay_msg.findtext('fee')
|
||||||
|
if status == '0':
|
||||||
|
kp_log = f'收款消息 {display_name}({username}) 扫描收款二维码'
|
||||||
|
elif status == '1':
|
||||||
|
kp_log = f'收款消息 {display_name}({username}) 付款成功 {int(fee) / 100} 元'
|
||||||
|
elif status == '2':
|
||||||
|
kp_log = f'收款消息 {display_name}({username}) 取消付款'
|
||||||
|
elif pay_msg_type == '45': # 貌似有未收款转账或转账红包过期会触发 42 和 45 类型
|
||||||
|
pass # kp_log = f'收款消息 {pay_msg.findtext("fromusername")} {pay_msg.findtext("content")}'
|
||||||
|
elif event_type == 1040: # 1040 撤回消息事件
|
||||||
|
if not group:
|
||||||
|
kp_log = f'撤回消息事件 {wx_name}({wxid}) 撤回了 {msg}'
|
||||||
|
else:
|
||||||
|
kp_log = f'撤回消息事件 {wx_name}({wxid}) 从群 {group_name}({group}) 撤回了 {msg}'
|
||||||
|
elif event_type == 1100: # 1100 同步消息
|
||||||
|
if group:
|
||||||
|
type_str = f'同步消息 群聊消息 群聊:{group_name}({group}) 发送者:{wx_name}({wxid})'
|
||||||
|
elif 'gh_' in wxid:
|
||||||
|
type_str = f'同步消息 公众号消息 {wx_name}({wxid})'
|
||||||
|
elif '@openim' in wxid:
|
||||||
|
type_str = f'同步消息 企业微信消息 {wx_name}({wxid})'
|
||||||
|
else:
|
||||||
|
type_str = f'同步消息 私聊消息 {wx_name}({wxid})'
|
||||||
|
|
||||||
|
if data.get('isSender') == 1:
|
||||||
|
# 手机发送还是电脑发送这里判断不是很准确
|
||||||
|
if to_wxid == account_wxid:
|
||||||
|
type_str = f'机器人手机端 发送的 ' + type_str
|
||||||
|
else:
|
||||||
|
type_str = f'机器人电脑端 发送的 ' + type_str
|
||||||
|
|
||||||
|
if msg_type == 1: # 1 文本消息/自带表情
|
||||||
|
kp_log = f'{type_str} 文本消息 内容:{msg}'
|
||||||
|
elif msg_type == 3: # 3 图片消息
|
||||||
|
kp_log = f'{type_str} 图片消息 内容:{filepath}'
|
||||||
|
# 本地dat图片解密
|
||||||
|
decrypt_path = WXBotService.local_decrypt_image(
|
||||||
|
filepath, os.path.join(os.getcwd(), '解密图片'))
|
||||||
|
print(f'{type_str} 图片消息 解密路径:{decrypt_path}')
|
||||||
|
elif msg_type == 34: # 34 语言消息(需要在设置中打开语言自动转文字)
|
||||||
|
xml_msg = ET.fromstring(msg)
|
||||||
|
kp_log = f'{type_str} 语音消息 内容:{xml_msg.find("voicetrans").get("transtext")}'
|
||||||
|
elif msg_type == 37: # 37 好友请求
|
||||||
|
xml_msg = ET.fromstring(msg)
|
||||||
|
kp_log = f'同步消息 好友请求 {xml_msg.get("fromnickname")}({xml_msg.get("fromusername")}) ' \
|
||||||
|
f'验证内容:{xml_msg.get("content")}'
|
||||||
|
# 同意好友请求
|
||||||
|
WXBotService.agree_friend_request(account_wxid,
|
||||||
|
xml_msg.get('alias'),
|
||||||
|
xml_msg.get('encryptusername'),
|
||||||
|
xml_msg.get('ticket'),
|
||||||
|
xml_msg.get('scene'))
|
||||||
|
elif msg_type == 42: # 42 名片消息
|
||||||
|
xml_msg = ET.fromstring(msg)
|
||||||
|
kp_log = f'{type_str} 企业微信名片消息 {xml_msg.get("nickname")}({xml_msg.get("username")})'
|
||||||
|
elif msg_type == 43: # 43 视频消息
|
||||||
|
kp_log = f'{type_str} 视频消息 内容:{filepath}'
|
||||||
|
elif msg_type == 47: # 47 表情包
|
||||||
|
kp_log = f'{type_str} 表情包消息 网址:{ET.fromstring(msg).find("emoji").get("cdnurl".replace("amp;", ""))}'
|
||||||
|
# 本地下载图片
|
||||||
|
down_path = WXBotService.local_download_image(
|
||||||
|
msg, os.path.join(os.getcwd(), '下载图片'))
|
||||||
|
print(f'{type_str} 表情包消息 下载路径:{down_path}')
|
||||||
|
elif msg_type == 48: # 48 地理位置
|
||||||
|
kp_log = f'{type_str} 地理位置 内容:{msg}'
|
||||||
|
|
||||||
|
|
||||||
|
elif msg_type == 49: # 49 xml消息
|
||||||
|
# 获取根节点
|
||||||
|
root=ET.fromstring(msg)
|
||||||
|
|
||||||
|
# 微信好友的wxid
|
||||||
|
wxid='111'
|
||||||
|
for pagepath in xml_appmsg.iter('pagepath'):
|
||||||
|
print (pagepath.text) # 打印名字
|
||||||
|
pagepath.text =pagepath.text +f'/?wxid={wxid}'
|
||||||
|
print ('修改path',pagepath.text) # 打印名字
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
xml_appmsg = root.find('appmsg')
|
||||||
|
xml_title = xml_appmsg.findtext('title')
|
||||||
|
xml_type = xml_appmsg.findtext('type')
|
||||||
|
xml_des = xml_appmsg.findtext('des')
|
||||||
|
xml_url = xml_appmsg.findtext('url')
|
||||||
|
|
||||||
|
if xml_type == '1': # 1 文本
|
||||||
|
kp_log = f'收到 {wxid} xml文本消息'
|
||||||
|
elif xml_type == '3': # 3 歌曲
|
||||||
|
kp_log = f'{type_str} 音乐消息 歌曲:{xml_title} 歌手:{xml_des} 网址:{xml_url}'
|
||||||
|
elif xml_type == '5': # 5 链接
|
||||||
|
kp_log = f'{type_str} 链接消息 标题:{xml_title} 内容:{xml_des} 网址:{xml_url}'
|
||||||
|
print("kp_log--------------------------------",msg)
|
||||||
|
# 本身也是系统消息-link,会无线循环
|
||||||
|
# 判断是不是自己发的消息
|
||||||
|
if data.get('isSender') != 1:
|
||||||
|
WXBotService.send_link_message(
|
||||||
|
account_wxid, "wxid_w2imh7ki5s4q12", "title", "dec",
|
||||||
|
"https://www.baidu.com",
|
||||||
|
"https://p1-q.mafengwo.net/s17/M00/E3/9C/CoUBXl_cawCAQWMcAAGGhEoBcRU77.jpeg")
|
||||||
|
|
||||||
|
|
||||||
|
elif xml_type == '6': # 6 文件
|
||||||
|
kp_log = f'{type_str} 文件消息 文件名:{xml_title} 文件大小:{xml_des} 文件路径:{filepath}'
|
||||||
|
elif xml_type == '19': # 19 合并转发聊天记录
|
||||||
|
kp_log = f'{type_str} 合并转发聊天记录 文件名:{xml_title} 文件大小:{xml_des} 文件路径:{filepath}'
|
||||||
|
elif xml_type == '33': # 33 小程序
|
||||||
|
kp_log = f'{type_str} 小程序消息 小程序名:{xml_appmsg.findtext("sourcedisplayname")} 标题:{xml_title} ' \
|
||||||
|
f'appid:{xml_appmsg.findtext("weappinfo/appid")} ' \
|
||||||
|
f'pagepath:{xml_appmsg.findtext("weappinfo/pagepath")}'
|
||||||
|
print("---------------------------kp_log",msg)
|
||||||
|
# print("---------------------------kp_log",planetXml)
|
||||||
|
# print('msg---', msg)
|
||||||
|
# 发送小程序
|
||||||
|
if data.get('isSender') != 1:
|
||||||
|
WXBotService.send_xml_message(
|
||||||
|
account_wxid, "wxid_w2imh7ki5s4q12", msg
|
||||||
|
# account_wxid, "wxid_w2imh7ki5s4q12", planetXml
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
elif xml_type == '57': # 引用消息
|
||||||
|
kp_log = f'{type_str} 引用消息 内容:{msg}'
|
||||||
|
elif xml_type == '2000': # 2000 转账消息
|
||||||
|
money = xml_appmsg.findtext('wcpayinfo/feedesc').replace(
|
||||||
|
'¥', '')
|
||||||
|
pay_subtype = xml_appmsg.findtext('wcpayinfo/paysubtype')
|
||||||
|
transfer_id = xml_appmsg.findtext('wcpayinfo/transferid')
|
||||||
|
if pay_subtype == '1':
|
||||||
|
kp_log = f'{type_str} 转账消息 {money} 元'
|
||||||
|
# 自动接收转账
|
||||||
|
WXBotService.transfer_receipt(account_wxid, wxid,
|
||||||
|
transfer_id)
|
||||||
|
elif pay_subtype == '3':
|
||||||
|
kp_log = f'{type_str} 已收款 {money} 元 转账'
|
||||||
|
elif msg_type == 66: # 66 企业微信名片消息
|
||||||
|
xml_msg = ET.fromstring(msg)
|
||||||
|
kp_log = f'企业微信名片消息 {xml_msg.get("nickname")}({xml_msg.get("username")})'
|
||||||
|
elif msg_type == 10000: # 10000 系统消息
|
||||||
|
kp_log = f'系统消息 {wx_name}({wxid}) {msg}'
|
||||||
|
|
||||||
|
#获取通讯录
|
||||||
|
# allFriends=WXBotService.get_address_list(account_wxid)
|
||||||
|
# print('allFriends',allFriends)
|
||||||
|
# 发送H5链接
|
||||||
|
|
||||||
|
if not kp_log:
|
||||||
|
print(
|
||||||
|
'===================================================================================='
|
||||||
|
)
|
||||||
|
print(event_data)
|
||||||
|
print(
|
||||||
|
'===================================================================================='
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(kp_log)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
wxbot.run('127.0.0.1', 28369)
|
||||||
921
WXBotService.py
Normal file
921
WXBotService.py
Normal file
@@ -0,0 +1,921 @@
|
|||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
from io import BytesIO
|
||||||
|
from typing import Union
|
||||||
|
import xml.etree.cElementTree as ET
|
||||||
|
|
||||||
|
import emoji
|
||||||
|
import requests
|
||||||
|
|
||||||
|
import config
|
||||||
|
|
||||||
|
|
||||||
|
def initialize(app_id: str, app_name: str, app_ver: str, app_key: str) -> dict:
|
||||||
|
r"""初始化[K10001]
|
||||||
|
|
||||||
|
:param app_id: 软件唯一id,暂时随意
|
||||||
|
:param app_name: 软件名称
|
||||||
|
:param app_ver: 软件版本号
|
||||||
|
:param app_key: 软件Key,暂时随意
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10001', 'appId': app_id, 'appName': app_name, 'appVer': app_ver, 'appKey': app_key}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def add_log(api_type: str, msg: str) -> dict:
|
||||||
|
r"""添加日志[K10002]
|
||||||
|
|
||||||
|
:param api_type: 1调试,2警告,3提示
|
||||||
|
:param msg: 日志内容
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10002', 'type': api_type, 'msg': msg}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def follow_official_account(robot_wxid: str, from_wxid: str) -> dict:
|
||||||
|
r"""关注公众号[K10003]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 公众号的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10003', 'robotWxid': robot_wxid, 'fromWxid': from_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def transfer_receipt(robot_wxid: str, from_wxid: str, transfer_id: str) -> dict:
|
||||||
|
r"""转账收款[K10004]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 转账人的wxid
|
||||||
|
:param transfer_id: 收到的转账transferid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10004', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'transferid': transfer_id}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def transfer_refund(robot_wxid: str, from_wxid: str, transfer_id: str) -> dict:
|
||||||
|
r"""转账退款[K10005]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 转账人的wxid
|
||||||
|
:param transfer_id: 收到的转账transferid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10005', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'transferid': transfer_id}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def agree_group_invite(robot_wxid: str, from_wxid: str, url: str) -> dict:
|
||||||
|
r"""同意群聊邀请[K10006]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
:param url: 收到的消息里获取
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10006', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'url': url}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def message_not_disturb(robot_wxid: str, from_wxid: str, is_flag: str) -> dict:
|
||||||
|
r"""消息免打扰[K10007]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param is_flag: 是否免打扰,0/1
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10007', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'isFlag': is_flag}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def set_chat_top(robot_wxid: str, from_wxid: str, is_flag: str) -> dict:
|
||||||
|
r"""置顶聊天[K10008]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param is_flag: 是否置顶,0/1
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10008', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'isFlag': is_flag}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def change_chat(robot_wxid: str, from_wxid: str) -> dict:
|
||||||
|
r"""切换当前聊天对象[K10009]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10009', 'robotWxid': robot_wxid, 'fromWxid': from_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_group_members_list(robot_wxid: str, from_wxid: str) -> dict:
|
||||||
|
r"""获取群成员列表[K10010]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10010', 'robotWxid': robot_wxid, 'fromWxid': from_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_wecom_group_members_list(robot_wxid: str, from_wxid: str) -> dict:
|
||||||
|
r"""获取企业群成员列表[K10011]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 企业群的id
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10011', 'robotWxid': robot_wxid, 'fromWxid': from_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def create_group(robot_wxid: str, from_wxid: str) -> dict:
|
||||||
|
r"""创建群聊[K10012]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: wxid,用英文逗号分隔
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10012', 'robotWxid': robot_wxid, 'fromWxid': from_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def update_group_name(robot_wxid: str, from_wxid: str, new_name: str) -> dict:
|
||||||
|
r"""修改群聊名称[K10013]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
:param new_name: 新的群名称
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10013', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'newName': new_name}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def publish_group_announcement(robot_wxid: str, from_wxid: str, new_msg: str) -> dict:
|
||||||
|
r"""发布群公告[K10014]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
:param new_msg: 公告内容
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10014', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'newMsg': new_msg}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def add_group_members_40_more(robot_wxid: str, from_wxid: str, new_wxid: str) -> dict:
|
||||||
|
r"""邀请群成员40人以上[K10015]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
:param new_wxid: 邀请进群的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10015', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'newWxid': new_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def add_group_members_40_less(robot_wxid: str, from_wxid: str, new_wxid: str) -> dict:
|
||||||
|
r"""添加群成员40人以下[K10016]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
:param new_wxid: 邀请进群的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10016', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'newWxid': new_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def drop_group_member(robot_wxid: str, from_wxid: str, old_wxid: str) -> dict:
|
||||||
|
r"""删除群成员[K10017]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
:param old_wxid: 群成员的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10017', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'oldWxid': old_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def quit_group(robot_wxid: str, from_wxid: str) -> dict:
|
||||||
|
r"""退出群聊[K10018]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10018', 'robotWxid': robot_wxid, 'fromWxid': from_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_group_member_nickname(robot_wxid: str, from_wxid: str, old_wxid: str) -> dict:
|
||||||
|
r"""获取群内昵称[K10019]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
:param old_wxid: 群成员的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10019', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'oldWxid': old_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def update_nickname_in_group(robot_wxid: str, from_wxid: str, new_msg: str) -> dict:
|
||||||
|
r"""修改群内昵称[K10020]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
:param new_msg: 新的群内昵称
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10020', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'newMsg': new_msg}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def hide_group_member_nickname(robot_wxid: str, from_wxid: str, is_flag: str) -> dict:
|
||||||
|
r"""显示或隐藏群成员昵称[K10021]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
:param is_flag: 是否隐藏,0/1
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10021', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'isFlag': is_flag}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def save_to_address(robot_wxid: str, from_wxid: str, is_flag: str) -> dict:
|
||||||
|
r"""保存到通讯录[K10022]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
:param is_flag: 是否保存,0/1
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10022', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'isFlag': is_flag}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_group_member_invite_information(robot_wxid: str, from_wxid: str) -> dict:
|
||||||
|
r"""获取群成员邀请信息[K10023]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 群聊的id
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10023', 'robotWxid': robot_wxid, 'fromWxid': from_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_address_list(robot_wxid: str) -> dict:
|
||||||
|
r"""获取通讯录列表[K10024],此处获取的好友+群等(具体自己测试)
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10024', 'robotWxid': robot_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_wecom_friend_list(robot_wxid: str) -> dict:
|
||||||
|
r"""获取企业好友列表[K10025]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10025', 'robotWxid': robot_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_friend_info(robot_wxid: str, from_wxid: str) -> dict:
|
||||||
|
r"""获取指定好友信息[K10026]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10026', 'robotWxid': robot_wxid, 'fromWxid': from_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_net_friend_info(robot_wxid: str, from_wxid: str) -> dict:
|
||||||
|
r"""网络获取指定好友信息[K10027]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10027', 'robotWxid': robot_wxid, 'fromWxid': from_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def del_friend(robot_wxid: str, from_wxid: str) -> dict:
|
||||||
|
r"""删除好友[K10028]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10028', 'robotWxid': robot_wxid, 'fromWxid': from_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def update_friend_remark(robot_wxid: str, from_wxid: str, remark: str) -> dict:
|
||||||
|
r"""修改好友备注[K10029]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param remark: 备注
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10029', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'newMsg': remark}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def agree_friend_request(robot_wxid: str, from_wxid: str, v3: str, v4: str, sence: str) -> dict:
|
||||||
|
r"""同意好友请求[K10030]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param v3: 接收到的消息里获取
|
||||||
|
:param v4: 接收到的消息里获取
|
||||||
|
:param sence: 接收到的消息里获取
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10030', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'v3': v3, 'v4': v4, 'sence': sence}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def friend_status_detection(robot_wxid: str, from_wxid: str) -> dict:
|
||||||
|
r"""好友状态检测[K10031]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10031', 'robotWxid': robot_wxid, 'fromWxid': from_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def add_blacklist(robot_wxid: str, from_wxid: str, is_flag: str) -> dict:
|
||||||
|
r"""拉黑好友[K10032]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param is_flag: 是否拉黑,0/1
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10032', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'isFlag': is_flag}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def send_text_message(robot_wxid: str, from_wxid: str, msg: str) -> dict:
|
||||||
|
r"""发送文本信息[K10033]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param msg: 消息内容
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10033', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'msg': msg}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def send_image_message(robot_wxid: str, from_wxid: str, msg: str) -> dict:
|
||||||
|
r"""发送图片信息[K10034]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param msg: 图片路径,支持网址(直链,如:http://127.0.0.1/tp.jpg)
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10034', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'msg': msg}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def send_file_message(robot_wxid: str, from_wxid: str, msg: str) -> dict:
|
||||||
|
r"""发送文件信息[K10035]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param msg: 文件路径,本地(鲲鹏机器人所在电脑/服务器)
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10035', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'msg': msg}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def send_gif_message(robot_wxid: str, from_wxid: str, msg: str) -> dict:
|
||||||
|
r"""发送GIF信息[K10036]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param msg: GIF路径,支持网址(直链,如:http://127.0.0.1/tp.gif)
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10036', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'msg': msg}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def send_at_message(robot_wxid: str, from_wxid: str, msg: str, wx_list: str) -> dict:
|
||||||
|
r"""发送艾特信息[K10037]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param msg: 消息内容
|
||||||
|
:param wx_list: 艾特的wxid列表,用英文逗号隔开
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10037', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'msg': msg, 'list': wx_list}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def send_card_message(robot_wxid: str, from_wxid: str, tj_wxid: str, tj_name: str) -> dict:
|
||||||
|
r"""发送名片信息[K10038]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param tj_wxid: wxid和v4都可以
|
||||||
|
:param tj_name: 推荐昵称
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10038', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'tjWxid': tj_wxid, 'tjName': tj_name}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def send_link_message(robot_wxid: str, from_wxid: str, title: str, desc: str, url: str, pic: str) -> dict:
|
||||||
|
r"""发送链接信息[K10039]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param title: 标题
|
||||||
|
:param desc: 描述
|
||||||
|
:param url: 链接
|
||||||
|
:param pic: 图片路径,支持网址(直链,如:http://127.0.0.1/tp.jpg)
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10039', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'title': title, 'desc': desc,
|
||||||
|
'url': url, 'pic': pic}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def send_applet_message(robot_wxid: str, from_wxid: str, xml: str, pic: str) -> dict:
|
||||||
|
r"""发送小程序信息[K10040]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param xml: xml
|
||||||
|
:param pic: 略缩图路径,支持网址(直链,如:http://127.0.0.1/tp.jpg)
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10040', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'xml': xml, 'pic': pic}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def relay_message(robot_wxid: str, from_wxid: str, msg_id: str) -> dict:
|
||||||
|
r"""转发信息[K10041]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param msg_id: 消息Id,SvrId
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10041', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'msgId': msg_id}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_login_status(robot_wxid: str) -> dict:
|
||||||
|
r"""取登录状态[K10042]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10042', 'robotWxid': robot_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def withdraw_message(robot_wxid: str, from_wxid: str, msg_id: str) -> dict:
|
||||||
|
r"""撤回信息[K10043]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param msg_id: 消息Id,SvrId
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10043', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'msgId': msg_id}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_personal_info(robot_wxid: str) -> dict:
|
||||||
|
r"""获取个人信息[K10044]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10044', 'robotWxid': robot_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_login_list() -> dict:
|
||||||
|
r"""取登录账号列表[K10045]"""
|
||||||
|
api_json = {'api': 'K10045'}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def download_image(robot_wxid: str, xml: str, path: str) -> dict:
|
||||||
|
r"""下载图片[K10046]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param xml: 接收到的消息xml
|
||||||
|
:param path: 保存路径,绝对路径,带后缀
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10046', 'robotWxid': robot_wxid, 'xml': xml, 'path': path}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def decrypt_image(robot_wxid: str, filepath: str, path: str) -> dict:
|
||||||
|
r"""解密图片[K10047]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param filepath: 接收消息里的filepath字段
|
||||||
|
:param path: 保存路径,绝对路径,带后缀
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10047', 'robotWxid': robot_wxid, 'filepath': filepath, 'path': path}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def send_xml_message(robot_wxid: str, from_wxid: str, xml: str) -> dict:
|
||||||
|
r"""发送XML信息[K10048]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param xml: XML信息
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10048', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'xml': xml}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def refresh_moments(robot_wxid: str) -> dict:
|
||||||
|
r"""刷新朋友圈[K10049]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10049', 'robotWxid': robot_wxid}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_moments_next_page(robot_wxid: str, circle_id: str) -> dict:
|
||||||
|
r"""获取朋友圈下一页[K10050]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param circle_id: itemid朋友圈ID,获取从该ID的下一条开始的一页
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10050', 'robotWxid': robot_wxid, 'circleId': circle_id}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def get_personal_moments(robot_wxid: str, from_wxid: str, circle_id: str) -> dict:
|
||||||
|
r"""获取个人朋友圈[K10051]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param from_wxid: 目标的wxid
|
||||||
|
:param circle_id: itemid朋友圈ID,获取从该ID的下一条开始的一页
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10051', 'robotWxid': robot_wxid, 'fromWxid': from_wxid, 'circleId': circle_id}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def moments_like(robot_wxid: str, circle_id: str) -> dict:
|
||||||
|
r"""朋友圈点赞[K10052]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param circle_id: itemid朋友圈ID,获取从该ID的下一条开始的一页
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10052', 'robotWxid': robot_wxid, 'circleId': circle_id}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def moments_cancel_like(robot_wxid: str, circle_id: str) -> dict:
|
||||||
|
r"""朋友圈取消点赞[K10053]
|
||||||
|
|
||||||
|
:param robot_wxid: 机器人的wxid
|
||||||
|
:param circle_id: itemid朋友圈ID,获取从该ID的下一条开始的一页
|
||||||
|
"""
|
||||||
|
api_json = {'api': 'K10053', 'robotWxid': robot_wxid, 'circleId': circle_id}
|
||||||
|
return api_request(api_json)
|
||||||
|
|
||||||
|
|
||||||
|
def local_download_image(xml, path):
|
||||||
|
r"""本地下载图片
|
||||||
|
|
||||||
|
:param xml: 接收到的消息xml
|
||||||
|
:param path: 保存文件夹的绝对路径
|
||||||
|
:return: 下载图片的绝对路径
|
||||||
|
"""
|
||||||
|
emoji_msg = ET.fromstring(xml).find('emoji')
|
||||||
|
url = emoji_msg.get('cdnurl').replace('amp;', '')
|
||||||
|
r = requests.get(url)
|
||||||
|
if os.path.exists(path) is False:
|
||||||
|
os.mkdir(path)
|
||||||
|
xo, j = image_format(r.content) # 判断图片格式 并计算返回异或值 函数
|
||||||
|
if j == 1:
|
||||||
|
mat = '.png'
|
||||||
|
elif j == 2:
|
||||||
|
mat = '.gif'
|
||||||
|
else:
|
||||||
|
mat = '.jpg'
|
||||||
|
file_name = re.findall(r'm=(.*?)&', url)[0]
|
||||||
|
out = os.path.join(path, file_name + mat)
|
||||||
|
with open(out, 'wb') as f:
|
||||||
|
f.write(r.content)
|
||||||
|
f.close()
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def local_decrypt_image(filepath: str, path: str) -> str:
|
||||||
|
r"""本地解密dat图片
|
||||||
|
|
||||||
|
:param filepath: 接收消息里的filepath字段
|
||||||
|
:param path: 保存文件夹的绝对路径
|
||||||
|
:return: 解密图片的绝对路径
|
||||||
|
"""
|
||||||
|
file_splitext = os.path.splitext(filepath)
|
||||||
|
file_type = file_splitext[1]
|
||||||
|
file_name = os.path.split(file_splitext[0])[1]
|
||||||
|
if file_type != '.dat':
|
||||||
|
return '不支持处理非.dat文件'
|
||||||
|
if '.' in path:
|
||||||
|
return 'path参数为保存文件夹的绝对路径'
|
||||||
|
if os.path.exists(path) is False:
|
||||||
|
os.mkdir(path)
|
||||||
|
for i in range(30):
|
||||||
|
if os.path.exists(filepath) is True:
|
||||||
|
break
|
||||||
|
time.sleep(2)
|
||||||
|
if os.path.exists(filepath) is False:
|
||||||
|
return '微信下载dat图片超时'
|
||||||
|
|
||||||
|
dat_read = open(filepath, "rb") # 读取.dat 文件
|
||||||
|
xo, j = image_format(filepath) # 判断图片格式 并计算返回异或值 函数
|
||||||
|
if j == 1:
|
||||||
|
mat = '.png'
|
||||||
|
elif j == 2:
|
||||||
|
mat = '.gif'
|
||||||
|
else:
|
||||||
|
mat = '.jpg'
|
||||||
|
out = os.path.join(path, file_name + mat)
|
||||||
|
png_write = open(out, "wb") # 图片写入
|
||||||
|
dat_read.seek(0) # 重置文件指针位置
|
||||||
|
for now in dat_read: # 循环字节
|
||||||
|
for nowByte in now:
|
||||||
|
new_byte = nowByte ^ xo # 转码计算
|
||||||
|
png_write.write(bytes([new_byte])) # 转码后重新写
|
||||||
|
dat_read.close()
|
||||||
|
png_write.close()
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def image_format(f):
|
||||||
|
"""
|
||||||
|
计算异或值
|
||||||
|
各图片头部信息
|
||||||
|
png:89 50 4e 47
|
||||||
|
gif: 47 49 46 38
|
||||||
|
jpeg:ff d8 ff
|
||||||
|
"""
|
||||||
|
if isinstance(f, str):
|
||||||
|
dat_r = open(f, "rb")
|
||||||
|
elif isinstance(f, bytes):
|
||||||
|
dat_r = BytesIO(f)
|
||||||
|
else:
|
||||||
|
return print('不支持的类型', type(f))
|
||||||
|
try:
|
||||||
|
a = [(0x89, 0x50, 0x4e), (0x47, 0x49, 0x46), (0xff, 0xd8, 0xff)]
|
||||||
|
for now in dat_r:
|
||||||
|
j = 0
|
||||||
|
for xor in a:
|
||||||
|
j = j + 1 # 记录是第几个格式 1:png 2:gif 3:jpeg
|
||||||
|
i = 0
|
||||||
|
res = []
|
||||||
|
now2 = now[:3] # 取前三组判断
|
||||||
|
for nowByte in now2:
|
||||||
|
res.append(nowByte ^ xor[i])
|
||||||
|
i += 1
|
||||||
|
if res[0] == res[1] == res[2]:
|
||||||
|
return res[0], j
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
dat_r.close()
|
||||||
|
|
||||||
|
|
||||||
|
# 表情代码
|
||||||
|
WC_EMOTICON_CONVERSION = {
|
||||||
|
'[微笑]': '😃', '[Smile]': '😃',
|
||||||
|
'[撇嘴]': '😖', '[Grimace]': '😖',
|
||||||
|
'[色]': '😍', '[Drool]': '😍',
|
||||||
|
'[发呆]': '😳', '[Scowl]': '😳',
|
||||||
|
'[得意]': '😎', '[Chill]': '😎',
|
||||||
|
'[流泪]': '😭', '[Sob]': '😭',
|
||||||
|
'[害羞]': '☺️', '[Shy]': '☺️', '[Blush]': '☺️',
|
||||||
|
'[闭嘴]': '🤐', '[Shutup]': '🤐',
|
||||||
|
'[睡]': '😴', '[Sleep]': '😴',
|
||||||
|
'[大哭]': '😣', '[Cry]': '😣',
|
||||||
|
'[尴尬]': '😰', '[Awkward]': '😰',
|
||||||
|
'[发怒]': '😡', '[Pout]': '😡',
|
||||||
|
'[调皮]': '😜', '[Wink]': '😜',
|
||||||
|
'[呲牙]': '😁', '[Grin]': '😁',
|
||||||
|
'[惊讶]': '😱', '[Surprised]': '😱',
|
||||||
|
'[难过]': '🙁', '[Frown]': '🙁',
|
||||||
|
'[囧]': '☺️', '[Tension]': '☺️',
|
||||||
|
'[抓狂]': '😫', '[Scream]': '😫',
|
||||||
|
'[吐]': '🤢', '[Puke]': '🤢',
|
||||||
|
'[偷笑]': '🙈', '[Chuckle]': '🙈',
|
||||||
|
'[愉快]': '☺️', '[Joyful]': '☺️',
|
||||||
|
'[白眼]': '🙄', '[Slight]': '🙄',
|
||||||
|
'[傲慢]': '😕', '[Smug]': '😕',
|
||||||
|
'[困]': '😪', '[Drowsy]': '😪',
|
||||||
|
'[惊恐]': '😱', '[Panic]': '😱',
|
||||||
|
'[流汗]': '😓', '[Sweat]': '😓',
|
||||||
|
'[憨笑]': '😄', '[Laugh]': '😄',
|
||||||
|
'[悠闲]': '😏', '[Loafer]': '😏',
|
||||||
|
'[奋斗]': '💪', '[Strive]': '💪',
|
||||||
|
'[咒骂]': '😤', '[Scold]': '😤',
|
||||||
|
'[疑问]': '❓', '[Doubt]': '❓',
|
||||||
|
'[嘘]': '🤐', '[Shhh]': '🤐',
|
||||||
|
'[晕]': '😲', '[Dizzy]': '😲',
|
||||||
|
'[衰]': '😳', '[BadLuck]': '😳',
|
||||||
|
'[骷髅]': '💀', '[Skull]': '💀',
|
||||||
|
'[敲打]': '👊', '[Hammer]': '👊',
|
||||||
|
'[再见]': '🙋\u200d♂', '[Bye]': '🙋\u200d♂',
|
||||||
|
'[擦汗]': '😥', '[Relief]': '😥',
|
||||||
|
'[抠鼻]': '🤷\u200d♂', '[DigNose]': '🤷\u200d♂',
|
||||||
|
'[鼓掌]': '👏', '[Clap]': '👏',
|
||||||
|
'[坏笑]': '👻', '[Trick]': '👻',
|
||||||
|
'[左哼哼]': '😾', '[Bah!L]': '😾',
|
||||||
|
'[右哼哼]': '😾', '[Bah!R]': '😾',
|
||||||
|
'[哈欠]': '😪', '[Yawn]': '😪',
|
||||||
|
'[鄙视]': '😒', '[Lookdown]': '😒',
|
||||||
|
'[委屈]': '😣', '[Wronged]': '😣',
|
||||||
|
'[快哭了]': '😔', '[Puling]': '😔',
|
||||||
|
'[阴险]': '😈', '[Sly]': '😈',
|
||||||
|
'[亲亲]': '😘', '[Kiss]': '😘',
|
||||||
|
'[可怜]': '😻', '[Whimper]': '😻',
|
||||||
|
'[菜刀]': '🔪', '[Cleaver]': '🔪',
|
||||||
|
'[西瓜]': '🍉', '[Melon]': '🍉',
|
||||||
|
'[啤酒]': '🍺', '[Beer]': '🍺',
|
||||||
|
'[咖啡]': '☕', '[Coffee]': '☕',
|
||||||
|
'[猪头]': '🐷', '[Pig]': '🐷',
|
||||||
|
'[玫瑰]': '🌹', '[Rose]': '🌹',
|
||||||
|
'[凋谢]': '🥀', '[Wilt]': '🥀',
|
||||||
|
'[嘴唇]': '💋', '[Lip]': '💋',
|
||||||
|
'[爱心]': '❤️', '[Heart]': '❤️',
|
||||||
|
'[心碎]': '💔', '[BrokenHeart]': '💔',
|
||||||
|
'[蛋糕]': '🎂', '[Cake]': '🎂',
|
||||||
|
'[炸弹]': '💣', '[Bomb]': '💣',
|
||||||
|
'[便便]': '💩', '[Poop]': '💩',
|
||||||
|
'[月亮]': '🌃', '[Moon]': '🌃',
|
||||||
|
'[太阳]': '🌞', '[Sun]': '🌞',
|
||||||
|
'[拥抱]': '🤗', '[Hug]': '🤗',
|
||||||
|
'[强]': '👍', '[Strong]': '👍',
|
||||||
|
'[弱]': '👎', '[Weak]': '👎',
|
||||||
|
'[握手]': '🤝', '[Shake]': '🤝',
|
||||||
|
'[胜利]': '✌️', '[Victory]': '✌️',
|
||||||
|
'[抱拳]': '🙏', '[Salute]': '🙏',
|
||||||
|
'[勾引]': '💁\u200d♂', '[Beckon]': '💁\u200d♂',
|
||||||
|
'[拳头]': '👊', '[Fist]': '👊',
|
||||||
|
'[OK]': '👌',
|
||||||
|
'[跳跳]': '💃', '[Waddle]': '💃',
|
||||||
|
'[发抖]': '🙇', '[Tremble]': '🙇',
|
||||||
|
'[怄火]': '😡', '[Aaagh!]': '😡',
|
||||||
|
'[转圈]': '🕺', '[Twirl]': '🕺',
|
||||||
|
'[嘿哈]': '🤣', '[Hey]': '🤣',
|
||||||
|
'[捂脸]': '🤦\u200d♂', '[Facepalm]': '🤦\u200d♂',
|
||||||
|
'[奸笑]': '😜', '[Smirk]': '😜',
|
||||||
|
'[机智]': '🤓', '[Smart]': '🤓',
|
||||||
|
'[皱眉]': '😟', '[Concerned]': '😟',
|
||||||
|
'[耶]': '✌️', '[Yeah!]': '✌️',
|
||||||
|
'[红包]': '🧧', '[Packet]': '🧧',
|
||||||
|
'[鸡]': '🐥', '[Chick]': '🐥',
|
||||||
|
'[蜡烛]': '🕯️', '[Candle]': '🕯️',
|
||||||
|
'[糗大了]': '😥',
|
||||||
|
'[Thumbs Up]': '👍', '[Pleased]': '😊',
|
||||||
|
'[Rich]': '🀅',
|
||||||
|
'[Pup]': '🐶',
|
||||||
|
'[吃瓜]': '🙄\u200d🍉', '[Onlooker]': '🙄\u200d🍉',
|
||||||
|
'[加油]': '💪\u200d😁',
|
||||||
|
'[加油加油]': '💪\u200d😷',
|
||||||
|
'[汗]': '😓',
|
||||||
|
'[天啊]': '😱',
|
||||||
|
'[Emm]': '🤔',
|
||||||
|
'[社会社会]': '😏',
|
||||||
|
'[旺柴]': '🐶\u200d😏', '[Awesome]': '🐶\u200d😏',
|
||||||
|
'[好的]': '😏\u200d👌',
|
||||||
|
'[哇]': '🤩',
|
||||||
|
'[打脸]': '😟\u200d🤚',
|
||||||
|
'[破涕为笑]': '😂', '[破涕為笑]': '😂', '[Lol]': '😂',
|
||||||
|
'[苦涩]': '😭',
|
||||||
|
'[翻白眼]': '🙄',
|
||||||
|
'[爆竹]': '🧨',
|
||||||
|
'[烟花]': '🎆',
|
||||||
|
'[裂开]': '[裂开]',
|
||||||
|
'[福]': '🧧',
|
||||||
|
'[發]': '🀅',
|
||||||
|
'[礼物]': '🎁',
|
||||||
|
'[庆祝]': '🎉',
|
||||||
|
'[合十]': '🙏',
|
||||||
|
'[叹气]': '😮💨', '[Sigh]': '😮💨',
|
||||||
|
'[让我看看]': '👀',
|
||||||
|
'[666]': '6️⃣6️⃣6️⃣',
|
||||||
|
'[无语]': '😑',
|
||||||
|
'[失望]': '😞',
|
||||||
|
'[恐惧]': '😨',
|
||||||
|
'[脸红]': '😳',
|
||||||
|
'[生病]': '😷',
|
||||||
|
'[笑脸]': '😁',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def unicode_escape(chars, data_dict):
|
||||||
|
"""emoji 替换 unicode 格式 "[\\u1f602],请勿主动调用"""
|
||||||
|
if chars in WC_EMOTICON_CONVERSION.values():
|
||||||
|
return [k for k, v in WC_EMOTICON_CONVERSION.items() if v == chars][0]
|
||||||
|
else:
|
||||||
|
chars_str = chars.encode('unicode-escape').decode().replace('U000', 'u')
|
||||||
|
chars_unicode_list = chars_str.split('\\')
|
||||||
|
chars_unicode_list.pop(0)
|
||||||
|
for i in range(len(chars_unicode_list)):
|
||||||
|
chars_unicode_list[i] = '[\\\\{}]'.format(chars_unicode_list[i])
|
||||||
|
return ''.join(chars_unicode_list)
|
||||||
|
|
||||||
|
|
||||||
|
def emoji_to_unicode(message: str) -> str:
|
||||||
|
"""将msg中的emoji表情转为鲲鹏 unicode 格式 "[\\u1f602]"
|
||||||
|
"""
|
||||||
|
return emoji.replace_emoji(message, replace=unicode_escape)
|
||||||
|
|
||||||
|
|
||||||
|
def unicode_to_emoji(message: Union[str, dict, list], msg_type='str') -> Union[str, dict, list]:
|
||||||
|
"""将msg中的鲲鹏unicode格式 "[\\u1f602]" 转为emoji表情
|
||||||
|
|
||||||
|
:param message: 建议传入json字符串,虽然提供了dict和list的解析方法,但递归遍历影响运行速度
|
||||||
|
:param msg_type: 默认为‘str';json字符串请传入’json‘,区别在于json的转义符多;dict和list通常情况下保持默认即可
|
||||||
|
"""
|
||||||
|
if isinstance(message, str):
|
||||||
|
return de_emoji(message, msg_type)
|
||||||
|
elif isinstance(message, dict) or isinstance(message, list):
|
||||||
|
return ergodic(message)
|
||||||
|
else:
|
||||||
|
return '暂不支持此类型'
|
||||||
|
|
||||||
|
|
||||||
|
def ergodic(message: Union[dict, list]) -> Union[dict, list]:
|
||||||
|
"""递归遍历,将鲲鹏unicode格式 "[\\u1f602]" 转为emoji表情,不建议使用此方法,且请勿主动调用"""
|
||||||
|
if isinstance(message, dict):
|
||||||
|
for key in message.keys():
|
||||||
|
message[key] = de_emoji(message[key])
|
||||||
|
return message
|
||||||
|
elif isinstance(message, list):
|
||||||
|
for i in range(len(message)):
|
||||||
|
message[i] = de_emoji(message[i])
|
||||||
|
return message
|
||||||
|
print(message)
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def de_emoji(message, msg_type='str'):
|
||||||
|
"""将鲲鹏unicode格式 "[\\u1f602]" 转为emoji表情,请勿主动调用"""
|
||||||
|
if not message:
|
||||||
|
return message
|
||||||
|
if msg_type == 'json':
|
||||||
|
zyf = '\\'
|
||||||
|
else:
|
||||||
|
zyf = ''
|
||||||
|
if isinstance(message, dict) or isinstance(message, list):
|
||||||
|
return ergodic(message)
|
||||||
|
elif isinstance(message, str):
|
||||||
|
emoji_list = re.findall(zyf + zyf + r'\\u[0-9a-fA-F]{5}', message)
|
||||||
|
# print(emoji_list)
|
||||||
|
for emoji_unicode in emoji_list:
|
||||||
|
chars = str(str.replace(emoji_unicode, zyf + '\\u', '\\U000')).encode('ASCII').decode('unicode-escape')
|
||||||
|
# print(chars)
|
||||||
|
message = message.replace(f'[{emoji_unicode}]', chars)
|
||||||
|
message = message.replace('[' + zyf + '\\u200d]', '\\u200d'.encode('ASCII').decode('unicode-escape'))
|
||||||
|
message = message.replace('[' + zyf + '\\ufe0f]', '\\ufe0f'.encode('ASCII').decode('unicode-escape'))
|
||||||
|
chars_list = re.findall(r'\[\w+]', message)
|
||||||
|
for chars in chars_list:
|
||||||
|
try:
|
||||||
|
message = message.replace(chars, WC_EMOTICON_CONVERSION[chars])
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
unicode_text_list = re.findall(zyf + zyf + r'\\u[0-9a-fA-F]{4}', message)
|
||||||
|
for unicode_text in unicode_text_list:
|
||||||
|
message = message.replace(f'[{unicode_text}]', unicode_text.replace(zyf, '', 1))
|
||||||
|
return message
|
||||||
|
else:
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def crypt_md5(message: Union[dict, str]) -> str:
|
||||||
|
"""鉴权算法"""
|
||||||
|
if isinstance(message, str):
|
||||||
|
message = json.loads(message)
|
||||||
|
crypt_text = f"{config.SECRET_KEY}{''.join(message.values())}{config.SECRET_KEY}"
|
||||||
|
jm = hashlib.md5()
|
||||||
|
jm.update(crypt_text.encode("utf8"))
|
||||||
|
crypt_text_2 = jm.hexdigest()
|
||||||
|
jm2 = hashlib.md5()
|
||||||
|
jm2.update(crypt_text_2.encode("utf8"))
|
||||||
|
return jm2.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def api_request(api_json: dict) -> dict:
|
||||||
|
r"""请求api接口,请勿主动调用
|
||||||
|
|
||||||
|
:param api_json: 请求参数
|
||||||
|
"""
|
||||||
|
|
||||||
|
if api_json.get('api') != 'K10002': # 添加日志不转emoji
|
||||||
|
api_json = emoji_to_unicode(json.dumps(api_json, ensure_ascii=False))
|
||||||
|
|
||||||
|
if isinstance(api_json, str): # str解析json
|
||||||
|
api_json = json.loads(api_json)
|
||||||
|
|
||||||
|
api_json.update({'sign': crypt_md5(api_json)}) # 增加鉴权
|
||||||
|
|
||||||
|
r = requests.post(config.wxbot_url, headers={'content-type': 'application/json'},
|
||||||
|
data=json.dumps(api_json, ensure_ascii=False).encode('utf-8')).json()
|
||||||
|
|
||||||
|
return r
|
||||||
BIN
__pycache__/WXBotService.cpython-310.pyc
Normal file
BIN
__pycache__/WXBotService.cpython-310.pyc
Normal file
Binary file not shown.
BIN
__pycache__/WXBotService.cpython-312.pyc
Normal file
BIN
__pycache__/WXBotService.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/config.cpython-310.pyc
Normal file
BIN
__pycache__/config.cpython-310.pyc
Normal file
Binary file not shown.
BIN
__pycache__/config.cpython-312.pyc
Normal file
BIN
__pycache__/config.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/planet.cpython-310.pyc
Normal file
BIN
__pycache__/planet.cpython-310.pyc
Normal file
Binary file not shown.
5
config.py
Normal file
5
config.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
work_path = os.getcwd()
|
||||||
|
wxbot_url = "http://127.0.0.1:2022/KP" # api地址
|
||||||
|
SECRET_KEY = '鉴权秘钥' # 鉴权秘钥
|
||||||
64
planet.py
Normal file
64
planet.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
planetXml='''<?xml version="1.0"? encoding="UTF-8"?>
|
||||||
|
<msg>
|
||||||
|
<appmsg appid="" sdkver="0">
|
||||||
|
<title>异度世界的星球</title>127.0.0.1 - - [20/Mar/2024 09:10:30] "POST /wxbot HTTP/1.1" 200 -
|
||||||
|
<des>异度世界的星球</des>
|
||||||
|
<type>33</type>
|
||||||
|
<action>view</action>
|
||||||
|
<url>https://mp.weixin.qq.com/mp/waerrpage?appid=wxa55815dd741a540d&type=upgrade&upgradetype=3#wechat_redirect</url>
|
||||||
|
<appattach>
|
||||||
|
<cdnthumburl>3057020100044b304902010002043866a09902032f591902044da90c79020465fa36d0042461316466393862632d656333632d346438302d623330652d3766613538653831613436340204051408030201000405004c537500</cdnthumburl>
|
||||||
|
<cdnthumbmd5>dc2e218e5faf36dd4add4db1e0308cbe</cdnthumbmd5>
|
||||||
|
<cdnthumblength>34873</cdnthumblength>
|
||||||
|
<cdnthumbwidth>720</cdnthumbwidth>
|
||||||
|
<cdnthumbheight>576</cdnthumbheight>
|
||||||
|
<cdnthumbaeskey>712778198a86497a3495eed7256f1fd7</cdnthumbaeskey>
|
||||||
|
<aeskey>712778198a86497a3495eed7256f1fd7</aeskey>
|
||||||
|
<encryver>0</encryver>
|
||||||
|
<filekey>wxid_haqoszjheyuz22_229_1710897030</filekey>
|
||||||
|
</appattach>
|
||||||
|
<sourceusername>gh_735af7f13193@app</sourceusername>
|
||||||
|
<sourcedisplayname>异度世界的星球</sourcedisplayname>
|
||||||
|
<md5>dc2e218e5faf36dd4add4db1e0308cbe</md5>
|
||||||
|
<webviewshared>
|
||||||
|
<jsAppId><![CDATA[]]></jsAppId>
|
||||||
|
</webviewshared>
|
||||||
|
<weappinfo>
|
||||||
|
<username><![CDATA[gh_735af7f13193@app]]></username>
|
||||||
|
<appid><![CDATA[wxa55815dd741a540d]]></appid>
|
||||||
|
<type>2</type>
|
||||||
|
<version>3</version>
|
||||||
|
<weappiconurl><![CDATA[http://mmbiz.qpic.cn/sz_mmbiz_png/43cSpHKSBGyHO7qHeuad8BJLUQ6W9ib7QLfgYicyvGTvpibvLicrS0MaTia3nplqDbWrLIXSfxQgpL3Aib1jGjHjOl9A/640?wx_fmt=png&wxfrom>
|
||||||
|
<pagepath><![CDATA[pages/index/index.html]]></pagepath>
|
||||||
|
<shareId><![CDATA[0_wxa55815dd741a540d_a96a890b27e8c43d18e2e75fda2a9215_1710896515_0]]></shareId>
|
||||||
|
<pkginfo>
|
||||||
|
<type>2</type>
|
||||||
|
<md5><![CDATA[721c114bb969b9fdc4379396248cb6a3]]></md5>
|
||||||
|
</pkginfo>
|
||||||
|
<appservicetype>0</appservicetype>
|
||||||
|
<brandofficialflag>0</brandofficialflag>
|
||||||
|
<showRelievedBuyFlag>0</showRelievedBuyFlag>
|
||||||
|
<hasRelievedBuyPlugin>0</hasRelievedBuyPlugin>
|
||||||
|
<flagshipflag>0</flagshipflag>
|
||||||
|
<subType>0</subType>
|
||||||
|
<videopageinfo>
|
||||||
|
<thumbwidth>720</thumbwidth>
|
||||||
|
<thumbheight>576</thumbheight>
|
||||||
|
<videosource><![CDATA[]]></videosource>
|
||||||
|
<fromopensdk>0</fromopensdk>
|
||||||
|
<appthumburl><![CDATA[(null)]]></appthumburl>
|
||||||
|
</videopageinfo>
|
||||||
|
<isprivatemessage>0</isprivatemessage>
|
||||||
|
</weappinfo>
|
||||||
|
<secretmsg>
|
||||||
|
<isscrectmsg>0</isscrectmsg>
|
||||||
|
</secretmsg>
|
||||||
|
</appmsg>
|
||||||
|
<fromusername>wxid_4413224132412</fromusername>
|
||||||
|
<scene>0</scene>
|
||||||
|
<appinfo>
|
||||||
|
<version>1</version>
|
||||||
|
<appname></appname>
|
||||||
|
</appinfo>
|
||||||
|
<commenturl></commenturl>
|
||||||
|
</msg>'''
|
||||||
64
planet.xml
Normal file
64
planet.xml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<msg>
|
||||||
|
<appmsg appid="" sdkver="0">
|
||||||
|
<title>异度世界的星球</title>127.0.0.1 - - [20/Mar/2024 09:10:30] "POST /wxbot HTTP/1.1" 200 -
|
||||||
|
<des>异度世界的星球</des>
|
||||||
|
<type>33</type>
|
||||||
|
<action>view</action>
|
||||||
|
<url>https://mp.weixin.qq.com/mp/waerrpage?appid=wxa55815dd741a540d&type=upgrade&upgradetype=3#wechat_redirect</url>
|
||||||
|
<appattach>
|
||||||
|
<cdnthumburl>3057020100044b304902010002043866a09902032f591902044da90c79020465fa36d0042461316466393862632d656333632d346438302d623330652d3766613538653831613436340204051408030201000405004c537500</cdnthumburl>
|
||||||
|
<cdnthumbmd5>dc2e218e5faf36dd4add4db1e0308cbe</cdnthumbmd5>
|
||||||
|
<cdnthumblength>34873</cdnthumblength>
|
||||||
|
<cdnthumbwidth>720</cdnthumbwidth>
|
||||||
|
<cdnthumbheight>576</cdnthumbheight>
|
||||||
|
<cdnthumbaeskey>712778198a86497a3495eed7256f1fd7</cdnthumbaeskey>
|
||||||
|
<aeskey>712778198a86497a3495eed7256f1fd7</aeskey>
|
||||||
|
<encryver>0</encryver>
|
||||||
|
<filekey>wxid_haqoszjheyuz22_229_1710897030</filekey>
|
||||||
|
</appattach>
|
||||||
|
<sourceusername>gh_735af7f13193@app</sourceusername>
|
||||||
|
<sourcedisplayname>异度世界的星球</sourcedisplayname>
|
||||||
|
<md5>dc2e218e5faf36dd4add4db1e0308cbe</md5>
|
||||||
|
<webviewshared>
|
||||||
|
<jsAppId><![CDATA[]]></jsAppId>
|
||||||
|
</webviewshared>
|
||||||
|
<weappinfo>
|
||||||
|
<username><![CDATA[gh_735af7f13193@app]]></username>
|
||||||
|
<appid><![CDATA[wxa55815dd741a540d]]></appid>
|
||||||
|
<type>2</type>
|
||||||
|
<version>3</version>
|
||||||
|
<weappiconurl><![CDATA[http://mmbiz.qpic.cn/sz_mmbiz_png/43cSpHKSBGyHO7qHeuad8BJLUQ6W9ib7QLfgYicyvGTvpibvLicrS0MaTia3nplqDbWrLIXSfxQgpL3Aib1jGjHjOl9A/640?wx_fmt=png&wxfrom>
|
||||||
|
<pagepath><![CDATA[pages/index/index.html?wxid=wxid_w2imh7ki5s4q12]]></pagepath>
|
||||||
|
<shareId><![CDATA[0_wxa55815dd741a540d_a96a890b27e8c43d18e2e75fda2a9215_1710896515_0]]></shareId>
|
||||||
|
<pkginfo>
|
||||||
|
<type>2</type>
|
||||||
|
<md5><![CDATA[721c114bb969b9fdc4379396248cb6a3]]></md5>
|
||||||
|
</pkginfo>
|
||||||
|
<appservicetype>0</appservicetype>
|
||||||
|
<brandofficialflag>0</brandofficialflag>
|
||||||
|
<showRelievedBuyFlag>0</showRelievedBuyFlag>
|
||||||
|
<hasRelievedBuyPlugin>0</hasRelievedBuyPlugin>
|
||||||
|
<flagshipflag>0</flagshipflag>
|
||||||
|
<subType>0</subType>
|
||||||
|
<videopageinfo>
|
||||||
|
<thumbwidth>720</thumbwidth>
|
||||||
|
<thumbheight>576</thumbheight>
|
||||||
|
<videosource><![CDATA[]]></videosource>
|
||||||
|
<fromopensdk>0</fromopensdk>
|
||||||
|
<appthumburl><![CDATA[(null)]]></appthumburl>
|
||||||
|
</videopageinfo>
|
||||||
|
<isprivatemessage>0</isprivatemessage>
|
||||||
|
</weappinfo>
|
||||||
|
<secretmsg>
|
||||||
|
<isscrectmsg>0</isscrectmsg>
|
||||||
|
</secretmsg>
|
||||||
|
</appmsg>
|
||||||
|
<fromusername>wxid_4413224132412</fromusername>
|
||||||
|
<scene>0</scene>
|
||||||
|
<appinfo>
|
||||||
|
<version>1</version>
|
||||||
|
<appname></appname>
|
||||||
|
</appinfo>
|
||||||
|
<commenturl></commenturl>
|
||||||
|
</msg>
|
||||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
requests
|
||||||
|
emoji~=1.6.3
|
||||||
|
flask
|
||||||
BIN
解密图片/b187e9876e93e1b34dcd586db898487e.png
Normal file
BIN
解密图片/b187e9876e93e1b34dcd586db898487e.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 182 KiB |
Reference in New Issue
Block a user