微信实现qq群的qq小冰功能

news/2025/2/22 22:50:23/

常玩qq的人应该知道qq群里可以引入一个“聊天机器人”qq小冰,而后可以在群里通过@qq小冰来达到调戏的目的


然而尿性的腾讯除了qq之外还有微信这样一款聊天的软件


本文目的就是注册一个微信号(来作为我们的机器人),将其拉到微信群里然后通过艾特的功能来实现个人聊天或者客服的目的


做为一个不合格的软开,怎么能不用别人的轮子呢(手动斜眼笑)


ok,给出轮子链接https://github.com/cncoder/WeChatBotJava(用Java语言来实现的)


通过这个轮子可以登陆你的微信,获取联系人、监听消息并自动回复


我们的功能是基于此轮子进行的修改


闲话少说


找到类me.biezhi.wechat.service.WechatServiceImpl,其getContact(WechatMeta)方法是用来获取联系人的

此方法中循环处理memberlist过滤其中公告号、群聊等账号,拿到所有用户contactList

因为我们的目的是实现群聊机器人,因此定义群聊联系人groupList并在群聊的判断语句里将当前contact加入到list中

循环结束后将该list注入wechatContact中去


getContact()方法最后调用了私有的getGroup()方法,起初不懂这是要干嘛,后来见名知意发现这个就是用来获取群联系人的(group嘛)

重写该方法,调用微信的webwxbatchgetcontact api,关于该api的具体使用可以自行百度

下面是该方法的代码

/*** 获取群成员* @param wechatMeta* @param wechatContact*/private void getGroup(WechatMeta wechatMeta, WechatContact wechatContact) {String url = wechatMeta.getBase_uri() + "/webwxbatchgetcontact?"+"type=ex"+"&r=" +DateKit.getCurrentUnixTime()+"&lang=zh_CN"+"&pass_ticket="+wechatMeta.getPass_ticket();JSONObject body = new JSONObject();JSONArray groupList = wechatContact.getGroupList();List<Map<String, String>> list = new ArrayList<Map<String, String>>();body.put("BaseRequest", wechatMeta.getBaseRequest());body.put("Count", groupList.size());for (int i = 0; i < groupList.size(); i++) {HashMap<String, String> map = new HashMap<String, String>();map.put("UserName", groupList.get(i).asJSONObject().getString("UserName"));map.put("EncryChatRoomId", "");list.add(map);}body.put("List", list);HttpRequest request = HttpRequest.post(url).contentType("application/json;charset=utf-8").header("Cookie", wechatMeta.getCookie()).send(body.toString());LOGGER.debug(request.toString());String res = request.body();request.disconnect();if (StringKit.isBlank(res)) {throw new WechatException("获取群信息失败");}LOGGER.debug(res);try {JSONObject jsonObject = JSONKit.parseObject(res);JSONObject BaseResponse = jsonObject.get("BaseResponse").asJSONObject();if (null != BaseResponse) {int ret = BaseResponse.getInt("Ret", -1);if (ret == 0) {JSONArray contactList = jsonObject.get("ContactList").asArray();if (null != contactList) {groupList = new JSONArray();for (int i = 0, len = contactList.size(); i < len; i++) {JSONObject contact = contactList.get(i).asJSONObject();if (contact.getString("UserName").indexOf("@@") != -1) {JSONArray memberList =contact.get("MemberList").asArray();for(JSONValue value:memberList) {groupList.add(value);}}}wechatContact.setGroupList(groupList);}}}} catch (Exception e) {throw new WechatException(e);}}

(注意1:groupLIst在这段代码中出现两次,第一次是JSONArray groupList = wechatContact.getGroupList();这里的groupList是群的相关信息,比如群名字,群成员列表等,第二次出现时在groupList.add(value);这里的groupLIst得到的就是群聊中所有成员的信息,包括昵称、用户名、群昵称等

注意2:在实际使用中可能发现这个wechatContact.getGroupList();得到的groupList为空,或者value里没有你想要的群的消息,这是因为这里得到的是被保存在通讯录里的群的列表,打开微信的某个群,在“聊天信息”里有一个“保存到通讯录”功能,这里开关要打开,然后才能获取到里面的值)


拿到了群成员列表之后,岂不就可以为所欲为了吗^_^


上文说到获得的groupList中的每个元素都对应着群中的一个成员,本项目中需要使用的属性为DisplayName和NickName,其中DisplayName为群昵称,就是设置的在这个群的昵称,NickName是个人昵称也就是微信昵称,对于设置了群昵称的群成员就艾特DisplayName,否则艾特NickName。


而群成员在聊天的时候获得的content为Username+内容的组合形式,也就是通过content的username部分获得是哪个用户艾特的机器人,然后根据这个username找到对应grouplist中的某个元素,再得到其displayname或nickname


结尾就是针对该类WechatServiceImpl的完整代码

package me.biezhi.wechat.service;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import com.blade.kit.DateKit;
import com.blade.kit.FileKit;
import com.blade.kit.StringKit;
import com.blade.kit.http.HttpRequest;
import com.blade.kit.json.JSONArray;
import com.blade.kit.json.JSONKit;
import com.blade.kit.json.JSONObject;
import com.blade.kit.json.JSONValue;import me.biezhi.wechat.Constant;
import me.biezhi.wechat.exception.WechatException;
import me.biezhi.wechat.model.WechatContact;
import me.biezhi.wechat.model.WechatMeta;
import me.biezhi.wechat.robot.MoLiRobot;
import me.biezhi.wechat.robot.Robot;
import me.biezhi.wechat.util.Matchers;
import me.cncoder.record.RecordCon;public class WechatServiceImpl implements WechatService {private static final Logger LOGGER = LoggerFactory.getLogger(WechatService.class);// 茉莉机器人private Robot robot = new MoLiRobot();/*** Step7:获取联系人* @url 	https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact* @method POST* @data JSON* @header ContentType: application/json; charset=UTF-8* @params BaseRequest* @return JSON*/@Overridepublic WechatContact getContact(WechatMeta wechatMeta) {String url = wechatMeta.getBase_uri() + "/webwxgetcontact?pass_ticket=" + wechatMeta.getPass_ticket() + "&skey="+ wechatMeta.getSkey() + "&r=" + DateKit.getCurrentUnixTime();JSONObject body = new JSONObject();body.put("BaseRequest", wechatMeta.getBaseRequest());HttpRequest request = HttpRequest.post(url).contentType("application/json;charset=utf-8").header("Cookie", wechatMeta.getCookie()).send(body.toString());LOGGER.debug(request.toString());String res = request.body();request.disconnect();if (StringKit.isBlank(res)) {throw new WechatException("获取联系人失败");}LOGGER.debug(res);WechatContact wechatContact = new WechatContact();try {JSONObject jsonObject = JSONKit.parseObject(res);JSONObject BaseResponse = jsonObject.get("BaseResponse").asJSONObject();if (null != BaseResponse) {int ret = BaseResponse.getInt("Ret", -1);if (ret == 0) {//成员列表JSONArray memberList = jsonObject.get("MemberList").asArray();//联系人列表JSONArray contactList = new JSONArray();//群成员列表JSONArray groupList = new JSONArray();if (null != memberList) {for (int i = 0, len = memberList.size(); i < len; i++) {JSONObject contact = memberList.get(i).asJSONObject();// 公众号/服务号if (contact.getInt("VerifyFlag", 0) == 8) {continue;}// 特殊联系人if (Constant.FILTER_USERS.contains(contact.getString("UserName"))) {continue;}// 群聊if (contact.getString("UserName").indexOf("@@") != -1) {groupList.add(contact);}// 自己if (contact.getString("UserName").equals(wechatMeta.getUser().getString("UserName"))) {continue;}contactList.add(contact);}wechatContact.setContactList(contactList);wechatContact.setMemberList(memberList);wechatContact.setGroupList(groupList);this.getGroup(wechatMeta, wechatContact);System.out.println(wechatContact.toString());return wechatContact;}}}} catch (Exception e) {throw new WechatException(e);}return null;}/*** 获取群成员* @param wechatMeta* @param wechatContact*/private void getGroup(WechatMeta wechatMeta, WechatContact wechatContact) {String url = wechatMeta.getBase_uri() + "/webwxbatchgetcontact?"+"type=ex"+"&r=" +DateKit.getCurrentUnixTime()+"&lang=zh_CN"+"&pass_ticket="+wechatMeta.getPass_ticket();JSONObject body = new JSONObject();JSONArray groupList = wechatContact.getGroupList();List<Map<String, String>> list = new ArrayList<Map<String, String>>();body.put("BaseRequest", wechatMeta.getBaseRequest());body.put("Count", groupList.size());for (int i = 0; i < groupList.size(); i++) {HashMap<String, String> map = new HashMap<String, String>();map.put("UserName", groupList.get(i).asJSONObject().getString("UserName"));map.put("EncryChatRoomId", "");list.add(map);}body.put("List", list);HttpRequest request = HttpRequest.post(url).contentType("application/json;charset=utf-8").header("Cookie", wechatMeta.getCookie()).send(body.toString());LOGGER.debug(request.toString());String res = request.body();request.disconnect();if (StringKit.isBlank(res)) {throw new WechatException("获取群信息失败");}LOGGER.debug(res);try {JSONObject jsonObject = JSONKit.parseObject(res);JSONObject BaseResponse = jsonObject.get("BaseResponse").asJSONObject();if (null != BaseResponse) {int ret = BaseResponse.getInt("Ret", -1);if (ret == 0) {JSONArray contactList = jsonObject.get("ContactList").asArray();if (null != contactList) {groupList = new JSONArray();for (int i = 0, len = contactList.size(); i < len; i++) {JSONObject contact = contactList.get(i).asJSONObject();if (contact.getString("UserName").indexOf("@@") != -1) {JSONArray memberList =contact.get("MemberList").asArray();for(JSONValue value:memberList) {groupList.add(value);}}}wechatContact.setGroupList(groupList);}}}} catch (Exception e) {throw new WechatException(e);}}/*** Step1:获取UUID uuid是服务端用来标识一次登陆的通信* @url https://login.weixin.qq.com/jslogin* @method Get* @data URL Encode* @params <b>appid</b> : wx782c26e4c19acffb  这个值不变,表示来自微信网页版<b>fun</b> : new <b>lang</b>: zh_CN <b>_</b> : 时间戳 * @return window.QRLogin.code = 200; window.QRLogin.uuid = "xxx"*/@Overridepublic String getUUID() throws WechatException {HttpRequest request = HttpRequest.get(Constant.JS_LOGIN_URL, true, "appid", "wx782c26e4c19acffb", "fun", "new","lang", "zh_CN", "_", DateKit.getCurrentUnixTime());LOGGER.debug(request.toString());String res = request.body();request.disconnect();if (StringKit.isNotBlank(res)) {String code = Matchers.match("window.QRLogin.code = (\\d+);", res);if (null != code) {if (code.equals("200")) {return Matchers.match("window.QRLogin.uuid = \"(.*)\";", res);} else {throw new WechatException("错误的状态码: " + code);}}}throw new WechatException("获取UUID失败");}/***Step6: 打开状态提醒*@url https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify*@method POST*@data JSON*@header Content-Type: application/json; charset=UTF-8*@params {*			BaseRequest: { Uin: xxx, Sid: xxx, Skey: xxx, DeviceID: xxx }, *			Code: 3, * 			FromUserName: 自己的ID, * 			ToUserName: 自己的ID, * 			ClientMsgId: 时间戳 * 		  }* @return JSON*/@Overridepublic void openStatusNotify(WechatMeta wechatMeta) throws WechatException {String url = wechatMeta.getBase_uri() + "/webwxstatusnotify?lang=zh_CN&pass_ticket=" + wechatMeta.getPass_ticket();JSONObject body = new JSONObject();body.put("BaseRequest", wechatMeta.getBaseRequest());body.put("Code", 3);body.put("FromUserName", wechatMeta.getUser().getString("UserName"));body.put("ToUserName", wechatMeta.getUser().getString("UserName"));body.put("ClientMsgId", DateKit.getCurrentUnixTime());HttpRequest request = HttpRequest.post(url).contentType("application/json;charset=utf-8").header("Cookie", wechatMeta.getCookie()).send(body.toString());LOGGER.debug("" + request);String res = request.body();request.disconnect();if (StringKit.isBlank(res)) {throw new WechatException("状态通知开启失败");}try {JSONObject jsonObject = JSONKit.parseObject(res);JSONObject BaseResponse = jsonObject.get("BaseResponse").asJSONObject();if (null != BaseResponse) {int ret = BaseResponse.getInt("Ret", -1);if (ret != 0) {throw new WechatException("状态通知开启失败,ret:" + ret);}}} catch (Exception e) {throw new WechatException(e);}}/*** Step5:微信初始化* @url https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit* @method POST* @data JSON* @header Content-Type: application/json; charset=UTF-8* @params 上一步登陆获得的BaseRequest* @return JSON 这一步中获取 SyncKey, User 后面的消息监听用。*/@Overridepublic void wxInit(WechatMeta wechatMeta) throws WechatException {String url = wechatMeta.getBase_uri() + "/webwxinit?r=" + DateKit.getCurrentUnixTime() + "&pass_ticket="+ wechatMeta.getPass_ticket() + "&skey=" + wechatMeta.getSkey();JSONObject body = new JSONObject();body.put("BaseRequest", wechatMeta.getBaseRequest());HttpRequest request = HttpRequest.post(url).contentType("application/json;charset=utf-8").header("Cookie", wechatMeta.getCookie()).send(body.toString());LOGGER.debug("" + request);String res = request.body();request.disconnect();if (StringKit.isBlank(res)) {throw new WechatException("微信初始化失败");}try {JSONObject jsonObject = JSONKit.parseObject(res);if (null != jsonObject) {JSONObject BaseResponse = jsonObject.get("BaseResponse").asJSONObject();if (null != BaseResponse) {int ret = BaseResponse.getInt("Ret", -1);if (ret == 0) {wechatMeta.setSyncKey(jsonObject.get("SyncKey").asJSONObject());wechatMeta.setUser(jsonObject.get("User").asJSONObject());StringBuffer synckey = new StringBuffer();JSONArray list = wechatMeta.getSyncKey().get("List").asArray();for (int i = 0, len = list.size(); i < len; i++) {JSONObject item = list.get(i).asJSONObject();synckey.append("|" + item.getInt("Key", 0) + "_" + item.getInt("Val", 0));}wechatMeta.setSynckey(synckey.substring(1));}}}} catch (Exception e) {}}/*** 选择同步线路*/@Overridepublic void choiceSyncLine(WechatMeta wechatMeta) throws WechatException {boolean enabled = false;for(String syncUrl : Constant.SYNC_HOST){int[] res = this.syncCheck(syncUrl, wechatMeta);if(res[0] == 0){String url = "https://" + syncUrl + "/cgi-bin/mmwebwx-bin";wechatMeta.setWebpush_url(url);LOGGER.info("选择线路:[{}]", syncUrl);enabled = true;break;}}if(!enabled){throw new WechatException("同步线路不通畅");}}/*** Step8:消息检测/检测心跳* @url https://webpush2.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck* @method GET* @data JSON* @header ContentType: application/json; charset=UTF-8* @params BaseRequest* @return window.synccheck={retcode:"xxx",selector:"xxx"}* 			其中retcode:0 正常1100 失败/登出微信selector:0 正常2 新的消息7 进入/离开聊天界面*/@Overridepublic int[] syncCheck(WechatMeta wechatMeta) throws WechatException{return this.syncCheck(null, wechatMeta);}/*** 检测心跳*/private int[] syncCheck(String url, WechatMeta meta) throws WechatException{if(null == url){url = meta.getWebpush_url() + "/synccheck";} else{url = "https://" + url + "/cgi-bin/mmwebwx-bin/synccheck";}JSONObject body = new JSONObject();body.put("BaseRequest", meta.getBaseRequest());HttpRequest request = HttpRequest.get(url, true, "r", DateKit.getCurrentUnixTime() + StringKit.getRandomNumber(5), "skey",meta.getSkey(), "uin", meta.getWxuin(), "sid", meta.getWxsid(), "deviceid",meta.getDeviceId(), "synckey", meta.getSynckey(), "_", System.currentTimeMillis()).header("Cookie", meta.getCookie());LOGGER.debug(request.toString());String res = request.body();request.disconnect();int[] arr = new int[]{-1, -1};if (StringKit.isBlank(res)) {return arr;}String retcode = Matchers.match("retcode:\"(\\d+)\",", res);String selector = Matchers.match("selector:\"(\\d+)\"}", res);if (null != retcode && null != selector) {arr[0] = Integer.parseInt(retcode);arr[1] = Integer.parseInt(selector);return arr;}return arr;}/*** 处理消息*/@Overridepublic void handleMsg(WechatMeta wechatMeta, JSONObject data) {if (null == data) {return;}JSONArray AddMsgList = data.get("AddMsgList").asArray();for (int i = 0, len = AddMsgList.size(); i < len; i++) {// LOGGER.info("你有新的消息,请注意查收");JSONObject msg = AddMsgList.get(i).asJSONObject();int msgType = msg.getInt("MsgType", 0);String content = msg.getString("Content");String name = getUserRemarkName(content.split(":")[0]);if (msgType == 1 ) {if (msg.getString("FromUserName").indexOf("@@") != -1) {LOGGER.info(name + ": " + content);String ans = "@";// webwxsendmsg(wechatMeta, ans+name+" 抓包成功", msg.getString("FromUserName"));LOGGER.info("自动回复 " + name + ":" + name);}} else if (msgType == 3) {String imgDir = Constant.config.get("app.img_path");String msgId = msg.getString("MsgId");FileKit.createDir(imgDir, false);String imgUrl = wechatMeta.getBase_uri() + "/webwxgetmsgimg?MsgID=" + msgId + "&skey="+ wechatMeta.getSkey() + "&type=slave";HttpRequest.get(imgUrl).header("Cookie", wechatMeta.getCookie()).receive(new File(imgDir + "/" + msgId + ".jpg"));// webwxsendmsg(wechatMeta, "无法查看图片", msg.getString("FromUserName"));} else if (msgType == 34) {// webwxsendmsg(wechatMeta, "语音也听不懂", msg.getString("FromUserName"));} }}/*** 发送消息*/private void webwxsendmsg(WechatMeta meta, String content, String to) {String url = meta.getBase_uri() + "/webwxsendmsg?lang=zh_CN&pass_ticket=" + meta.getPass_ticket();JSONObject body = new JSONObject();//写入当前回复对象UserNameRecordCon.cache.add(to);String clientMsgId = DateKit.getCurrentUnixTime() + StringKit.getRandomNumber(5);JSONObject Msg = new JSONObject();Msg.put("Type", 1);Msg.put("Content", content);Msg.put("FromUserName", meta.getUser().getString("UserName"));Msg.put("ToUserName", to);Msg.put("LocalID", clientMsgId);Msg.put("ClientMsgId", clientMsgId);body.put("BaseRequest", meta.getBaseRequest());body.put("Msg", Msg);HttpRequest request = HttpRequest.post(url).contentType("application/json;charset=utf-8").header("Cookie", meta.getCookie()).send(body.toString());//LOGGER.info("发送消息...");//LOGGER.debug("" + request);request.body();request.disconnect();}private String getUserRemarkName(String id) {String name = "这个人物名字未知";for (int i = 0, len = Constant.CONTACT.getGroupList().size(); i < len; i++) {JSONObject member = Constant.CONTACT.getGroupList().get(i).asJSONObject();if (member.getString("UserName").equals(id)) {if (StringKit.isNotBlank(member.getString("RemarkName"))) {name = member.getString("RemarkName");}else if(StringKit.isNotBlank(member.getString("DisplayName"))){name = member.getString("DisplayName");}else {name = member.getString("NickName");}return name;}}return name;}@Overridepublic JSONObject webwxsync(WechatMeta meta) throws WechatException{String url = meta.getBase_uri() + "/webwxsync?skey=" + meta.getSkey() + "&sid=" + meta.getWxsid();JSONObject body = new JSONObject();body.put("BaseRequest", meta.getBaseRequest());body.put("SyncKey", meta.getSyncKey());body.put("rr", DateKit.getCurrentUnixTime());HttpRequest request = HttpRequest.post(url).contentType("application/json;charset=utf-8").header("Cookie", meta.getCookie()).send(body.toString());LOGGER.debug(request.toString());String res = request.body();request.disconnect();if (StringKit.isBlank(res)) {throw new WechatException("同步syncKey失败");}JSONObject jsonObject = JSONKit.parseObject(res);JSONObject BaseResponse = jsonObject.get("BaseResponse").asJSONObject();if (null != BaseResponse) {int ret = BaseResponse.getInt("Ret", -1);if (ret == 0) {meta.setSyncKey(jsonObject.get("SyncKey").asJSONObject());StringBuffer synckey = new StringBuffer();JSONArray list = meta.getSyncKey().get("List").asArray();for (int i = 0, len = list.size(); i < len; i++) {JSONObject item = list.get(i).asJSONObject();synckey.append("|" + item.getInt("Key", 0) + "_" + item.getInt("Val", 0));}meta.setSynckey(synckey.substring(1));return jsonObject;}}return null;}}

其实针对这个轮子还修改了RecordCon类,该类是用来将联系人列表写入本地文件的,不过因为这个不是核心处理类,而且逻辑比较简单,这里就不摘了,最后只需要修改返回值ans比如调用图灵机器人api,就可以实现你自己不可告人的需求了


 


http://www.ppmy.cn/news/788373.html

相关文章

Android开发之添加QQ群的方法(官方代码)

/**************** * * 发起添加群流程。群号&#xff1a;物美价廉淘宝购(485761716) 的 key 为&#xff1a; uTJdlkbFAd9IdpZKEN6vumHHYqFyuTPt * 调用 joinQQGroup(uTJdlkbFAd9IdpZKEN6vumHHYqFyuTPt) 即可发起手Q客户端申请加群 物美价廉淘宝购(485761716) * * param key 由…

ChatGPT在社交媒体分析中的应用如何?

ChatGPT在社交媒体分析中具有广泛的应用潜力&#xff0c;可以提供有价值的洞察和支持。以下是ChatGPT在社交媒体分析中的一些应用场景&#xff1a; 1. 情感分析和舆情监测&#xff1a;ChatGPT可以分析社交媒体上用户的发帖、评论和回复&#xff0c;进行情感分析和舆情监测。它…

java 监控qq群信息_易语言通过监控图标实现QQ消息监控的代码

DLL命令表 .版本 2 .DLL命令 GetWindowThreadProcessId___, 整数型, "user32.dll", "GetWindowThreadProcessId" .参数 hwnd, 整数型 .参数 lpdwProcessId, 整数型, 传址 .DLL命令 OpenProcess___, 整数型, "kernel32.dll", "OpenProcess&q…

QQ加群组件-Android

/**************** * * 发起添加群流程。群号&#xff1a;翻车群(********) 的 key 为&#xff1a; DBByLeFXyW-cDJnA1_gCereoUmgS-26O * 调用 joinQQGroup(DBByLeFXyW-cDJnA1_gCereoUmgS-26O) 即可发起手Q客户端申请加群 翻车群(*******) * * param key 由官网生成的key * ret…

Android/ios/h5 三步调起QQ群聊,一键加群

官网可生成网页、ios、android相关代码等三种方式&#xff0c;二维码就不说了 三步走&#xff1a; 1、登录官网&#xff1a;https://qun.qq.com/join.html 2、选择群聊 3、复制代码 收工。 android代码示例&#xff1a; /**************** * * 发起添加群流程。群号&#…

Android一键加QQ群

接入总流程 Step 1 &#xff1a;发送接入方案阐述&#xff08;详细到设计稿&#xff09;到群开放平台官方邮箱 qunkaifangtencent.com &#xff0c;获得平台认可确定后才可接入应用 Step 2 &#xff1a;开发者在腾讯开放平台进行注册 Step 3 &#xff1a;开发者在腾讯开放平台…

分享qq空间出现失败

分享qq空间出现失败 详情描述 做 qq 分享时&#xff0c;如果给 qq 的链接参数中有中文&#xff1b;会分享失败&#xff1b;

q群机器人php,QQ机器人接口(加群可见)

→ → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → → →↑建↑议↑及↑反↑馈 ------------------------------------- QQ机器人测试_PHP插件_水水的演示站 ---------- 【折腾】基于Node的QQ机器人项目_电脑网…