利用公众平台模拟登录发送微信消息给指定好友

今天初来乍到cnode.js,也应该贡献贡献.看到微信公众平台,开始有点兴奋,能做个机器人玩玩,,随后用Node.js写了一个,觉得其实这没什么意思.很快就觉得腻了,于是有了做发送微信接口的想法.首先要做的我们就要模拟公众平台的登陆.对于微信的这些lib,当然不能直接写在routes里面,,那要怎么办呢?没错,就要封装起来,方便复用.你可以打开控制台看到公众平台的登录请求,还有所需的参数,其中密码它是用它本身的md5进行加密的,那么我们需要做的只是将它copy过来放在一个helpers/wx/md5.js文件里就可以直接用了,以下是微信公众平台解析后格式化的js提交代码

submit: function() {
      if (!n()) return;
        var e = d.getVal();
         t.post("/cgi-bin/login?lang=zh_CN", {
            username: e.account,
            pwd1: t.md5(e.password.substr(0, 15)),
            pwd2: t.md5(e.password),
            imgcode: f.data("isHide") ? "": e.verify,
            register: e.isRegister,
            f: "json"
         },

我们要建立一个login的方法

request = require 'superagent'
require __basename + '/helpers/wx/md5'
config = require __basename + '/config/config'
module.exports = 
  login: (fn) ->
    wx_usr = config.wx.user
    wx_pwd = md5 config.wx.pwd.substr(0, 16)
    request
      .post('http://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN')
      .type('form')
      .send(
        username: wx_usr
        pwd: wx_pwd
        imgcode : ''
        f : 'json'
        register : 0
      )
      .end (res) ->
          //在这里你已经成功获取cookie了

但是经过分析我想你会发现,这里的cookie其实并非你想要的cookie,因为它包含一些没用的信息Path=,我们设置cookie的时候,事实上是不能用直接设置这样的cookie,应该是一个cookie里面不应该有其他的东西,而分号后面的path应该将它去掉,这里是返回的结果:

[
"mp_user=xxxxxx; Path=/",
"mp_sid=NlJ2Tm5hb1NXRGxOU3V1MzF2a25tSFVWRHhTNkhwek1nMXlEOVZzMnZMUG1lZ29nSkdENGt3WlgwUjBJZnhydndYNkZSd0ZsaHRHdEozSHBIa3QwT3FWTmdXc3RxVFhYUDBCR3dnWkxIRWVvRlZObG15UC83SzU1aEZPZWpocU8=; Path=/"
]

以下是完整的login代码:

login: (fn) ->
    wx_usr = config.wx.user
    wx_pwd = md5 config.wx.pwd
    request
      .post('http://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN')
      .type('form')
      .send(
        username: wx_usr
        pwd1: wx_pwd
        pwd2: wx_pwd
        imgcode : ''
        f : 'json'
      )
      .end (res) ->
        cookie = ''
        for rs in res.header['set-cookie']
          cookie += rs.replace(/Path=\//g, '')
        fn null, cookie

在这里,我们已经完成登录的操作了,接下来,我们要做的是进行发送,在发送的时候,要把这个cookie设置在请求的地址中,接下来的代码比较简单:(注意:这里面的fakeid是微信公众平台的id,我们可以用控制台去微信公众平台的用户管理中查看,如何获取用户好友的fakeid,接下来一章我会讲)

sender: (options, fn) ->
    msg = options.msg
    fakeid = options.fakeid

    unless msg
      fn error: 'missing msg'
      return

    unless fakeid
      fn error: 'missing fakeid'
      return

    psotParams =
      type: 1
      content: msg
      error: false
      tofakeid : fakeid
      ajax : 1

    request
      .post('http://mp.weixin.qq.com/cgi-bin/singlesend?t=ajax-response&lang=zh_CN')
      .type('form')
      .send(psotParams)
      .set('Cookie', options.cookie)
      .end (res) ->
        fn null, JSON.parse res.text

这里,我们已经能完全发送了,因为返回的结果是一个json,所要最好先JSON.parse一下,里面的成功判断大家可以加上,返回的接口有个叫ret的参数,0为发送成功

{
ret: "0",
msg: "ok"
}

下一章,我会为大家深入讲解怎么发送信息给好友,及获取微信头像等等技术

首先我们要获取这个发送微信人的信息,当你用控制台查看微信的接口你会发现,要有一个Fakeid,那么我们首要要获取Fakeid,其他就好办了.首先我们先获取登录人的这个fakeid,防止后面还会用的.看了一下微信公众平台的所有api接口,,没有发现,那么我们只能去它的用户页面去拿,代码如下:

getFakeId: (options, fn) ->
    request
      .get('http://mp.weixin.qq.com/cgi-bin/userinfopage?t=wxm-setting&lang=zh_CN#')
      .set('Cookie', options.cookie)
      .end (res) ->
         //这里是你的fakeid
 //在拿到的结果里,实际上是一个页面的所有数据,那么我们只能用正则去匹配到所需的fakeid数据,下面是完整的代码:
getFakeId: (options, fn) ->
    request
      .get('http://mp.weixin.qq.com/cgi-bin/userinfopage?t=wxm-setting&lang=zh_CN#')
      .set('Cookie', options.cookie)
      .end (res) ->
        fakeid = res.text.match(/FakeID : "(\d+)"/)[1]
        fn null, fakeid

到了这一步,其实还没有成功,因为我们还没有拿到发送人的fakeid,不然怎么发微信消息给好友呢?于是,我们要去微信公众平台的用户管理页面拿到你所有的好友的fakeid,代码如下:

getFriendPage: (req, fn) ->
    [@login](/user/login) (err, cookie)->
      request
        .get('http://mp.weixin.qq.com/cgi-bin/contactmanagepage?t=wxm-friend&lang=zh_CN&pagesize=&pageidx=0&type=0&groupid=0')
        .set('Cookie', cookie)
        .end (res) ->
       //在这里res.text已经是用户管理页面的html代码了,但是并不会出来,一番查找后,发现是因为它里面的js在我们这里用是有跨域的问题的,知道问题就好办了,查找html它里面设置了document.domain:`document.domain = document.location.hostname.match(/[^\.]+\.com/)[0];`结果在控制台的输出是qq.com,看到这里,就证明我的判断是没有错误的.正则替换掉里面的hostname就ok了.完整代码如下:
getFriendPage: (req, fn) ->
    [@login](/user/login) (err, cookie)->
      request
        .get('http://mp.weixin.qq.com/cgi-bin/contactmanagepage?t=wxm-friend&lang=zh_CN&pagesize=&pageidx=0&type=0&groupid=0')
        .set('Cookie', cookie)
        .end (res) ->
          rs = res.text.replace(/document.location.hostname.match.*\[0\]/g, '"'+req.host+'"')
          fn null, res.text

在这里,大家已经能拿到所有好友的fakeid了,但是不能用jsdom或者cheerio去拿,因为是整个页面加载后才出现好友的html的,至于解决方法我是用phantom.js解决的,具体代码我就不贴了,因为要涉及到安装什么的.因为研究微信公众平台时间也就几天,如果有更好的方法获取好友的fakeid请在下面留言. 到这一步,在这里已经拿到了fakeid了,我们可以去拿到这个微信好友的相关信息,在微信公众平台中,找到了如下接口,以下是代码:

getInfo: (fakeid, fn) ->
    [@login](/user/login) (err, cookie) ->
      request
        .post(’http://mp.weixin.qq.com/cgi-bin/getcontactinfo?t=ajax-getcontactinfo&fakeid=‘+fakeid)
        .type('form')
        .set('Cookie', cookie)
        .end (res) ->
          fn null, JSON.parse res.text

调用代码打印以下结果:

{
FakeId: "xxxx",
NickName: "岳蒙",
ReMarkName: "",
Username: "xxxx",
Signature: "",
Country: "中国",
Province: "江西",
City: "南昌",
Sex: "1",
GroupID: "0",
Groups: [
{
GroupId: "0",
GroupName: "未分组"
},
{
GroupId: "1",
GroupName: "黑名单"
},
{
GroupId: "2",
GroupName: "星标组"
}
]
}

当然群发的话也挺简单的,我已经做好了就不发了,大家可以贴出自己的代码,互相讨论下. 微信发送到这里已经讲完,后面我会为大家准备一个node.js+express的OAuth2的一个认证流程的代码出来/

发布完不能编辑?这… 如果大家想获取微信的头像的话,其实有点复杂,因为是远程图片,而且要附带cookie上去,为了怕新手碰壁,以下贴出代码:下面的__basename其实是我定义的全局变量,放在index.js或者app.js都可以

global.__basename = __dirname

getAvatar: (options, fn) ->
    @login (err, cookie) ->
      request
        .get('mp.weixin.qq.com/cgi-bin/getheadimg?fakeid=' + options.takeid)
        .set('Cookie', cookie)
        .end (res) ->
          f = fs.createWriteStream(__basename + '/public/avatar/'+options.takeid+'.jpg',
            flags: "w"
            encoding: "binary"
          )
          res.on "data", (data) ->
            f.write data
            options.res.write data

          res.on "end", (data) ->
            f.end()
            options.res.end()

发表评论