一直有需求想做一个微信自动发送消息的功能,然而官方没有提供公开的接口,趁着下午有空简单的研究了一下.
大概有以下几种方法可以实现:
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里面写死的....
好吧,你牛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,直接得到uuidwindow.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
虽然说不知道具体是为了干嘛,不过做网抓的,必须要心细,任何疑点都不要放过,先记录一下留一个坑位,将来有问题了好回来思考.
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
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数据,登录也差不多结束了,接下去要做的应该就是获取人员列表以及发送消息了.
写到这里觉得网页版微信接口抓取还算顺利,后面的数据读取希望也如现在这样一帆风顺!^_^
11
看着很不错现在都用PC版微信接口发消息了 2645542961