Draft pyauto
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# WcfAuto 客户端(基于 python 客户端)
|
||||
[](https://pypi.python.org/pypi/wcferry) [](https://pypi.python.org/pypi/wcferry) [](https://wechatferry.readthedocs.io/zh/latest/?badge=latest)
|
||||
|
||||
|[📖 文档](https://wechatferry.readthedocs.io/)|[📺 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/vAGpn1C9stI8Xzt1hUJhLA)|
|
||||
|:-:|:-:|:-:|
|
||||
|
||||
🤖示例机器人框架:[WeChatRobot](https://github.com/lich0821/WeChatRobot)。
|
||||
|
||||
## 快速开始
|
||||
```sh
|
||||
pip install --upgrade wcfauto
|
||||
```
|
||||
|
||||
### Demo:
|
||||
```py
|
||||
#! /usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from time import sleep
|
||||
|
||||
from wcfauto import Register
|
||||
from wcferry import Wcf, WxMsg
|
||||
|
||||
logging.basicConfig(level='DEBUG', format="%(asctime)s %(message)s")
|
||||
LOG = logging.getLogger("Demo")
|
||||
|
||||
|
||||
def main():
|
||||
receiver = Register()
|
||||
|
||||
@receiver.message_register(isDivision=True, isGroup=True, isPyq=False)
|
||||
def process_msg(bot: Wcf, msg: WxMsg):
|
||||
"""
|
||||
同步消息函数装饰器
|
||||
"""
|
||||
LOG.info(f"收到消息: {msg}")
|
||||
|
||||
sleep(5) # 等微信加载好,以免信息显示异常
|
||||
LOG.info(f"已经登录: {True if bot.is_login() else False}")
|
||||
LOG.info(f"wxid: {bot.get_self_wxid()}")
|
||||
|
||||
# bot.disable_recv_msg() # 当需要停止接收消息时调用
|
||||
sleep(5)
|
||||
ret = bot.send_text("Hello world.", "filehelper")
|
||||
LOG.info(f"send_text: {ret}")
|
||||
|
||||
sleep(5)
|
||||
# 需要确保图片路径正确,建议使用绝对路径(使用双斜杠\\)
|
||||
ret = bot.send_image(
|
||||
"https://raw.githubusercontent.com/lich0821/WeChatFerry/master/assets/QR.jpeg", "filehelper")
|
||||
LOG.info(f"send_image: {ret}")
|
||||
|
||||
sleep(5)
|
||||
# 需要确保文件路径正确,建议使用绝对路径(使用双斜杠\\)
|
||||
ret = bot.send_file("https://raw.githubusercontent.com/lich0821/WeChatFerry/master/README.MD", "filehelper")
|
||||
LOG.info(f"send_file: {ret}")
|
||||
|
||||
sleep(5)
|
||||
LOG.info(f"Message types:\n{bot.get_msg_types()}")
|
||||
LOG.info(f"Contacts:\n{bot.get_contacts()}")
|
||||
|
||||
sleep(5)
|
||||
LOG.info(f"DBs:\n{bot.get_dbs()}")
|
||||
LOG.info(f"Tables:\n{bot.get_tables('db')}")
|
||||
LOG.info(f"Results:\n{bot.query_sql('MicroMsg.db', 'SELECT * FROM Contact LIMIT 1;')}")
|
||||
|
||||
# 需要真正的 V3、V4 信息
|
||||
# bot.accept_new_friend("v3", "v4")
|
||||
|
||||
# 添加群成员,填写正确的群 ID 和成员 wxid
|
||||
# ret = bot.add_chatroom_members("chatroom id", "wxid1,wxid2,wxid3,...")
|
||||
# LOG.info(f"add_chatroom_members: {ret}")
|
||||
|
||||
# 删除群成员,填写正确的群 ID 和成员 wxid
|
||||
# ret = bot.del_chatroom_members("chatroom id", "wxid1,wxid2,wxid3,...")
|
||||
# LOG.info(f"add_chatroom_members: {ret}")
|
||||
|
||||
sleep(5)
|
||||
bot.refresh_pyq(0) # 刷新朋友圈第一页
|
||||
# bot.refresh_pyq(id) # 从 id 开始刷新朋友圈
|
||||
|
||||
@receiver.async_message_register()
|
||||
async def async_process_msg(bot: Wcf, msg: WxMsg):
|
||||
"""
|
||||
异步消息函数装饰器
|
||||
"""
|
||||
print(msg)
|
||||
|
||||
# 开始接受消息
|
||||
receiver.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
|||
|
||||
|:-:|:-:|
|
||||
|后台回复 `WeChatFerry` 加群交流|如果你觉得有用|
|
||||
@@ -0,0 +1,80 @@
|
||||
#! /usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from time import sleep
|
||||
|
||||
from wcfauto import Register
|
||||
from wcferry import Wcf, WxMsg
|
||||
|
||||
logging.basicConfig(level='DEBUG', format="%(asctime)s %(message)s")
|
||||
LOG = logging.getLogger("Demo")
|
||||
|
||||
|
||||
def main():
|
||||
receiver = Register()
|
||||
|
||||
@receiver.message_register(isDivision=True, isGroup=True, isPyq=False)
|
||||
def process_msg(bot: Wcf, msg: WxMsg):
|
||||
"""
|
||||
同步消息函数装饰器
|
||||
"""
|
||||
LOG.info(f"收到消息: {msg}")
|
||||
|
||||
sleep(5) # 等微信加载好,以免信息显示异常
|
||||
LOG.info(f"已经登录: {True if bot.is_login() else False}")
|
||||
LOG.info(f"wxid: {bot.get_self_wxid()}")
|
||||
|
||||
# bot.disable_recv_msg() # 当需要停止接收消息时调用
|
||||
sleep(5)
|
||||
ret = bot.send_text("Hello world.", "filehelper")
|
||||
LOG.info(f"send_text: {ret}")
|
||||
|
||||
sleep(5)
|
||||
# 需要确保图片路径正确,建议使用绝对路径(使用双斜杠\\)
|
||||
ret = bot.send_image(
|
||||
"https://raw.githubusercontent.com/lich0821/WeChatFerry/master/assets/QR.jpeg", "filehelper")
|
||||
LOG.info(f"send_image: {ret}")
|
||||
|
||||
sleep(5)
|
||||
# 需要确保文件路径正确,建议使用绝对路径(使用双斜杠\\)
|
||||
ret = bot.send_file("https://raw.githubusercontent.com/lich0821/WeChatFerry/master/README.MD", "filehelper")
|
||||
LOG.info(f"send_file: {ret}")
|
||||
|
||||
sleep(5)
|
||||
LOG.info(f"Message types:\n{bot.get_msg_types()}")
|
||||
LOG.info(f"Contacts:\n{bot.get_contacts()}")
|
||||
|
||||
sleep(5)
|
||||
LOG.info(f"DBs:\n{bot.get_dbs()}")
|
||||
LOG.info(f"Tables:\n{bot.get_tables('db')}")
|
||||
LOG.info(f"Results:\n{bot.query_sql('MicroMsg.db', 'SELECT * FROM Contact LIMIT 1;')}")
|
||||
|
||||
# 需要真正的 V3、V4 信息
|
||||
# bot.accept_new_friend("v3", "v4")
|
||||
|
||||
# 添加群成员,填写正确的群 ID 和成员 wxid
|
||||
# ret = bot.add_chatroom_members("chatroom id", "wxid1,wxid2,wxid3,...")
|
||||
# LOG.info(f"add_chatroom_members: {ret}")
|
||||
|
||||
# 删除群成员,填写正确的群 ID 和成员 wxid
|
||||
# ret = bot.del_chatroom_members("chatroom id", "wxid1,wxid2,wxid3,...")
|
||||
# LOG.info(f"add_chatroom_members: {ret}")
|
||||
|
||||
sleep(5)
|
||||
bot.refresh_pyq(0) # 刷新朋友圈第一页
|
||||
# bot.refresh_pyq(id) # 从 id 开始刷新朋友圈
|
||||
|
||||
@receiver.async_message_register()
|
||||
async def async_process_msg(bot: Wcf, msg: WxMsg):
|
||||
"""
|
||||
异步消息函数装饰器
|
||||
"""
|
||||
print(msg)
|
||||
|
||||
# 开始接受消息
|
||||
receiver.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,40 @@
|
||||
#! /usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import wcfauto
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
with open("README.md", "r", encoding="utf-8") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
|
||||
setup(
|
||||
name="wcfauto",
|
||||
version=wcfauto.__version__,
|
||||
author="Changhua",
|
||||
author_email="lichanghua0821@gmail.com",
|
||||
description="一个玩微信的工具",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
license="MIT",
|
||||
url="https://github.com/lich0821/WeChatFerry",
|
||||
python_requires=">=3.8",
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
install_requires=[
|
||||
"setuptools",
|
||||
"wcferry",
|
||||
],
|
||||
classifiers=[
|
||||
"Environment :: Win32 (MS Windows)",
|
||||
"Intended Audience :: Developers",
|
||||
"Intended Audience :: Customer Service",
|
||||
"Topic :: Communications :: Chat",
|
||||
"Operating System :: Microsoft :: Windows",
|
||||
"Programming Language :: Python",
|
||||
],
|
||||
project_urls={
|
||||
"Documentation": "https://wechatferry.readthedocs.io/zh/latest/index.html",
|
||||
"GitHub": "https://github.com/lich0821/WeChatFerry/",
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from wcfauto.auto_res import Register
|
||||
|
||||
__version__ = "39.0.3.0"
|
||||
@@ -0,0 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from wcfauto.auto_res.bot import Register
|
||||
from wcfauto.auto_res.core import load_function
|
||||
|
||||
|
||||
Register = load_function(Register)
|
||||
@@ -0,0 +1,113 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from abc import abstractmethod
|
||||
from typing import Any, Callable
|
||||
|
||||
from wcfauto.event import Event
|
||||
from wcferry.client import Wcf
|
||||
|
||||
|
||||
class Register(Event):
|
||||
def __init__(self, debug=True, **kwargs):
|
||||
super(Register, self).__init__()
|
||||
logging.basicConfig(level='DEBUG', format="%(asctime)s %(message)s")
|
||||
self._LOG = logging.getLogger("Demo")
|
||||
self._LOG.info("开始初始化...")
|
||||
# 默认连接本地服务
|
||||
self._wcf = Wcf(debug=debug, **kwargs)
|
||||
|
||||
@abstractmethod
|
||||
def _process_msg(self, wcf: Wcf):
|
||||
"""
|
||||
有消息的时候,通知分发器分发消息
|
||||
:param wcf: Wcf
|
||||
:return: None
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def _register(self,
|
||||
func: Callable[[Any], Any]):
|
||||
"""
|
||||
消息处理工厂, 所有消息处理函数都会汇总在这里提交给事件分发器
|
||||
:param func: 被装饰的待处理消息函数
|
||||
:return: func
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def _processing_async_func(self,
|
||||
isGroup: bool,
|
||||
isDivision: bool,
|
||||
isPyq: bool):
|
||||
"""
|
||||
异步函数消息处理函数, 用来接受非协程函数
|
||||
参数:
|
||||
:param isGroup 对消息进行限制, 当为True时, 只接受群消息, 当为False时, 只接受私聊消息,
|
||||
注意! 仅当isDivision为 True时, isGroup参数生效
|
||||
:param isPyq 是否接受朋友圈消息
|
||||
:param isDivision 是否对消息分组
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def _processing_universal_func(self,
|
||||
isGroup: bool,
|
||||
isDivision: bool,
|
||||
isPyq: bool):
|
||||
"""
|
||||
同步函数消息处理函数, 用来接受非协程函数
|
||||
参数:
|
||||
:param isGroup 对消息进行限制, 当为True时, 只接受群消息, 当为False时, 只接受私聊消息,
|
||||
注意! 仅当isDivision为 True时, isGroup参数生效
|
||||
:param isPyq 是否接受朋友圈消息
|
||||
:param isDivision 是否对消息分组
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def message_register(self,
|
||||
isGroup: bool = False,
|
||||
isDivision: bool = False,
|
||||
isPyq: bool = False):
|
||||
"""
|
||||
外部可访问接口
|
||||
消息处理函数注册器, 用来接受同步函数
|
||||
参数:
|
||||
:param isGroup 对消息进行限制, 当为True时, 只接受群消息, 当为False时, 只接受私聊消息,
|
||||
注意! 仅当isDivision为 True时, isGroup参数生效
|
||||
:param isPyq 是否接受朋友圈消息
|
||||
:param isDivision 是否对消息分组
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def async_message_register(self,
|
||||
isGroup: bool = False,
|
||||
isDivision: bool = False,
|
||||
isPyq: bool = False):
|
||||
"""
|
||||
外部可访问接口
|
||||
消息处理函数注册器, 用来接受异步函数
|
||||
参数:
|
||||
:param isGroup 对消息进行限制, 当为True时, 只接受群消息, 当为False时, 只接受私聊消息,
|
||||
注意! 仅当isDivision为 True时, isGroup参数生效
|
||||
:param isPyq 是否接受朋友圈消息
|
||||
:param isDivision 是否对消息分组
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def run(self, *args, **kwargs):
|
||||
"""
|
||||
启动程序, 开始接受消息
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def stop_receiving(self):
|
||||
"""
|
||||
停止接受消息
|
||||
"""
|
||||
raise NotImplementedError
|
||||
@@ -0,0 +1,120 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import asyncio
|
||||
import functools
|
||||
import queue
|
||||
import traceback
|
||||
from threading import Thread
|
||||
from typing import Any, Callable
|
||||
|
||||
from wcferry.client import Wcf
|
||||
from wcferry.wxmsg import WxMsg
|
||||
|
||||
|
||||
def load_function(cls):
|
||||
cls._process_msg = _process_msg
|
||||
cls._register = _register
|
||||
cls._processing_async_func = _processing_async_func
|
||||
cls._processing_universal_func = _processing_universal_func
|
||||
cls.message_register = message_register
|
||||
cls.async_message_register = async_message_register
|
||||
cls.run = run
|
||||
cls.stop_receiving = stop_receiving
|
||||
return cls
|
||||
|
||||
|
||||
def _process_msg(self, wcf: Wcf):
|
||||
"""有消息的时候,通知分发器分发消息"""
|
||||
while wcf.is_receiving_msg():
|
||||
try:
|
||||
msg = wcf.get_msg()
|
||||
self._message = msg
|
||||
self._run_func()
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
|
||||
def _register(self,
|
||||
func: Callable[[Any], Any]):
|
||||
self._add_callback(func, self._wcf)
|
||||
# 此处必须返回被装饰函数原函数, 否则丢失被装饰函数信息
|
||||
return func
|
||||
|
||||
|
||||
def _processing_async_func(self,
|
||||
isGroup: bool,
|
||||
isDivision: bool,
|
||||
isPyq: bool,):
|
||||
def _async_func(func):
|
||||
|
||||
@functools.wraps(func)
|
||||
@self._register
|
||||
async def __async_func(bot: Wcf, message: WxMsg):
|
||||
try:
|
||||
# 判断被装饰函数是否为协程函数, 本函数要求是协程函数
|
||||
if not asyncio.iscoroutinefunction(func): raise ValueError(
|
||||
f'这里应使用协程函数, 而被装饰函数-> ({func.__name__}) <-是非协程函数')
|
||||
if message.is_pyq() and isPyq:
|
||||
return await func(bot, message)
|
||||
if not isDivision:
|
||||
return await func(bot, message)
|
||||
if message.from_group() and isGroup:
|
||||
return await func(bot, message)
|
||||
if not message.from_group() and not isGroup:
|
||||
return await func(bot, message)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return __async_func
|
||||
return _async_func
|
||||
|
||||
|
||||
def _processing_universal_func(self,
|
||||
isGroup: bool,
|
||||
isDivision: bool,
|
||||
isPyq: bool, ):
|
||||
def _universal_func(func):
|
||||
|
||||
@functools.wraps(func)
|
||||
@self._register
|
||||
def universal_func(bot: Wcf, message: WxMsg):
|
||||
try:
|
||||
# 判断被装饰函数是否为协程函数, 本函数要求是协程函数
|
||||
if asyncio.iscoroutinefunction(func): raise ValueError(
|
||||
f'这里应使用非协程函数, 而被装饰函数-> ({func.__name__}) <-协程函数')
|
||||
if message.is_pyq() and isPyq:
|
||||
return func(bot, message)
|
||||
if not isDivision:
|
||||
return func(bot, message)
|
||||
if message.from_group() and isGroup:
|
||||
return func(bot, message)
|
||||
if not message.from_group() and not isGroup:
|
||||
return func(bot, message)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return None
|
||||
return universal_func
|
||||
return _universal_func
|
||||
|
||||
|
||||
def message_register(self,
|
||||
isGroup: bool = False,
|
||||
isDivision: bool = False,
|
||||
isPyq: bool = False):
|
||||
return self._processing_universal_func(isGroup, isDivision, isPyq)
|
||||
|
||||
|
||||
def async_message_register(self,
|
||||
isGroup: bool = False,
|
||||
isDivision: bool = False,
|
||||
isPyq: bool = False):
|
||||
return self._processing_async_func(isGroup, isDivision, isPyq)
|
||||
|
||||
|
||||
def run(self, *args, **kwargs):
|
||||
self._wcf.enable_receiving_msg(*args, pyq=True, **kwargs)
|
||||
Thread(target=self._process_msg, name="GetMessage", args=(self._wcf,), daemon=True).start()
|
||||
self._LOG.debug("开始接受消息")
|
||||
self._wcf.keep_running()
|
||||
|
||||
def stop_receiving(self):
|
||||
return self._wcf.disable_recv_msg()
|
||||
@@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from wcfauto.event.event import Event
|
||||
from wcfauto.event.core import load_function
|
||||
|
||||
Event = load_function(Event)
|
||||
@@ -0,0 +1,59 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import asyncio
|
||||
import traceback
|
||||
from threading import Thread
|
||||
|
||||
|
||||
def load_function(cls):
|
||||
cls._add_callback = _add_callback
|
||||
cls._run_func = _run_func
|
||||
return cls
|
||||
|
||||
|
||||
def _add_callback(self, func, bot):
|
||||
"""
|
||||
消息处理函数加载器
|
||||
:param func: 消息处理函数
|
||||
:param args: 消息处理函数参数
|
||||
:param kwargs: 消息处理函数参数
|
||||
"""
|
||||
if func in self._message_callback_func_list: return
|
||||
self._message_callback_func_list.append(func)
|
||||
self._message_callback_func[func] = bot
|
||||
|
||||
|
||||
|
||||
def _run_func(self):
|
||||
"""
|
||||
消息分发器, 将消息发送给所有消息处理函数
|
||||
"""
|
||||
try:
|
||||
async_func = []
|
||||
universal_func = []
|
||||
for ele in self._message_callback_func:
|
||||
if asyncio.iscoroutinefunction(ele):
|
||||
async_func.append(ele)
|
||||
else:
|
||||
universal_func.append(ele)
|
||||
|
||||
# 同步函数运行器
|
||||
def run_universal_func():
|
||||
for fn in universal_func:
|
||||
fn(self._message_callback_func[fn], self._message)
|
||||
|
||||
if len(universal_func) != 0: Thread(target=run_universal_func).start()
|
||||
if len(async_func) == 0: return
|
||||
|
||||
# 异步函数运行器
|
||||
async def _run_callback():
|
||||
tasks = [asyncio.create_task(func(self._message_callback_func[func], self._message))
|
||||
for func in async_func]
|
||||
await asyncio.wait(tasks)
|
||||
|
||||
self._loop.run_until_complete(_run_callback())
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from abc import abstractmethod
|
||||
|
||||
|
||||
class Event(object):
|
||||
_message_callback_func = {}
|
||||
_message_callback_func_list = []
|
||||
_loop = asyncio.get_event_loop()
|
||||
|
||||
def __init__(self):
|
||||
super(Event, self).__init__()
|
||||
self._message = None
|
||||
self._logger: logging = logging.getLogger()
|
||||
|
||||
@abstractmethod
|
||||
def _add_callback(self, func, *args, **kwargs):
|
||||
"""
|
||||
消息处理函数加载器
|
||||
:param func: 消息处理函数
|
||||
:param args: 消息处理函数参数
|
||||
:param kwargs: 消息处理函数参数
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def _run_func(self):
|
||||
"""
|
||||
消息分发器, 将消息发送给所有消息处理函数
|
||||
"""
|
||||
raise NotImplementedError
|
||||
Reference in New Issue
Block a user