资讯专栏INFORMATION COLUMN

用Electron-nightmare快速实现微信天气助手Syaya

jiekechoo / 2982人阅读

摘要:项目背景庞大的用户安装量和恐怖的用户使用时间,微信已成为国内移动互联网上基础设施级的应用。以一周时间开发的微信天气查询助手,就是一次技术验证性尝试。但就针对微信来说,不是最好的解决方案。

项目背景

庞大的用户安装量和恐怖的用户使用时间,微信已成为国内移动互联网上基础设施级的应用。

以微信为平台的客服服务有很多方式,比如订阅号,服务号,小程序,但受到微信官方的限制,如果想做一个聊天群的自助客服, 或者私人订制的客服,那就没有了官方的自动化方案。例如场景一:折扣商品导购群里,只要@客服+产品名,就可以马上反馈一条产品折扣信息。场景二:徒步群里参加一个活动报名,只需要@客服+活动名称 就可以自助报名参加活动。

以Electron-nightmare一周时间开发的微信天气查询助手 ,就是一次技术验证性尝试。

依赖项


-

技术选择 python、phantomjs 对比 Electron-nightmare

python的优点,python是非常棒的语言,有着广阔的舞台,在可预见的未来,python的热度还将大幅提升。python有大量的三方库支持,各种重量级的应用框架、前瞻性产品基本上都提供python接口,有大量的社区。就微信机器人来说,有非常优秀的itchat。但就针对微信来说,python不是最好的解决方案。因为python需要从底层web通讯协议开始分析,需要用抓包、分解、组装,完完全全的实现一个web协议的机器人,这其间的开发工作量过大。而且越陷入web底层,将来随着官方协议变更,维护版本的工作量也不容忽视。这背离了我们的初衷:在松耦合基础上尽可能的专注业务本身。而且python还面临2与3的不兼容的坑,也是需要考虑的问题。

phantomjs 一个headless的浏览器框架,基于webkit。第一次了解到phantomjs是用来做爬虫,phantomjs非常适合动态页面的内容爬取,而且phantomjs可以很方便的运行在linux服务器上,相对于普通的浏览器,phantomjs消耗的内存要少太多。但phantomjs也有一些问题。最大的问题就是phantomjs的headless,无法很简单的测试代码片段。而这几年浏览器前端发展迅速,各种js新的特性不断涌现,但phantomjs兼容性问题也凸显:例如phantomjs对set Object就不支持。而且就整体性能而言,没有V8引擎的支持的js,在执行效率上也要打折扣。所以我们还是要尽可能站在巨人的肩膀上拓展业务

站在巨人的肩上,Electron。Electron是基于Google的Chromium框架,本来是专注快速开发跨平台桌面应用。但基于高性能浏览器的Electron是天生的web自动化框架。配合Node.js的express,可以很简单的实现一个RESTFul服务。而浏览器的可视化调试工具也大大提高了测试、调试效率。在Electron上做微信网页版自动化更像是做一个plugin,这将减少了大量的的开发工作。

python, phantomjs, Electron在微信自动化上的对比
功能 python phantomjs Electron
三方库 ★★★★★ ★★★★ ★★★★☆
学习容易 ★★★☆ ★★★☆ ★★★☆
开发效率 ★★ ★★★☆ ★★★★☆
方便测试 ★★☆ ★★☆ ★★★★☆
运行效率 ★★★★☆ ★★☆ ★★★☆
维护简单 ★★☆ ★★★☆ ★★★★☆
硬件要求低 ★★★★☆ ★★★☆ ★★☆
syaya的系统说明

从模块分离的原则,在设计上,将微信机器人作为服务提供出来,这样即可以在以后按照其约定方式(RESTFul)提供新的对接方式,也隔离的本身业务与机器人服务之间的耦合性,而且分离后,基础服务可以远程部署。设计思路如下图

系统分解图

微信网页版代码分析(模块分析)

当前(2017-11-30日)微信网页版是基于AngularJS v1.2.28开发的,采用MVC分离模式。通过分析最主要的index.js源码我们可以大概知道各个功能模块的组合方式。

模块分解图

在了解网页版模式后,接下来就是获取,并调用对应的功能模块,具体实现位于 wxinjector.js

var injector = angular.element(document.body).injector();
var F = {
  chatFactory:injector.get("chatFactory"),
  contactFactory:injector.get("contactFactory"),
  confFactory:injector.get("confFactory"),
  loginFactory:injector.get("loginFactory"),
  accountFactory:injector.get("accountFactory"),
  utilFactory:injector.get("utilFactory"),
}
var CTRLS = {
  appController:angular.element(document.body).scope(),
  loginController:angular.element(document.querySelector("body > div.login.ng-scope")).scope(),
  chatSenderController:angular.element(document.querySelector("#chatArea > div.box_ft.ng-scope")).scope(),
}
编写测试片段代码

chrome的dev-tools是非常好用的可视化测试工具,我们可以将功能片段一点一点的在console中测试后,再添加到项目的代码中

测试获得联系人列表

angular.element(document.body).injector().get("contactFactory").getAllContacts();

测试发送文本消息

function SendMessage(ToUserName, msg){
  var a = angular.element(document.querySelector("#editArea")).scope();
  var confFactory = angular.element(document.body).injector().get("confFactory")
  var chatFactory = angular.element(document.body).injector().get("chatFactory");
  a.editAreaCtn = msg;
  var e = chatFactory.createMessage({
    ToUserName:ToUserName,
    MsgType: confFactory.MSGTYPE_TEXT,
    Content: a.editAreaCtn
  });
  chatFactory.appendMessage(e),
  chatFactory.sendMessage(e),
  // O[chatFactory.getCurrentUserName()] = "",
  a.editAreaCtn = "";
}
项目代码组织
|____conf                       # 程序配置文件
| |____service.json
| |____wxconf.js
| |____cities.json              # 城市气象编码表
|____lib                        # 模块代码
| |____weather.js
| |____inject
| | |____wxinjector.js
| |____wxbot.js
|____test                       # 测试代码目录
|____.gitignore
|____package.json
|____README.md
|____sy-cli.js                  # 天气问答业务程序
|____syaya.js                   # 微信基础服务程序
运行项目

cnpm install

启动微信基础服务 node syaya.js

启动天气问答业务 node sy-cli.js

扫码登录微信账号(业务账号)

用另一个微信账号给业务账号发信息测试


开发过程中的一些备忘经验

ubuntu server上运行electron

$sudo apt-get install xvfb libgtk2.0-0 libnotify-bin libgconf-2-4 libnss3 libasound2 libcap2-bin libcups2 libxtst6 libxss1
$xvfb-run node --harmony syaya.js

window.reload后,重新加载注入脚本的时机: 在事件"dom-ready"中注入

  page.engin.on("dom-ready", function () {
    console.log("DOM-READY for inject...");
    page.engin.inject("js", WX_HELPER_JS);
  });

express下,让curl的post正常工作

var bodyParser = require("body-parser");
var app = express();
app.use(bodyParser.json({
  limit: "100kb",
  type: "application/x-www-form-urlencoded"
}));

js的sleep等待

async function sleep(ms) {
  return new Promise(resolve => {
    var tm = setTimeout(() => {
      console.log("clear", tm);
      clearTimeout(tm);
      resolve(0);
    }, ms);
  });
}
async function test_sleep(){
  var r =  await sleep(2000);
  console.log(r);
}
test_sleep();

js协程处理单条消息, 伪代码

var co = require("co");
function process_one_message(msg){
  co(function *(message) {
    var action = yield extract_action(message);
    var r = yield action.do_step1();
    if(r.status == "success"){
      r = yield action.do_step2();
    }
    r = yield action.do_final();
    r = yield make_response(action, message);
  }, msg);
}
参考

在线XML、JSON数据互转

有哪些免费开放且收录城市较完整的天气 API 接口

http://itchat.readthedocs.io/...

https://github.com/Chatie/wec...

https://shields.io

问题和建议

如果有什么问题或者建议都可以在这个Issue和我讨论
或者也可以在微博上联系我:rockee阿木
或者微信联系:

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90126.html

相关文章

  • 海王必备,我python写了一个微信机器人和她聊天之后把我拉黑了

    摘要:在我看来,很多人起床第一件事情就是看微信消息,既然这样,我就勉为其难每天早晨给小姐姐发送一则天气预报吧。联想起之前看到的一个开源库,一个非常强大的微信调用类库,正好满足我当前的需要,那话不多说,开干。 前言 事情是这样的,最近认识的一位小姐姐有每天早晨看天气预报的习惯。在我看来,很多人起床第...

    lixiang 评论0 收藏0
  • 爆肝一周,Python在物联网设备上写了个智能语音助手

    摘要:背景介绍智能语音助手作为物联网领域的一个重要生态成员,是一种全新的交互方式,它能够解放双手,随时提供服务,无须借助任何按键。学完该案例让你对智能语音助手有一个全新的认识。快来打造你的智能语音助手吧 1. 背景介绍 智能语音助手作为物联网领域的一个重要生态成员,是一种全新的交互方式,它能够解...

    I_Am 评论0 收藏0
  • 快速开发android,离不开这10个优秀的开源项目

    摘要:作为一名菜鸡,时常瞻仰大佬们的开源项目是非常必要的。后台部分在这地址动漫你的名字同款开源,原文效果图简诗地址一款优雅的中国风记录,包括端和端原文相关博客如何在一天之内完成一款具备属性的产品简书地址一个基于豆瓣仿网易云音乐的开源项目。 作为一名菜鸡Android,时常瞻仰大佬们的开源项目是非常必要的。这里我为大家收集整理了10个优秀的开源项目,方便我们日常开发中学习! 作者:Listen...

    wangshijun 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<