微信自动发送消息接口开发(一)

一直有需求想做一个微信自动发送消息的功能,然而官方没有提供公开的接口,趁着下午有空简单的研究了一下.
大概有以下几种方法可以实现:
1:通过电脑版微信去模拟发送消息
这种方式相当于服务器开启一个微信客户端,通过程序获取客户端的句柄去模拟手动操作各种功能,这种方法优势是程序开发完后维护较少,缺点是可能存在技术难点,比方说如何定位到要发送的群,发送图片是否存在难题等.
2:通过网页版微信抓包获取接口,调用接口开发功能.
这种方式占用资源小,效率较高,延迟低,缺点是人家万一重构连接口都改了,就的重新开发了.
3:通过桌面程序内嵌一个web容器,通过web容器模拟操作各种动作.这个相对第一个简单一点,但是也存在服务器开销大,延迟高等问题.
4:通过电脑版微信抓包获取接口,模拟调用接口开发功能.
这个有点是性能达到最高,但是对我而言比较难,TCP协议抓包功夫不到家,万一中途碰到坑爬都爬不出来.

综合考虑觉得还是通过网页版微信抓包先观察观察具体情况再说.
(本人C#网抓喜欢用苏飞的HttpHelper,的确挺好用的.网址:http://www.sufeinet.com/thread-3-1-1.html)

首先访问微信网页版网址: https://wx.qq.com/

观察了一下数据包请求.
登录页面

发现微信并没有用webSocket连接进行通讯,而是采用长轮询的方式进行通讯,感觉有戏.第一次赞美IE8等浏览器的存在.决定就通过网页版微信开发自己想要的接口吧!

首先发现微信会post提交一个 https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxstatreport?fun=new 的接口,
然而一直没有什么返回消息,感觉像是等待消息的接口,先挖一个坑,放在这里.以后再来看.

接下去又会Get请求一个https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_=1515506233792
的接口.
里面有一个appid参数,不知道是怎么获取来的,通过我不懈的努力,发现...是....js里面写死的....
appiid

好吧,你牛B,姑且认为你写死吧,就当写死的用,大不了以后改版了再去你js里面取.

private HttpResult GetLoginHtml()
    {
        Item.URL = "https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_=" + DateTime.Now.Ticks;
        var rst = Http.GetHtml(Item);
        return rst;
    }

恩,不需要任何cookie,直接得到uuid
window.QRLogin.code = 200; window.QRLogin.uuid = "QY1SL_Lv_Q==";

public string Get_uuid()
    {
        try
        {
            var loginRst = GetLoginHtml();
            string html = loginRst.Html;
            var uuid = Regex.Match(html, @"""[^""]+").Value.Substring(1);
            return uuid;
        }
        catch (Exception)
        {
            return null;
        }
    }

紧接着后面又是一个接口就用到uuid了.
https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=QY1SL_Lv_Q==&tip=1&r=616617253&_=1515506837549

这个接口是一个长轮询,应该就是在等待我们用手机扫描二维码了.赶紧看一看这图片是怎么生成的.

微信二维码

太棒了,这图片后面跟着的就是一个uuid(微信扫码登录有时间限制,超过多少时间就会重置,所以没法取到上面的uuid了,其实都一样,就是uuid)

OK,写一个登录自动发送图片到邮箱的方法.(邮箱发送不是本次重点,略过不谈)

public static bool Login(WXService wx, string sendMail)
    {
        string uuid = wx.Get_uuid();
        wx.uuid = uuid;
        if (string.IsNullOrEmpty(uuid))
        {
            Console.WriteLine("获取uuid失败");
            return false;
        }
        //二维码链接
        string url = "https://login.weixin.qq.com/qrcode/" + uuid;
        //发送邮件.
        MailHelper mail = new MailHelper();
        MailItem item = new MailItem();

        item.SendMailNumbers.Add(sendMail);     //发送方邮箱
        item.MailSubJect = "微信登录服务程序";
        item.IsBodyHtml = true;
        item.MailBody = $"<img src='{url}' />";

        return mail.Send(item);

    }

邮箱二维码
完美收到需要扫描的二维码,为将来自动化登录做好基础.

接下来就是长轮询请求等待扫码登录了.
上面已经说过,请求接口是https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=QY1SL_Lv_Q==&tip=1&r=616617253&_=1515506837549

值得注意的是这里的tip参数,第一次请求是1,但是如果超时后,接下来的请求都会提交0
tip

虽然说不知道具体是为了干嘛,不过做网抓的,必须要心细,任何疑点都不要放过,先记录一下留一个坑位,将来有问题了好回来思考.

private HttpResult GetTicket(string uuid)
    {
        var obj = new
        {
            loginicon = true,
            uuid = uuid,
            tip = 0,
            r = DateTime.Now.Ticks,
            _ = DateTime.Now.Ticks
        };
        string url = "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?" + HttpTool.UrlEncodeObj(obj);
        Item.URL = url;

        var rst = Http.GetHtml(Item);

        return rst;
    }

HttpTool是我封装的一些网抓小功能,UrlEncodeObj就是把object对象解析成url的字符串参数.辅助函数不做详细讲解,有疑问的话可以联系我的邮箱.
如果一直没有扫描,最终接口会返回window.code=408;同时再次发出一个相同的请求.
手机扫描二维码后,接口会返回一个window.code=201;同时会将微信的头像以base64的形式返回回来.(通过测试发现,loginicon参数给false就没有头像返回回来,我的服务程序不需要图像,在后面完善时改成了false)
成功登陆后,该接口会返回

window.code=200;
window.redirect_uri="https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=ASDBS3liXbgbLZiGetuv9Y6a@qrticket_0&uuid=wYcsrOLhog==&lang=zh_CN&scan=1515508420";

通过验证后.这个地方又得到一个非常重要的值:ticket
根据redirect_uri接口,微信网页版在后面又加上了&fun=new&version=v2,再次发起请求
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=ASDBS3liXbgbLZiGetuv9Y6a@qrticket_0&uuid=wYcsrOLhog==&lang=zh_CN&scan=1515508420&fun=new&version=v2
可以拿到一个xml数据.里面有用的参数应该有:skey,wxsid,wxuin,pass_ticket,isgrayscale
当然还有很多才cookice
cookice

public WXModel GetOAuthWXModel(string uuid)
    {
        bool authFlag = false;
        WXModel result = new WXModel();
        int c = 0;
        while (!authFlag)
        {
            var rst = this.GetTicket(uuid);
            if (Regex.IsMatch(rst.Html, @"window\.code=200"))
            {   //成功.
                var d = HttpTool.GetUrlCode(rst.Html);
                result.uuid = d["uuid"];
                result.ticket = d["ticket"];

                var oResult = this.GetOAuth(result.uuid, result.ticket, d["scan"]);
                string xml = oResult.Html;
                result.skey = GetXMLValue(xml, "skey");
                result.wxsid = GetXMLValue(xml, "wxsid");
                result.wxuin = GetXMLValue(xml, "wxuin");
                result.pass_ticket = GetXMLValue(xml, "pass_ticket");
                result.isgrayscale = GetXMLValue(xml, "isgrayscale");

                return result;
            }
            c++;

            if (c > 10) break;      //超时.
        }
        return null;
    }

xml

完美拿到xml数据,登录也差不多结束了,接下去要做的应该就是获取人员列表以及发送消息了.
写到这里觉得网页版微信接口抓取还算顺利,后面的数据读取希望也如现在这样一帆风顺!^_^

标签: none

已有 2 条评论

  1. gy gy

    11

  2. nihef nihef

    看着很不错现在都用PC版微信接口发消息了 2645542961

添加新评论