Skip to content

Commit 7206fe0

Browse files
author
xin.cui
committed
feat: 🎸 基于wechaty的机器人体验
1 parent 5359d73 commit 7206fe0

File tree

9 files changed

+432
-0
lines changed

9 files changed

+432
-0
lines changed

meizi.py

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import os,re,tqdm,requests,sys,time,colorama
2+
from urllib import request
3+
from lxml import etree
4+
5+
def httpget(url):
6+
i=1
7+
while i<=3:
8+
try:
9+
headers={b'accept': b'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', b'accept-encoding': b'gzip, deflate, br', b'accept-language': b'zh-CN,zh;q=0.9', b'cache-control': b'max-age=0', b'cookie': b'UM_distinctid=17075d85cff10a-01607eb9ead8a8-376b4502-100200-17075d85d00120; CNZZDATA1255357127=319138885-1582524254-%7C1583800577', b'referer': b'https://www.meitulu.com/', b'sec-fetch-mode': b'navigate', b'sec-fetch-site': b'same-origin', b'sec-fetch-user': b'?1', b'upgrade-insecure-requests': b'1', b'user-agent': b'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}
10+
r=requests.get(url=url,headers=headers,timeout=3)
11+
r.raise_for_status()
12+
return r.text
13+
except requests.RequestException as e:
14+
print(colorama.Back.RED+'发生错误:'+str(e))
15+
print('[{}/3]正在尝试重连!'.format(str(i)))
16+
i+=1
17+
print(colorama.Back.RED+'重连失败,请复制错误信息报告作者!')
18+
input('请按Enter键退出!')
19+
sys.exit()
20+
21+
def get_input(maxint,text):
22+
while True:
23+
userin=input(text)
24+
if userin.lower()=='q':sys.exit()
25+
if userin.isdecimal()==True:
26+
if int(userin)<=maxint and int(userin)>0:
27+
return int(userin)
28+
break
29+
print(colorama.Back.RED+'您的输入非法,请重新输入!')
30+
31+
class mtl():
32+
def __init__(self):
33+
self.host='https://www.meitulu.com'
34+
self.titles,self.allurls=[],[]
35+
36+
def search(self):
37+
while True:
38+
while True:
39+
keyword=input('请输入搜索关键词: ')
40+
if keyword=='':print(colorama.Back.RED+'关键词不能为空!')
41+
elif keyword=='q':sys.exit()
42+
elif str.isalnum(keyword)==False:print(colorama.Back.RED+'您的输入非法,请重新输入!')
43+
else:break
44+
45+
t0=time.time()
46+
url=self.host+'/search/'+keyword
47+
html=httpget(url)
48+
ehtml=etree.HTML(html)
49+
self.results=ehtml.xpath("//ul[@class='img']/li")
50+
if len(self.results)==0:
51+
print(colorama.Back.RED+'没有匹配的结果,换个关键词试试吧!')
52+
else:
53+
t1=time.time()
54+
print(colorama.Back.GREEN+'共找到匹配结果{}条,耗时{}秒'.format(str(len(self.results)),str(round(t1-t0,3))))
55+
break
56+
57+
def makeurls(self):
58+
i=get_input(len(self.results),'请输入爬取图集数量: ')
59+
for result in self.results[:i]: #result:一个图集,self.results:所有图集
60+
title=result.xpath("./p[@class='p_title']/a/text()")[0] #获取图集标题
61+
str_num=result.xpath("./p[1]/text()")[0]
62+
num=re.search(r'(?<=:).*(?=张)', str_num).group().strip() #提取图片数量
63+
url0=result.xpath("./a/img/@src")[0].replace('0.jpg','{}.jpg') #图片链接模板
64+
65+
urls=[] #用于储存一个图集中所有图片链接
66+
for i in range(int(num)): #生成图片链接
67+
urls.append(url0.format(str(i+1)))
68+
69+
self.titles.append(title)
70+
self.allurls.append(urls)
71+
72+
def download(self):
73+
i1=0 #下载图集数
74+
c=0 #下载图片计数
75+
t0=time.time()
76+
print('已开始下载任务!')
77+
for title in self.titles:
78+
print('-------------------->>正在下载第{}组,还剩{}组<<--------------------'.format(str(i1+1),str(len(self.titles)-i1-1)))
79+
print(' ·图册标题:'+title)
80+
fdir='./Photos/'+title+'/'
81+
if os.path.isdir(fdir) == False:
82+
os.makedirs(fdir)
83+
pbar=tqdm.tqdm(range(len(self.allurls[i1])),ascii=True,ncols=90)
84+
for i2 in pbar:
85+
path=fdir+'{}.jpg'.format(str(i2+1))
86+
if os.path.isfile(path)==False:
87+
pbar.set_description_str(colorama.Fore.GREEN+' ·下载进度')
88+
try:
89+
request.urlretrieve(self.allurls[i1][i2],path)
90+
c+=1
91+
except Exception:
92+
pbar.set_description_str(colorama.Fore.RED+' ·下载出错')
93+
time.sleep(1.5)
94+
else:
95+
pbar.set_description_str(colorama.Fore.YELLOW+' ·图片已存在')
96+
time.sleep(0.05)
97+
i1+=1
98+
t1=time.time()
99+
print(colorama.Back.GREEN+'\n已完成下载任务,共下载图集{}个(图片{}张),耗时{}秒'.format(str(i1),str(c),str(round(t1-t0,3))))
100+
101+
def run(self):
102+
colorama.init(True)
103+
self.search()
104+
self.makeurls()
105+
self.download()
106+
107+
if __name__ == "__main__":
108+
os.system('title MeiTuLuSpider[V2] @吾爱破解 lihaisanhui')
109+
print('欢迎使用美图录Spider[V2,2020.03.11]!\n前往数据源:https://www.meitulu.com 下载更多精彩图片!\n')
110+
mtl=mtl()
111+
mtl.run()
112+
input('请按Enter键退出!')

wechaty/README.md

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# wechaty-Robot
2+
3+
[![Powered by Wechaty](https://img.shields.io/badge/Powered%20By-Wechaty-green.svg)](https://github.com/chatie/wechaty)
4+
[![Wechaty开源激励计划](https://img.shields.io/badge/Wechaty-开源激励计划-green.svg)](https://github.com/juzibot/Welcome/wiki/Everything-about-Wechaty)
5+
6+
基于 wechaty-puppet-padplus 的微信机器人助手
7+
8+
9+
#### 目前已实现的功能
10+
11+
- 自动通过好友验证
12+
- 当有人添加机器人时,判断验证消息关键字后通过或直接通过
13+
- 通过验证后自动回复并介绍机器人功能
14+
- 私聊关键字回复
15+
- 例如回复 `加群` 推送指定群聊邀请
16+
- 自动聊天
17+
- 群聊中通过 `@机器人名` 可以和机器人聊天需搭配
18+
- 私聊发送消息即可聊天
19+
- 加入群聊自动欢迎
20+
- 当新的小伙伴加入群聊后自动 `@[新入群的]` 发送特定入群欢迎语
21+
22+
23+
24+
#### 结构
25+
26+
```js
27+
|-- src/
28+
|---- index.js # 入口文件
29+
|---- config.js # 配置文件
30+
|---- onScan.js # 机器人需要扫描二维码时监听回调
31+
|---- onRoomJoin.js # 进入房间监听回调
32+
|---- onMessage.js # 消息监听回调
33+
|---- onFriendShip.js # 好友添加监听回调
34+
|-- package.json
35+
```
36+

wechaty/package.json

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "wechaty-pro",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1",
8+
"serve": "node ./src/index.js"
9+
},
10+
"keywords": [],
11+
"author": "",
12+
"license": "ISC",
13+
"dependencies": {
14+
"qrcode-terminal": "^0.12.0",
15+
"request": "^2.88.2",
16+
"urlencode": "^1.1.0",
17+
"wechaty": "^0.31.8",
18+
"wechaty-puppet-padplus": "^0.5.7"
19+
}
20+
}

wechaty/src/config.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
module.exports = {
3+
// puppet_padplus Token
4+
token: "puppet_padplu_你申请的token",
5+
// 机器人名字
6+
name: "氧气",
7+
// 群
8+
room: {
9+
// 管理群组列表
10+
roomList: {
11+
// 群名 : 群id
12+
Goodog: "群id",
13+
前端开发中: "群id"
14+
},
15+
// 加入房间回复
16+
roomJoinReply: `入群欢迎`
17+
},
18+
// 加还有验证
19+
personal: {
20+
// 好友验证自动通过关键字
21+
addFriendKeywords: ["加群", "机器人体验"],
22+
// 是否开启加群
23+
addRoom: true
24+
}
25+
}

wechaty/src/friend.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
const { Friendship } = require("wechaty")
3+
// 配置文件
4+
const config = require("./config")
5+
// 好友添加验证消息自动同意关键字数组
6+
const addFriendKeywords = config.personal.addFriendKeywords
7+
8+
// 好友添加监听回调
9+
module.exports = async function onFriendShip(friendship) {
10+
let logMsg
11+
try {
12+
logMsg = "添加好友" + friendship.contact().name()
13+
console.log(logMsg)
14+
switch (friendship.type()) {
15+
/**
16+
* 1. 新的好友请求
17+
* 设置请求后,我们可以从request.hello中获得验证消息,
18+
* 并通过`request.accept()`接受此请求
19+
*/
20+
case Friendship.Type.Receive:
21+
// 判断配置信息中是否存在该验证消息
22+
if (addFriendKeywords.some(v => v == friendship.hello())) {
23+
logMsg = `自动通过验证,因为验证消息是"${friendship.hello()}"`
24+
// 通过验证
25+
await friendship.accept()
26+
} else {
27+
logMsg = "不自动通过,因为验证消息是: " + friendship.hello()
28+
}
29+
break
30+
31+
/**
32+
* 2. 友谊确认
33+
*/
34+
case Friendship.Type.Confirm:
35+
logMsg = "friend ship confirmed with " + friendship.contact().name()
36+
break
37+
}
38+
console.log(logMsg)
39+
} catch (e) {
40+
logMsg = e.message
41+
}
42+
}

wechaty/src/groupJoin.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
3+
// 配置文件
4+
const config = require("./config")
5+
// 加入房间回复
6+
const roomJoinReply = config.room.roomJoinReply
7+
// 管理群组列表
8+
const roomList = config.room.roomList
9+
10+
// 进入房间监听回调 room-群聊 inviteeList-受邀者名单 inviter-邀请者
11+
module.exports = async function onRoomJoin(room, inviteeList, inviter) {
12+
// 判断配置项群组id数组中是否存在该群聊id
13+
if (Object.values(roomList).some(v => v == room.id)) {
14+
// let roomTopic = await room.topic()
15+
inviteeList.map(c => {
16+
// 发送消息并@
17+
room.say(roomJoinReply, c)
18+
})
19+
}
20+
}

wechaty/src/index.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
const { Wechaty } = require("wechaty") // Wechaty核心包
3+
const { PuppetPadplus } = require("wechaty-puppet-padplus") // padplus协议包
4+
const config = require("./config") // 配置文件
5+
6+
const onScan = require("./onScan") // 机器人需要扫描二维码时监听回调
7+
const onRoomJoin = require("./onRoomJoin") // 加入房间监听回调
8+
const onMessage = require("./onMessage") // 消息监听回调
9+
const onFriendShip = require("./onFriendShip") // 好友添加监听回调
10+
11+
// 初始化
12+
const bot = new Wechaty({
13+
puppet: new PuppetPadplus({
14+
token: config.token
15+
}),
16+
name: config.name
17+
})
18+
19+
bot
20+
.on("scan", onScan) // 机器人需要扫描二维码时监听
21+
.on("room-join", onRoomJoin) // 加入房间监听
22+
.on("message", onMessage(bot)) // 消息监听
23+
.on("friendship", onFriendShip) // 好友添加监听
24+
.start()

0 commit comments

Comments
 (0)