Wechat_Sender

随时随地发送消息到微信

简介

wechat_sender 是基于 wxpytornado 实现的一个可以将你的网站、爬虫、脚本等其他应用中各种消息 (日志、报警、运行结果等) 发送到微信的工具

初衷

wxpy 基于 itchat 提供了较为完备的微信个人号 API ,而我想使用个人微信来接收我的网站的报警信息以及一些爬虫的结果,因此我写了这个工具。

安装

pip install wechat_sender

运行环境

Python 2.7 及以上 Python 3 及以上

使用

  1. 登录微信并启动 wechat_sender 服务.
from wxpy import *
from wechat_sender import *
bot = Bot()
listen(bot)
# 之后 wechat_sender 将持续运行等待接收外部消息
  1. 在外部向微信发送消息.
from wechat_sender import Sender
Sender().send('Hello From Wechat Sender')
# Hello From Wechat Sender 这条消息将通过 1 中登录微信的文件助手发送给你

如果你是 wxpy 的使用者,只需更改一句即可使用 wechat_sender:

例如这是你本来的代码:

# coding: utf-8
from __future__ import unicode_literals

from wxpy import *
bot = Bot('bot.pkl')

my_friend = bot.friends().search('xxx')[0]

my_friend.send('Hello WeChat!')

@bot.register(Friend)
def reply_test(msg):
    msg.reply('test')

bot.join()

使用 wechat_sender:

# coding: utf-8
from __future__ import unicode_literals

from wxpy import *
from wechat_sender import listen
bot = Bot('bot.pkl')

my_friend = bot.friends().search('xxx')[0]

my_friend.send('Hello WeChat!')

@bot.register(Friend)
def reply_test(msg):
    msg.reply('test')

listen(bot) # 只需改变最后一行代码

之后如果你想在其他程序或脚本中向微信发消息,只需要:

# coding: utf-8
from wechat_sender import Sender
Sender().send("Hello From Wechat Sender")

交流

扫描二维码,验证信息输入 ‘wechat_sender’ 或 ‘加群’ 进入微信交流群

screenshot

listen 方法

listen() 方法用于监听 wxpy 的 bot 对象实例并启动 wechat_sender 服务,为外部发送消息到微信提供支持。

wechat_sender.listen(bot, receivers=None, token=None, port=10245, status_report=False, status_receiver=None, status_interval=3600000)[源代码]

传入 bot 实例并启动 wechat_sender 服务

参数:
  • bot – (必填|Bot对象) - wxpy 的 Bot 对象实例
  • receivers – (选填|wxpy.Chat 对象|Chat 对象列表) - 消息接收者,wxpy 的 Chat 对象实例, 或 Chat 对象列表,如果为 list 第一个 Chat 为默认接收者。如果为 Chat 对象,则默认接收者也是此对象。 不填为当前 bot 对象的文件接收者
  • token – (选填|str) - 信令,防止 receiver 被非法滥用,建议加上 token 防止非法使用,如果使用 token 请在初始化 Sender() 时也使用统一 token,否则无法发送。token 建议为 32 位及以上的无规律字符串
  • port – (选填|int) - 监听端口, 监听端口默认为 10245 ,如有冲突或特殊需要请自行指定,需要和 Sender() 统一
  • status_report – (选填|bool) - 是否开启状态报告,如果开启,wechat_sender 将会定时发送状态信息到 status_receiver
  • status_receiver – (选填|Chat 对象) - 指定 status_receiver,不填将会发送状态消息给默认接收者
  • status_interval – (选填|int|datetime.timedelta) - 指定状态报告发送间隔时间,为 integer 时代表毫秒

小技巧

专门申请一个微信号负责发送应用消息及日志信息
避免使用自己的个人微信造成不便
可以把接收者指定为个人微信

指定接收者

from wxpy import *
from wechat_sender import listen

# 这里登录单独申请的微信号
bot = Bot()
# 这里查询你的个人微信, search 填入你的微信昵称
my = bot.friends().search('your name')[0]
# 传入你的私人微信作为接收者
listen(bot, receivers=my)

向你的私人微信发送消息:

from wechat_sender import Sender
Sender().send('hello')

指定多个接收者

from wxpy import *
from wechat_sender import listen

# 这里登录单独申请的微信号
bot = Bot()
# 这里查询你的个人微信, search 填入你的微信昵称
my = bot.friends().search('your name')[0]
group = bot.groups().search('group name')[0]
# 传入接收者列表
listen(bot, receivers=[my, group])

向 group 发送消息:

from wechat_sender import Sender
Sender('group name').send('hello')

注解

关于接收者:
listen() 传入 receivers 时会把第一个 receiver 当做默认接收者,所有未指定接收者的 Sender 都将把消息发给默认接收者

使用 token 以防 sender 被滥用

警告

wechat_sender 基于 http 服务提供消息发送服务,如果部署在服务器上有潜在盗用风险,所以 listen() 初始化时务必传入 token 以防止盗用

警告

注意保证 token 安全,不要被泄漏

# 同样,基于 http 的服务需要一个端口与外部通信,listen 默认端口是 10245 ,你可以改成任何空闲端口,例如 8888
listen(bot, receiver, token='your secret', port=8888)

注解

如果传入了 token 或 port 请务必保证 Sender 在初始化时也传入相同的 token 和 port

开启 wechat_sender 的状态报告

鉴于微信个人号接口的不稳定性,我们可以开启 wechat_sender 的状态报告,定时向 status_receiver 发送状态信息

listen(bot, my, token='your secret', status_report=True, status_receiver=my)

注解

不指定 status_receiver 时状态报告将发送到默认接收者
默认每隔一小时进行一次状态报告

Sender 发送者对象

Sender 对象可以理解为在外部程序中( 非 wechat_sender 服务,例如你的个人脚本、网站等 )向微信发送消息的发送者

class wechat_sender.Sender(token=None, receivers=None, host=u'http://localhost', port=10245)[源代码]

sender 对象,任何外部程序向微信发送消息都需要初始化 sender 对象:

from wechat_sender import Sender
sender = Sender(token='test', receiver='wechat_name,xxx,xxx')

# 向 receiver 发送消息
sender.send('Hello From Wechat Sender')
Sender.__init__(token=None, receivers=None, host=u'http://localhost', port=10245)[源代码]
参数:
  • token – (选填|str) - 信令,如果不为空请保持和 listen 中的 token 一致
  • receivers – (选填|str) - 接收者,wxpy 的 puid 或 微信名、昵称等,多个发送者请使用半角逗号 ‘,’ 分隔。不填将发送至 default_receiver
  • host – (选填|str) - 远程地址,本地调用不用填写
  • port – (选填|int) - 发送端口,默认 10245 端口,如不为空请保持和 listen 中的 port 一致

指定多个发送者

Sender 的 receiver 可以指定多个发送者,由这个 Sender 发送的消息默认会广播给多个发送者:

# coding: utf-8
import datetime
from wechat_sender import Sender

sender = Sender(token='xxx', receivers='aaa,bbb,ccc,ddd')
sender.send('broadcast message')

注解

使用英文半角逗号分隔多个接收者

Sender.send(message)[源代码]

发送基本文字消息

参数:message – (必填|str) - 需要发送的文本消息
返回:
  • status:发送状态,True 发送成,False 发送失败
  • message:发送失败详情
Sender.delay_send(content, time, title=u'', remind=3600)[源代码]

发送延时消息

参数:
  • content – (必填|str) - 需要发送的消息内容
  • time – (必填|str|datetime) - 发送消息的开始时间,支持 datetime.date、datetime.datetime 格式或者如 ‘2017-05-21 10:00:00’ 的字符串
  • title – (选填|str) - 需要发送的消息标题
  • remind – (选填|int|datetime.timedelta) - 消息提醒时移,默认 1 小时,即早于 time 值 1 小时发送消息提醒, 支持 integer(毫秒) 或 datetime.timedelta
返回:

  • status:发送状态,True 发送成,False 发送失败
  • message:发送失败详情

发送延时消息

某些情况下,我们希望消息可以延迟发送,例如日程、会议提醒等,这时用 Sender.delay_send() 即可满足需求:

# coding: utf-8
import datetime
from wechat_sender import Sender

sender = Sender()
time = datetime.datetime.now()+datetime.timedelta(hours=1)
sender.delay_send(content="测试内容", time=time, title="测试标题", remind=datetime.timedelta(minutes=59))

如果返回正常,1 分钟后你将收到这条消息时间是 1 小时后的消息提醒:

#标题:测试标题
#时间:2017-06-07 12:56:16
#内容:延迟消息测试
Sender.periodic_send(content, interval, title=u'')[源代码]

发送周期消息

参数:
  • content – (必填|str) - 需要发送的消息内容
  • interval – (必填|int|datetime.timedelta) - 发送消息间隔时间,支持 datetime.timedelta 或 integer 表示的秒数
  • title – (选填|str) - 需要发送的消息标题
返回:

  • status:发送状态,True 发送成,False 发送失败
  • message:发送失败详情

发送周期消息

如果希望某条消息周期性发送到微信,可以使用 Sender.periodic_send():

# coding: utf-8
import datetime
from wechat_sender import Sender

sender = Sender()
interval = datetime.timedelta(seconds=10)
sender.periodic_send(content='测试消息', interval=interval, title='测试标题')

如果返回正常,每隔 10 s 你将收到一条消息如下:

# 标题:测试标题
# 内容:周期消息测试test

小技巧

使用 Wechat Sender 的控制命令 查看已注册的延时周期消息

Sender.send_to(content, search)[源代码]

向指定好友发送消息

参数:
  • content – (必填|str) - 需要发送的消息内容
  • search – (必填|str|dict|list)-搜索对象,同 wxpy.chats.search 使用方法一样。例如,可以使用字符串进行搜索好友或群,或指定具体属性搜索,如 puid=xxx 的字典
返回:

  • status:发送状态,True 发送成,False 发送失败
  • message:发送失败详情

发送定向消息

如果你希望某条消息发送给指定的微信好友,你可以使用 Sender.send_to():

# coding: utf-8
import datetime
from wechat_sender import Sender

sender = Sender()
sender.send_to('Hello From Wechat Sender', '微信好友昵称')

如果返回正常,你指定的微信好友将收到这条消息

小技巧

Sender.send_to() 的 search 参数使用方法和 wxpy 的 wxpy.chats().search(). 一致
直接搜索昵称或用综合查询条件均可以搜索好友或群

使用多条件查询好友:

# coding: utf-8
import datetime
from wechat_sender import Sender

sender = Sender()
sender.send_to('Hello From Wechat Sender', search={'city': 'xx', 'nick_name': 'xxx'})

Sender 日志对象

Sender 日志对象可以更平滑的接入外部应用的 log 系统中,基本无需更改代码即可使应用日志发送到微信

class wechat_sender.LoggingSenderHandler(name=None, token=None, receiver=None, host=u'http://localhost', port=10245, level=30)[源代码]

wechat_sender 的 LoggingHandler 对象,可以使用 logging.addHandler() 的方式快速使外部应用支持微信日志输出。在外部应用中:

# spider.py
# 假如在一个爬虫脚本,我们想让此脚本的警告信息直接发到微信

import logging
from wechat_sender import LoggingSenderHandler

logger = logging.getLogger(__name__)

# spider code here
def test_spider():
    ...
    logger.exception("EXCEPTION: XXX")

def init_logger():
    sender_logger = LoggingSenderHandler('spider', level=logging.EXCEPTION)
    logger.addHandler(sender_logger)

if __name__ == '__main__':
    init_logger()
    test_spider()
LoggingSenderHandler.__init__(name=None, token=None, receiver=None, host=u'http://localhost', port=10245, level=30)[源代码]
参数:
  • name – (选填|str) - 标识日志来源,不填将取应用所在服务器地址为名称
  • token – (选填|str) - 信令,如果不为空请保持和 listen 中的 token 一致
  • receiver – (选填|str) - 接收者,wxpy 的 puid 或 微信名、昵称等,不填将发送至 default_receiver
  • host – (选填|str) - 远程地址,本地调用不用填写
  • port – (选填|int) - 发送端口,默认 10245 端口,如不为空请保持和 listen 中的 port 一致
  • level – (选填|int) - 日志输出等级,默认为 logging.WARNING

Wechat Sender 的控制命令

我们向 wechat_sender 发送支持的命令来获取 wechat_sender 的信息

注解

wechat_sender 只会响应 default_recevier 的命令

注解

关于 default_recevier:
listen() 传入 receivers 时会把第一个 receiver 当做 default_recevier
所有未指定接收者的 Sender 都将把消息发给默认接收者

获取运行状态信息

@wss

使用 listen 中绑定的 default_receiver 向 wecaht_sender 发送 @wss 即可返回当前运行状态:

#[当前时间] 09:22:41
#[运行时间] 1 day, 13:33:47
#[内存占用] 28.00 MB
#[发送消息] 67

获取已注册的延时周期消息

@wsr

使用 listen 中绑定的 default_receiver 向 wecaht_sender 发送 @wsr 即可返回已注册的延时周期消息:

#当前已注册延时消息共有1条
#[ID (序号) ]:D0
#[消息接收]:rapospectre
#[发送时间]:2017-06-07 11:57:16
#[消息时间]:2017-06-07 12:56:16
#[消息标题]:延迟消息测试

#当前已注册周期消息共有0条

Wechat Sender 中的基本类

class wechat_sender.objects.WxBot(bot=None, receivers=None, status_receiver=None, *args, **kwargs)[源代码]

储存微信 bot 相关信息及 wechat_sender 各类 receiver 的类

WxBot.__init__(bot=None, receivers=None, status_receiver=None, *args, **kwargs)[源代码]
参数:
  • bot – wxpy bot 对象实例
  • receivers – wxpy chat 对象实例
  • status_receiver – wxpy chat 对象实例
class wechat_sender.objects.Message(content, title=None, time=None, remind=None, interval=None, receivers=None)[源代码]

wechat_sender 消息类,是所有 wechat_sender 发送消息的基本类型

Message.__init__(content, title=None, time=None, remind=None, interval=None, receivers=None)[源代码]
参数:
  • content – 消息内容
  • title – 消息标题
  • time – 消息时间
  • remind – 消息提醒时间
  • interval – 消息提醒间隔
  • receivers – 消息接收者
class wechat_sender.objects.Global(*args, **kwargs)[源代码]

wechat_sender 的全局对象类

最佳实践

在服务器 XXX.XXX.XXX.XXX 部署 wechat_sender 服务:

from wxpy import *
from wechat_sender import *

bot = Bot('bot.pkl', console_qr=True)
bot.enable_puid()
master = ensure_one(bot.friends().search(puid='xxxx'))
log_group = ensure_one(bot.groups().search(puid='xxxxxx'))
other = ensure_one(bot.friends().search('xxxxxx'))
token = 'xxxxxxxxxxxxxxxxxxxxx'
listen(bot, [master, other, log_group], token=token, port=9090, status_report=True, status_receiver=log_group)

在其他地方进行消息发送:

from wechat_sender import Sender
host = 'XXX.XXX.XXX.XXX'
token = 'xxxxxxxxxxxxxxxxxxxxx'
sender = Sender(token=token, receiver='xxx', host=host, port='9090')

在其他应用中加入 wechat_sender logging handler:

# 假如这是你另一台服务器上的脚本
# spider.py

import logging
from wechat_sender import LoggingSenderHandler

logger = logging.getLogger(__name__)

# spider code here
def test_spider():
    ...
    logger.exception("EXCEPTION: XXX")

def init_logger():
    token = 'xxxxxxxxxxxxxxxxxxxxx'
    sender_logger = LoggingSenderHandler('spider', token=token, port=9090, host='XXX.XXX.XXX.XXX', receiver='xxx', level=logging.EXCEPTION)
    logger.addHandler(sender_logger)

if __name__ == '__main__':
    init_logger()
    test_spider()

只需要在原有 logger 中加入 wechat_sender 的 log handler 即可实现把日志发送到微信

底层 API

wechat_sender 是基于 http 提供的服务,因此底层 API 也是基于 http 服务构建的。
所以非 Python 项目也可以使用 wechat_sender 进行信息发送,你只需要自己封装一个简单的 sender 即可

listen() 中设定的 port 与 wechat_sender 部署地址即为服务地址,默认: http://localhost:10245

ADDR = http://localhost:10245

返回码说明

status结果码 状态
0 成功
1 权限不足(token 不正确)
2 bot 故障
3 wechat_sender 服务故障
4 未知错误

发送普通消息

POST ADDR/message

参数
content:(必填|str) - 需要发送的消息
token:(选填|str) - 令牌
receiver:(选填|str) - 接收者名称
返回
{
  "status": 1,
  "message": "Token is missing"
}
or
{
  "status": 0,
  "message": "Success"
}

发送延时消息

POST ADDR/delay_message

参数
content:(必填|str) - 需要发送的消息
title:(选填|str) - 消息标题
time:(选填|str) - 消息时间, “XXXX-XX-XX XX:XX:XX” 形式
remind:(选填|int) - 提醒时移,integer 表示的秒
token:(选填|str) - 令牌
receiver:(选填|str) - 接收者名称
返回
{
  "status": 1,
  "message": "Token is missing"
}
or
{
  "status": 0,
  "message": "Success"
}

发送周期消息

POST ADDR/periodic_message

参数
content:(必填|str) - 需要发送的消息
title:(选填|str) - 消息标题
interval:(选填|int) - 提醒周期,integer 表示的秒
token:(选填|str) - 令牌
receiver:(选填|str) - 接收者名称
返回
{
  "status": 1,
  "message": "Token is missing"
}
or
{
  "status": 0,
  "message": "Success"
}

发送定向消息

POST ADDR/send_to_message

参数
content:(必填|str) - 需要发送的消息
search:(选填|str) - 好友搜索条件
返回
{
  "status": 1,
  "message": "Token is missing"
}
or
{
  "status": 0,
  "message": "Success"
}