предисловие
Вопросы в начале?
- У вас есть незанятая учетная запись WeChat?
- Вы хотите иметь маленького секретаря, чтобы напоминать вам о том, что вы собираетесь делать регулярно?
- Вас раздражает, что вы забываете о некоторых юбилеях?
- Вы работаете допоздна и забываете, что у вас сегодня назначена встреча с кем-то другим?
- Вы не забываете забрать курьера после работы, только чтобы обнаружить, что забыли, когда пришли домой?
- Хотите научиться быть секретарем WeChat?
Если у вас есть один из вышеперечисленных вопросов, то вы можете его прочитать со спокойной душой, потому что секретарь WeChat может помочь вам решить большинство проблем. Конечно, если совпадения нет, можете продолжить чтение, ведь раз вы здесь, значит, вам все еще интересно😆.
Конечно, если маленькая секретарша не соответствует вашим требованиям.«Напишите скрипт-краулер с помощью Node+wechaty, чтобы каждый день отправлять WeChat теплые слова друзьям женского (мужского) пола»Вы также можете взглянуть на O!
стек технологий
node: рекомендуется последняя стабильная версия.Из-за слабых зависимостей, по крайней мере, узел> 10 или вышеKoa: среда веб-разработки для написания серверных приложений.
MongoDB: нереляционная база данных
mongoose: библиотека, которая подключается к mongodb.
wechaty: Предоставить веб-версию API-интерфейса, связанного с работой WeChat.
node-schedule- Дела по расписанию
адрес проекта
github:GitHub.com/gengchen528…
Функция
Личный секретарь, который очень вас слушает, помогает создавать запланированные задачи, ежедневные напоминания, напоминания о годовщинах и напоминания в тот же день.
Поддерживаемые текстовые форматы:(Ключевые слова нужно разделять пробелами, особенно разделять никнейм и время. Время 24 часа, а выражения пока не поддерживаются 😭)
- «Напомни мне выйти с работы в 18:30, собраться и не забыть что-нибудь взять»(Напоминание в назначенное время суток)
- «Напомнить другим никнейм 2019-09-10 10:00 Как бы вы ни были заняты на работе, не забывайте пить воду»(Доверьте маленькому секретарю напоминать другим)
- «Напоминай мне каждый день в 8:00 брать с собой ключи, автобусную карточку и коробку с обедом, когда я выхожу из дома»(Ежедневное напоминание о назначенном времени)
- «Напоминание wo 2019-09-10 10:00 До дня рождения моей девушки осталось два дня, так что подготовьтесь заранее»(Укажите дату и время напоминания)
Схема эффекта выглядит следующим образом:
напомнить себе
Напоминание делегирования (при условии, что вы и человек, которому вы хотите напомнить, оба являются друзьями маленького секретаря, используя псевдонимы для поиска пользователей, а не замечания, на которые следует обратить внимание)
Задание добавлено в базу
Готов к работе
Так как в этом проекте используется база данных MongoDB, ее необходимо установить на компьютер или сервер самостоятельно, я не буду здесь повторять процесс установки, те, кто не знает, как установить, могуттыкать ссылку, визуализатор для MongoDB, который я использую на Macmongobooster, вы можете скачать его, если вам это нужно.
описание кода
Структура каталогов
- config: koa, таймер Tasker, каталог конфигурации суперагента
- mongodb: файлы конфигурации, связанные с соединением mongodb, основной каталог схемы и модели
- пока: общий метод добычи
основной код wechaty
index.js
Вход в Wechat, инициализация задач по времени и основные файлы для конкретной реализации маленького секретаря. интерфейсgetScheduleList
После каждого входа невыполненные запланированные задачи будут извлекаться из базы данных и инициализироваться, чтобы предотвратить невозможность восстановления запланированных задач после случайного отключения. В то же время каждый раз устанавливайте временную задачу, интерфейсaddSchedule
Запись задачи будет вставлена непосредственно в базу данных, и задача будет добавлена в список запланированных задач. После выполнения каждой задачи интерфейсupdateSchedule
Статус указанной задачи в базе данных будет обновлен для предотвращения повторного выполнения задачи.
const { Wechaty, Friendship } = require('wechaty')
const schedule = require('./config/schedule')
const { FileBox } = require('file-box')
const Qrterminal = require('qrcode-terminal')
const { request } = require('./config/superagent')
const untils = require('./untils/index')
const host = 'http://127.0.0.1:3008/api'
// 每次登录初始化定时任务
initSchedule = async(list) => {
try {
for (item of list) {
let time = item.isLoop ? item.time : new Date(item.time)
schedule.setSchedule(time, async() => {
let contact = await bot.Contact.find({ name: item.subscribe })
console.log('你的专属提醒开启啦!')
await contact.say(item.content)
if (!item.isLoop) {
request(host + '/updateSchedule', 'POST', '', { id: item._id }).then((result) => {
console.log('更新定时任务成功')
}).catch(err => {
console.log('更新错误', err)
})
}
})
}
} catch (err) {
console.log('初始化定时任务失败', err)
}
}
// 二维码生成
onScan = (qrcode, status) => {
Qrterminal.generate(qrcode)
const qrImgUrl = ['https://api.qrserver.com/v1/create-qr-code/?data=', encodeURIComponent(qrcode)].join('')
console.log(qrImgUrl)
}
// 登录事件
onLogin = async(user) => {
console.log(`贴心助理${user}登录了`)
request(host + '/getScheduleList', 'GET').then((res) => {
let text = JSON.parse(res.text)
let scheduleList = text.data
console.log('定时任务列表', scheduleList)
initSchedule(scheduleList)
}).catch(err => {
console.log('获取任务列表错误', err)
})
}
// 登出事件
onLogout = (user) => {
console.log(`${user} 登出了`)
}
// 消息监听
onMessage = async(msg) => {
const contact = msg.from()
const content = msg.text()
const room = msg.room()
if (msg.self()) return
if (room) {
const roomName = await room.topiac()
console.log(`群名: ${roomName} 发消息人: ${contact.name()} 内容: ${content}`)
} else {
console.log(`发消息人: ${contact.name()} 消息内容: ${content}`)
let keywordArray = content.replace(/\s+/g, ' ').split(" ") // 把多个空格替换成一个空格,并使用空格作为标记,拆分关键词
console.log("分词后效果", keywordArray)
if (keywordArray[0] === "提醒") {
let scheduleObj = untils.contentDistinguish(contact, keywordArray)
addSchedule(scheduleObj)
contact.say('小助手已经把你的提醒牢记在小本本上了')
} else {
contact.say('很高兴你能和我聊天,来试试我的新功能吧!回复案例:“提醒 我 18:30 下班回家”,创建你的专属提醒,记得关键词之间使用空格分隔开')
}
}
}
// 添加定时提醒
addSchedule = async(obj) => {
request(host + '/addSchedule', 'POST', '', obj).then(async(res) => {
res = JSON.parse(res.text)
let nickName = res.data.subscribe
let time = res.data.time
let Rule1 = res.data.isLoop ? time : new Date(time)
let content = res.data.content
let contact = await bot.Contact.find({ name: nickName })
schedule.setSchedule(Rule1, async() => {
console.log('你的专属提醒开启啦!')
await contact.say(content)
if (!res.isLoop) {
request(host + '/updateSchedule', 'POST', '', { id: res.data._id }).then((result) => {
console.log('更新定时任务成功')
}).catch(err => {
console.log('更新错误', err)
})
}
})
}).catch(err => {
console.log('错误', err)
})
}
// 自动加好友
onFriendShip = async(friendship) => {
let logMsg
try {
logMsg = '添加好友' + friendship.contact().name()
console.log(logMsg)
switch (friendship.type()) {
/**
*
* 1. New Friend Request
*
* when request is set, we can get verify message from `request.hello`,
* and accept this request by `request.accept()`
*/
case Friendship.Type.Receive:
await friendship.accept()
break
/**
*
* 2. Friend Ship Confirmed
*
*/
case Friendship.Type.Confirm:
logMsg = 'friend ship confirmed with ' + friendship.contact().name()
break
}
} catch (e) {
logMsg = e.message
}
console.log(logMsg)
}
const bot = new Wechaty({ name: 'WechatEveryDay' })
bot.on('scan', onScan)
bot.on('login', onLogin)
bot.on('logout', onLogout)
bot.on('message', onMessage)
bot.on('friendship', onFriendShip)
bot.start()
.then(() => { console.log('开始登陆微信') })
.catch(e => console.error(e))
untils/index.js
Здесь в основном метод обработки после ввода ключевых слов.index.js中
, я разделяю введенные пользователем ключевые слова по пробелам, помещаю их в массив, а затем передаюcontentDistinguish()
метод. В соответствии с различными ключевыми словами, является ли обработка ежедневной задачей, запланированной задачей дня или задачей в указанную дату. Из-за разных типов задач на время формат времени отличается.Для ежедневных задач я используюCron风格定时器
,аналогичный0 30 8 * * *
(Напоминание в 8:30 каждый день) Это при указании даты и времени и задачи дня используюnew Date('2019-9-10 12:30:00')
обрабатывать.
В то же время для совместимости формат двоеточия полной ширины вместо половинной ширины используется при обработке даты, и содержание больше соответствует秘书
Я заменил на вас все темы, а также разобрался с разницей в содержании создания временных задач для себя и тех, которые вы создаете для других.
getToday = () => { // 获取今天日期
const date = new Date()
let year = date.getFullYear()
let month = date.getMonth() + 1
let day = date.getDate()
return year + '-' + month + '-' + day + ' '
}
convertTime = (time) => { // 转换定时格式
let array = time.split(':')
return "0 " + array[1] + ' ' + array[0] + ' * * *'
}
contentDistinguish = (contact, keywordArray) => {
let scheduleObj = {}
let today = getToday()
scheduleObj.setter = contact.name() // 设置定时任务的用户
scheduleObj.subscribe = (keywordArray[1] === "我") ? contact.name() : keywordArray[1] // 定时任务接收者
if (keywordArray[2] === "每天") { // 判断是否属于循环任务
console.log('已设置每日定时任务')
scheduleObj.isLoop = true
scheduleObj.time = convertTime(keywordArray[3])
scheduleObj.content = (scheduleObj.setter === scheduleObj.subscribe) ? scheduleObj.content = "亲爱的" + scheduleObj.subscribe + ",温馨提醒:" + keywordArray[4].replace('我', '你') : "亲爱的" + scheduleObj.subscribe + "," + scheduleObj.setter + "委托我提醒你," + keywordArray[4].replace('我', '你')
} else if (keywordArray[2] && keywordArray[2].indexOf('-') > -1) {
console.log('已设置指定日期时间任务')
scheduleObj.isLoop = false
scheduleObj.time = keywordArray[2] + ' ' + keywordArray[3].replace(':', ':')
scheduleObj.content = (scheduleObj.setter === scheduleObj.subscribe) ? scheduleObj.content = "亲爱的" + scheduleObj.subscribe + ",温馨提醒:" + keywordArray[4].replace('我', '你') : "亲爱的" + scheduleObj.subscribe + "," + scheduleObj.setter + "委托我提醒你," + keywordArray[4].replace('我', '你')
} else {
console.log('已设置当天任务')
scheduleObj.isLoop = false
scheduleObj.time = today + keywordArray[2].replace(':', ':')
scheduleObj.content = (scheduleObj.setter === scheduleObj.subscribe) ? scheduleObj.content = "亲爱的" + scheduleObj.subscribe + ",温馨提醒:" + keywordArray[3].replace('我', '你') : "亲爱的" + scheduleObj.subscribe + "," + scheduleObj.setter + "委托我提醒你," + keywordArray[3].replace('我', '你')
}
return scheduleObj
}
module.exports = {
getToday,
convertTime,
contentDistinguish
}
основной код коа
Излишне говорить, коа, еще один шедевр TJ после экспресса, очень легкий, и избавился от проблемы «адского обратного звонка», поставил изображение бога в городе (прическа очень красивая, ха-ха)
Служба koa по умолчанию использует порт 3008. Если вы его измените, вам потребуется изменить адрес хоста в index.js. В настоящее время здесь написано три интерфейса, а именно: добавление задач по времени, получение списков задач по времени и обновление списков задач.mongodb/model.js
завершено в
config/koa.js
const Koa = require("koa")
const Router = require("koa-router")
const bodyParser = require('koa-bodyparser')
const model = require("../mongodb/model")
const app = new Koa()
const router = new Router()
app.use(bodyParser())
router.post('/api/addSchedule', async(ctx, next) => { // 添加定时任务
let body = ctx.request.body;
console.log('接收参数', body)
let res = await model.insert(body);
ctx.body = { code: 200, msg: "ok", data: res }
next()
})
router.get('/api/getScheduleList', async(ctx, next) => { // 获取定时任务列表
const condition = { hasExpired: false }
let res = await model.find(condition)
ctx.response.status = 200;
ctx.body = { code: 200, msg: "ok", data: res }
next()
})
router.post('/api/updateSchedule', async(ctx, next) => { // 更新定时任务
const condition = { _id: ctx.request.body.id }
let res = await model.update(condition)
ctx.response.status = 200;
ctx.body = { code: 200, msg: "ok", data: res }
next()
})
const handler = async(ctx, next) => {
try {
await next();
} catch (err) {
ctx.respose.status = err.statusCode || err.status || 500;
ctx.response.type = 'html';
ctx.response.body = '<p>出错啦</p>';
ctx.app.emit('error', err, ctx);
}
}
app.use(handler)
app.on('error', (err) => {
console.error('server error:', err)
})
app.use(router.routes())
app.use(router.allowedMethods())
app.listen(3008, () => {
console.log('[demo] route-use-middleware is starting at port 3008')
})
основной код мангуста
mongodb/config.js
Вот в основном основной файл конфигурации MongoDB, использующий mongoose для связывания базы данных MongoDB, порт по умолчанию — 27017, создающий файл с именемwechatAssitant
библиотека
const mongoose = require("mongoose")
const db_url = 'mongodb://localhost:27017/wechatAssitant'
let db = mongoose.connect(db_url, { useNewUrlParser: true })
//连接成功
mongoose.connection.on('connect', () => {
console.log("Mongoose connection open to " + db_url)
})
//连接异常
mongoose.connection.on('error', (err) => {
console.log("Mongoose connection erro " + err);
});
//连接断开
mongoose.connection.on('disconnected', () => {
console.log("Mongoose connection disconnected ");
});
module.exports = mongoose
mongodb/schema.js
В Mongoose все начинается со схемы, и каждая схема сопоставляется с коллекцией в MongoDB. Схема определяет шаблон (или структуру) документов в коллекции.Следующий код определяет схему запланированной задачи:
const mongoose = require('./config')
const Schema = mongoose.Schema
let assistant = new Schema({
subscribe: String, // 订阅者
setter: String, // 设定任务者
content: String, // 订阅内容
time: String, // 定时日期
isLoop: Boolean, // 是否为循环定时任务
hasExpired: { type: Boolean, default: false }, // 判断任务是否过期
createdAt: { type: Date, default: Date.now },
})
module.exports = mongoose.model('Assistant', assistant)
mongodb/model.js
Чтобы использовать определенную схему, нам нужно преобразовать схему в модель, которую мы можем использовать (фактически схема компилируется в модель, поэтому все определения для схемы должны быть завершены до компиляции). Другими словами, модель — это дескриптор, с которым мы можем работать, а конкретный код реализацииmongoose.model('Assistant', assistant)
, здесь мы экспортировали его непосредственно в файл schema.js и сослались на него непосредственно в model.js.
const Assistant = require('./schema')
module.exports = {
insert: (conditions) => { // 添加定时任务
return new Promise((resolve, reject) => {
Assistant.create(conditions, (err, doc) => {
if (err) return reject(err)
console.log('创建成功', doc)
return resolve(doc)
})
})
},
find: (conditions) => { // 获取定时任务列表
return new Promise((resolve, reject) => {
Assistant.find(conditions, (err, doc) => {
if (err) return reject(err)
return resolve(doc)
})
})
},
update: (conditions) => { // 更新定时任务状态
return new Promise((resolve, reject) => {
Assistant.updateOne(conditions, { hasExpired: true }, (err, doc) => {
if (err) return reject(err)
return resolve(doc)
})
})
}
}
Запуск проекта
Поскольку вам нужно установить хром, вам нужно сначала настроить зеркало.Обратите внимание, что из-за ограничения wechaty вы должны использовать node10 или выше.
npm или пряжа настроить источник Taobao
(Очень важно предотвратить сбой загрузки хрома, потому что файл загрузки составляет около 150 МБ, поэтому вам нужно подождать более одной или двух минут для загрузки после запуска npm run start, пожалуйста, подождите терпеливо) npm
npm config set registry https://registry.npm.taobao.org
npm config set disturl https://npm.taobao.org/dist
npm config set puppeteer_download_host https://npm.taobao.org/mirrors
yarn
yarn config set registry https://registry.npm.taobao.org
yarn config set disturl https://npm.taobao.org/dist
yarn config set puppeteer_download_host https://npm.taobao.org/mirrors
Скачать зависимости установки проекта
git clone git@github.com:gengchen528/wechat-assistant.git
cd wechat-assistant.git
npm install
npm run start
сканировать логин
Используйте WeChat для сканирования QR-кода, отображаемого на консоли, и согласитесь войти в систему на своем мобильном телефоне. Используйте другой WeChat для отправки текста в указанном формате, чтобы добавить запланированные задачи.
Развертывание сервера
1. Если вам нужно выполнить развертывание на сервере, вам нужно один раз отсканировать QR-код, чтобы войти в систему, и сгенерировать файл json для WeChat, чтобы сохранить статус входа, как показано ниже:
2. После создания этого файла вы можете использовать инструмент pm2 для демона процесса. Для удобства при локальной разработке я установилnpm run start
Две команды выполняются одновременно, поэтому при развертывании на стороне сервера рекомендуется запускать его первымkoa.js
начать сноваindex.js
Общая проблема
-
Я не могу войти в свою учетную запись WeChat
Начиная с конца июня 2017 года существует высокая вероятность того, что вам будет запрещено входить в систему с помощью веб-решения доступа WeChat. Основные проявления: невозможно войти в Web WeChat, но это не влияет на другие платформы, такие как мобильные телефоны. Убедитесь, что вы не ограничены в входе в систему:wx.qq.comОтсканируйте код, чтобы узнать, можете ли вы войти в систему. Для получения дополнительной информации см.:
[Слух] WeChat закроет веб-версию
Недавно зарегистрированная учетная запись WeChat не может войти в систему
-
Невозможно установить puppet-puppeteer && Chromium при запуске запуска npm
-
Следующие проблемы возникают при развертывании под Centos7
причины проблемы:сегмент fault.com/ah/119000001…
решение:
#依赖库 yum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf2.x86_64 alsa-lib.x86_64 atk.x86_64 gtk3.x86_64 -y #字体 yum install ipa-gothic-fonts xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-utils xorg-x11-fonts-cyrillic xorg-x11-fonts-Type1 xorg-x11-fonts-misc -y
-
Не удалось загрузить puppeteer под windows
Связь:disk.baidu.com/is/1YF09NE LP…Код извлечения: 0mrz
Поместите загруженный файл по пути, как показано ниже, и распакуйте его в текущую папку.
-
-
Поддерживает ли он красные конверты, переводы, круг друзей...?
Связанные с оплатой - красные конверты, переводы, коллекции и т.д. не поддерживаются
-
Подробнее об интерфейсах, связанных с функциями wechaty
-
Другие решения проблем
- Будет ли база данных Mongodb локально
- Сначала проверьте, больше ли версия узла 10
- Подтвердите, что npm или пряжа были настроены с источником Taobao.
- Если есть файл package-lock.json, сначала удалите его.
- удалять
node_modules
повторно выполнить послеnpm install
илиcnpm install
Уведомление
Этот проект относится к разработке личных интересов. Он открыт для технического обмена. Пожалуйста, не используйте этот проект для нарушения правил WeChat или других незаконных действий. Для тестирования рекомендуется использовать небольшую учетную запись, так как существует риск блокировки микроконвертом на авторизации входа на веб-страницу (клиент не затрагивается), пожалуйста, убедитесь, что используете его добровольно.
наконец
Моя маленькая секретарша научилась функции автоматического добавления друзей, поэтому заинтересованные друзья могут добавить мой WeChat для проверки, она также может быть вашим личным секретарем 😆 (Будьте осторожны, не отправляйте слишком много сообщений, это ее испортит )
Спешите попробовать сами, я думаю, вы откроете для себя больше интересных возможностей
github:GitHub.com/gengchen528…