一个主动回复机器人
大家好,我是查理
微信自上线以来,始终没有主动回复的性能,想必是有他们的理念。然而有些人群,的确对此性能有肯定需要,我举两个栗子:
不愿时刻被音讯打搅的人
音讯须要批量解决的人们(比方微商)
设计了几个性能:
[x] 收到音讯立刻主动回复
[x] 收到音讯提早指定工夫回复
[x] 对不同好友定制不同的回复内容
[x] 在手机端随时进行管制
itchat 的原理是通过扫码进行近程微信网页端的登录,而后通过在挪动端进行操作,网页端进行响应,来实现一些性能,尽管仿佛绕了个弯子,然而在微信的限度下,这仿佛曾经是一种最佳的形式了,犹如戴着镣铐起舞。
咱们能够先通过设定几个全局变量来做作为性能的开关和保留数据的容器。
# 主动回复开关
SWITCH_REPLY=True
#提早回复开关
SWITCH_DELAY=False
#延迟时间
DELAY_TIME=120
#音讯前缀开关
SWITCH_PREFIX=True
#音讯前缀内容
PREFIX_CONTENT="[主动回复]"
#回复内容字典
REPLY_DICT={}
#提早回复字典
DELAY_REPLY_DICT={}
而后通过判断 web 端在”文件管理器“中接管到的字符串指令来进行不同操作,这一部分的代码比较简单且简短,这里就不贴出来了,残缺源码地址将会在文末给出。
如果此时咱们收到了敌人的音讯,须要程序给出主动回复。
# 获取发送音讯的敌人的信息
target_friend=itchat.search_friends(userName = msg['FromUserName'])
if target_friend:
#获取 ta 的昵称
nickName=target_friend['NickName']
if not REPLY_DICT.__contains__(nickName):
#设置默认回复
REPLY_DICT[nickName]="道歉我有事暂未看到音讯,稍后回复,若有急事能够电话分割(•ω•`)"
reply_content=REPLY_DICT[nickName]
#判断主动回复开关
if SWITCH_REPLY:
#判断延时回复开关
if SWITCH_DELAY:
localtime = time.time()
DELAY_REPLY_DICT[nickName]=[localtime,msg['FromUserName']]
print (DELAY_REPLY_DICT)
if not SWITCH_DELAY:
#判断音讯前缀开关
if SWITCH_PREFIX:
reply_content = PREFIX_CONTENT + REPLY_DICT[nickName]
else:
reply_content = REPLY_DICT[nickName]
#发送音讯
itchat.send(reply_content, toUserName=msg['FromUserName'])
收到敌人音讯即时进行主动回复是很简略的,然而如何去做延时发送回复音讯呢?(至于做这个性能有没有必要的问题能够先搁置,不过我认为在很多场景下是须要这个性能的,大家也能够在评论区探讨在什么场景下须要提早主动回复)当初就回到技术的问题,如何实现可设置工夫的延时主动回复。
我先谈一谈我的想法,抛砖引玉。个别发送音讯须要用到队列,进行入队和出队,我在这里设置了一个字典来保留音讯发送者的数据。键为音讯发送者的昵称,值是一个长度为 2 的数组,别离保留音讯发送者的微信 id 和接管音讯时的工夫戳。这样我将每条发送过去的敌人信息保留在这个字典中,再通过将设定延迟时间同音讯工夫戳求和与以后工夫戳进行比照,若以后工夫戳较大,那么执行发送音讯的操作。
此时再开启一个线程作为定时工作,定时去检测字典中每条数据是否达到了发送的临界要求(以后工夫戳 >= 音讯工夫戳 + 设定的延迟时间)Python 中有个专门做定时工作的模块叫 sched,然而我尝试了一下,sched 会阻塞以后主线程,也会阻塞 itchat 的线程,所以并不适合。这里我还是采纳了 threading 的 Timer 来充当定时器,不过要留神应用递归,否则将会呈现运行一次就完结的状况。
# 提早发送音讯的函数
def delay_reply():
#print("开始执行")
global DELAY_REPLY_DICT
if SWITCH_DELAY:
while len(DELAY_REPLY_DICT)>0:
localtime = time.time()
# print (localtime)
# print (DELAY_REPLY_DICT[item][0])
# print (int(DELAY_TIME))
for item in list(DELAY_REPLY_DICT.keys()):
if SWITCH_REPLY:
reply_content = item + "," + str(round(int(DELAY_TIME) / 60, 1)) + "分钟过来了," + REPLY_DICT[item]
itchat.send(reply_content, toUserName=DELAY_REPLY_DICT[item][1])
# print ("发送音讯")
del DELAY_REPLY_DICT[item]
print (DELAY_REPLY_DICT)
global timer1
timer1=threading.Timer(DELAY_TIME,delay_reply)
timer1.start()
到此为止,次要的性能曾经实现了,我用一个测试账号对我的微信进行了各种测试,看一下以下截图:
这时性能根本曾经实现了,这就完结了吗?别着急,再想想有没有须要欠缺一下的中央?用过微信 web 端的同学应该晓得,当 web 端长期处于未操作的状态下会失去连贯。在咱们这个状况下,如果你长时间未收到微信音讯,后台程序将会与微信失去连贯,再次开启须要登上服务器重启程序,这显然十分麻烦。有没有什么简略的解决办法呢? 我想到一些利用的后盾通常会做一道心跳检测机制,那我就模拟这个思路,定时给我的”文件管理器“发一个字符串,来放弃连贯。
def keep_alive():
text="放弃登录"
itchat.send(text, toUserName="filehelper")
global timer2
timer2 = threading.Timer(60*60,keep_alive)
timer2.start()
最初,咱们须要将这个程序公布在服务器上,让它全天候为我的微信服务。
image
这里须要留神,如果仅用 python xxxx.py
来运行的话,敞开 shell 会导致过程完结,所以咱们须要应用 nohup python xxxx.py &
来全方位守护过程,这里啰嗦一句,nohup 和 & 的性能是不一样的,很多人容易混同,感兴趣的话能够去查下材料辨别一下。
到此,微信通过了咱们的稍稍调教,曾经乖了一点。然而,这远远不够,思路能够持续拓展,比方实现通过手机微信来管制电脑的开关机,电脑软件的启动敞开,都是能够的,甚至实现管制家中的空调,实践上也未尝不可,只是比拟有难度。
简略剖析微信好友信息
上文提到,既然咱们能通过 itchat 来获取好友的信息,name 天然会有很多好玩的信息(这里不做具体解析)。
性别比例
def get_sex():
# 获取好友数据
my_friends = itchat.get_friends(update=True)[0:]
sex = {"male": 0, "female": 0, "other": 0}
for item in my_friends[1:]:
s = item["Sex"]
if s == 1:
sex["male"] += 1
elif s == 2:
sex["female"] += 1
else:
sex["other"] += 1
total = len(my_friends[1:])
# 开始画饼图
attr = list(sex.keys())
v1 = list(sex.values())
pie = Pie("好友性别比例")
pie.add("", attr, v1, v1, is_label_show=True)
pie.render(path="sex_html/sex.html")
性别比例
全国好友省级散布
def friends_province():
# 获取好友省份
province= get_data("Province")
# 分类
province_distribution = {}
for item in province:
#删除英文省份,因为中国地图表中没有
if bool(re.search('[a-z]',item)):
continue
elif not province_distribution.__contains__(item):
province_distribution[item] = 1
else:
province_distribution[item] += 1
#将省份名为空的删除
province_distribution.pop('')
#提取地图接口须要的数据格式
# print(province_distribution)
province_keys=province_distribution.keys()
province_values=province_distribution.values()
return province_keys,province_values
留神:这里须要本人装置地图,否则会只显示南海诸岛问题,https://www.jianshu.com/p/20fd061d0b96:
解决方案,手动装置地图
- 寰球国家地图: echarts-countries-pypkg (1.9MB): 世界地图和 213 个国家,包含中国地图
- 中国省级地图: echarts-china-provinces-pypkg (730KB):23 个省,5 个自治区
- 中国市级地图: echarts-china-cities-pypkg (3.8MB):370 个中国城市
须要这些地图的敌人,能够装 pip 命令行:
pip install echarts-countries-pypkg
pip install echarts-china-provinces-pypkg
pip install echarts-china-cities-pypkg
特地注明,中国地图在 echarts-countries-pypkg 里。
全国好友散布
好友标签
def friends_signature():
signature = get_data("Signature")
wash_signature=[]
for item in signature:
#去除 emoji 表情等非文字
if "emoji" in item:
continue
rep = re.compile("1f\d+\w*|[<>/=【】『』♂ω]")
item=rep.sub("", item)
wash_signature.append(item)
words="".join(wash_signature)
print(wash_signature)
wordlist = jieba.cut(words, cut_all=True)
word_space_split = " ".join(wordlist)
global NickName
global Sex
# print(NickName, Sex)
# 图片的作用:生成的图片是这个图片的两倍大小
# 依据性别抉择对应的性别模板图
if Sex == 2:
coloring = np.array(Image.open("standard/girl.jpg"))
elif Sex == 1:
coloring = np.array(Image.open("standard/boy.jpg"))
else:
coloring = np.array(Image.open("standard/num.jpg"))
# simkai.ttf 必填项 辨认中文的字体,例:simkai.ttf,my_wordcloud = WordCloud(background_color="white", max_words=800,
mask=coloring, max_font_size=120, random_state=30, scale=2,font_path="fonts/STKAITI.TTF").generate(word_space_split)
image_colors = ImageColorGenerator(coloring)
plt.imshow(my_wordcloud.recolor(color_func=image_colors))
plt.imshow(my_wordcloud)
plt.axis("off")
plt.show()
# 保留图片
my_wordcloud.to_file('Signature/signature.png')
阐明两点:
1、肯定要有标签样幅员,生成对应款式
2、要增加辨认中文的字体