qq聊天机器人 群发工具 (java版) (二)

上一篇介绍了如何借用webqq协议登陆qq,这一篇主要讲下如何实现群发消息。就目前我所知的消息类型有3种,分别是好友消息,群消息以及临时会话消息(这个一般是往群组成员群发)。3种消息分别对应3种方法(3个post方法),下面依次介绍。

1.群发好友消息

要想群发好友消息,首先要获取消息对象,也即好友列表。只有获取了每个QQ好友的标识,才知道往谁去发消息。所以,群发的第一步其实就是获取对象,这里也即获取好友列表。下面是获取好友列表的post请求信息:

Request URL:http://s.web2.qq.com/api/get_user_friends2
Request Method:POST
Content-Type:application/x-www-form-urlencoded
Referer:http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1
Form-Data:r={"vfwebqq":"23aedade67a2278b9a807015eb4bcad5771671c3a7c5a5e7c017034b9ba9d3f28407f179e5f34566","hash":"51C8576A0E1B5A7D"}

url地址很简单,看名字也知道意思,post方法。一定要记住要设置请求头Content-Type为application/x-www-form-urlencoded(不设置post请求就不成功即返回的retcode不为0)。同时也要设置请求头Referer,不然也会失败(后续很多方法都要设置Referer)。再就是表单数据,同之前一样,json字符串之前一定要带上"r="。vfwebqq即上篇中我所提到的,单独获取vfwebqq返回的值,而非第二次登陆成功所返回的值。hash是通过某种方式加密后获取到的值,同密码一样,是通过js文件加密的。这边先附上js的链接:http://0.web.qstatic.com/webqqpic/pubapps/0/50/eqq.all.js。加密方法就在这个js里面,将代码格式化后找到P
= function(b, j) 这个方法(参数可能不是b,j,方法每隔一段时间就会变),只将这个方法提取出来就好,加密用到的就是这个方法。b即登陆的QQ账号,j即之前登陆时获取的ptwebqq。下面先贴出我提取出后更改函数名后的hash加密方法(至少今天还是这个方法,以后即使方法换了,js文件地址也不变,方法结构大致也差不多,即使不懂如何加密的,在js文件里找类似的方法也容易):

function getHash(b, j) {
	for (var a = [], i = 0; i < j.length; i++) a[i % 4] ^= j.charCodeAt(i);
	var w = ["EC", "OK"],
	d = [];
	d[0] = b >> 24 & 255 ^ w[0].charCodeAt(0);
	d[1] = b >> 16 & 255 ^ w[0].charCodeAt(1);
	d[2] = b >> 8 & 255 ^ w[1].charCodeAt(0);
	d[3] = b & 255 ^ w[1].charCodeAt(1);
	w = [];
	for (i = 0; i < 8; i++) w[i] = i % 2 == 0 ? a[i >> 1] : d[i >> 1];
	a = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
	d = "";
	for (i = 0; i < w.length; i++) d += a[w[i] >> 4 & 15],
	d += a[w[i] & 15];
	return d
};

下面附上Java调用js的方法:

/**
 * 获取QQ好友列表的post参数hash
 *
 * @param paras
 * @return
 * @throws ScriptException
 * @throws FileNotFoundException
 * @throws NoSuchMethodException
 */
public static String getHash(String QQ, String ptwebqq) {
	Object t = null;
	try {
		ScriptEngineManager m = new ScriptEngineManager();
		ScriptEngine se = m.getEngineByName("javascript");
		se.eval(new FileReader(new File("resources/js/eqq.all.js")));
		t = se.eval("getHash(\"" + QQ + "\",\"" + ptwebqq + "\")");
		return t.toString();
	} catch (Exception e) {
		e.printStackTrace();
	}
	return t.toString();
}

最后附上发送post请求的方法,首先拼装好发送的json字符串,这里切记,json数据要经过url转码(外面的"r="不需要转码)

getFriendListStr = "{\"vfwebqq\":\"" + vfwebqq + "\",\"hash\":\""
				+ hash + "\"}";
		getFriendListStr = "r="
				+ URLEncoder.encode(getFriendListStr, "utf-8");

下面是post方法:

// 获取好友列表
public static boolean getFriendList() throws Exception {
	// post 请求
	DefaultHttpClient client = new DefaultHttpClient();
	HttpPost postjson = new HttpPost(
			"http://s.web2.qq.com/api/get_user_friends2");

	postjson.setHeader("Referer",
			"http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1");

	HttpClientParams.setCookiePolicy(client.getParams(),
			CookiePolicy.BROWSER_COMPATIBILITY);

	client.getParams().setParameter(
			CoreConnectionPNames.CONNECTION_TIMEOUT, 5000);
	client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 5000);

	StringEntity entity = new StringEntity(getFriendListStr);
	entity.setContentType("application/x-www-form-urlencoded");
	postjson.setEntity(entity);

	// 设置CookieStore
	if (cs != null) {
		client.setCookieStore(cs);
	}

	// 获得返回的json数据包
	HttpResponse httpResponse = client.execute(postjson);
	HttpEntity httpent = httpResponse.getEntity();

	// 保存CookieStore
	cs = client.getCookieStore();

	String line;
	StringBuffer sb = new StringBuffer();

	if (httpent != null) {
		BufferedReader br = new BufferedReader(new InputStreamReader(
				httpent.getContent(), "UTF-8"));
		while ((line = br.readLine()) != null) {
			sb.append(line);
		}
		br.close();
	}
	JSONObject obj = new JSONObject(sb.toString());
	if (obj.getInt("retcode") == 0) {
		JSONObject res = obj.getJSONObject("result");
		QQMsgHandler.getInstance().getFriendList(res);// 处理信息,得到好友列表
		return true;
	} else {
		return false;
	}
}

请求成功返回的json数据如下:

{"retcode":0,"result":{"friends":[{"flag":0,"uin":2741681712,"categories":0},{"flag":0,"uin":2117029336,"categories":0}],"marknames":[],"categories":[],"vipinfo":[{"vip_level":0,"u":2741681712,"is_vip":0},{"vip_level":0,"u":2117029336,"is_vip":0}],"info":[{"face":303,"flag":294126146,"nick":"               ScumVirus","uin":2741681712},{"face":564,"flag":8388608,"nick":"ScumVirus","uin":2117029336}]}}

在friends中有categories这个属性,可能是好友分组的标志位,不过这里我没研究,因为我只做了群发所有好友消息。有兴趣的朋友可以深入分析下好友分组,这样可以指定只给某一分组的好友发送消息,这样那些生活工作通用一个QQ的人群发消息会比较方便。info跟friends类似,不过没有带上分组信息,多了用户昵称。所以我只截取了info中的数据作为好友列表,uin即每一个好友的标识,nick即昵称。face不知道是什么,我没深入研究,flag也是一个标志位,但是具体有什么作用我也不知道,因为实现群发功能uin作为标识足矣。中间的vipinfo应该是与qq会员相关的信息,不过一般做QQ机器人都没有这方面需求,我直接无视了。

接下来就要发送好友消息了。其实群发消息也就是给每一个好友都发送一条消息(我没试过在json里以数组形式写上所有消息,不知道能不能实现一次群发)。

Request URL:http://d.web2.qq.com/channel/send_buddy_msg2
Request Method:POST
Referer:http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=2
Form-Data:r={"to":2741681712,"content":"[\"123\",[\"font\",{\"name\":\"宋体\",\"size\":10,\"style\":[0,0,0],\"color\":\"000000\"}]]","face":564,"clientid":53999199,"msg_id":38600001,"psessionid":"8368046764001d636f6e6e7365727665725f77656271714031302e3133392e372e313630000054bd00000bcd026e04003654298d6d0000000a404e364b386b707858676d000000286740432cf4f2628258046027ab71e7c932587058acf842d2c727a076b663ff32b4082a088f3c4521"}

依旧是post请求,不过要带上Referer,json字符串格式如上所示。to是发送对象即好友的uin,content里带的是发送文字的相关信息,我发的是最普通的消息,所有参数都是默认的,如果你想发点与众不同的, 改下参数即可。clientid同登陆一样,随机8-9位,随便写,我程序里这个参数都是写的固定的默认值。msg_id为发送消息的标识,随便写个数字,然后每发一条自增加1作为区分即可(即使每次都一样好像也没什么影响吧,不过最好+1吧),psessionid也是登陆成功返回的参数。代码同之前没什么区别,就不贴了。

2.群发群消息

同上,先获取对象,即群列表。·获取群消息的post请求如下:

Request URL:http://s.web2.qq.com/api/get_group_name_list_mask2
Request Method:POST
Content-Type:application/x-www-form-urlencoded
Referer: http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1
Form-Data:r={"vfwebqq":"23aedade67a2278b9a807015eb4bcad5771671c3a7c5a5e7c017034b9ba9d3f28407f179e5f34566","hash":"51C8576A0E1B5A7D"}

方法大致同获取好友列表时,只有url地址不一样,其他都一样(包括json数据)。返回的json数据如下:

{"retcode":0,"result":{"gmasklist":[],"gnamelist":[{"flag":1090520065,"name":"芭蕉躲在被窝不给h包","gid":4065055661,"code":818309331},{"flag":17826817,"name":"ScumVirus","gid":1068943425,"code":1244601995},{"flag":16778241,"name":"永丶夜","gid":818744232,"code":171813541},{"flag":16778241,"name":"ScumVirus机器人","gid":2646811562,"code":3760910371}],"gmarklist":[]}}

gid即群标识,也即我们发送群消息的对象。不过code也是群的一种标示,不过不同于gid。

这里简单讲解一下uin和gid分别是好友标识和群标识,针对同一个对象(1个好友或者1个群),同一账号每次登陆获取到的标识是一样的,但是不同账号获取的不同。比如说a,b在群c中,但是a登陆后获取到c的gid为1,b登陆后获取到c的gid可能就是2,反正不同于a获取到的。但是code不一样,每个人每次登陆获取到同一个群的gid是一样的,比如如上的永丶夜这个群,我2个账号登陆获取到的gid都是818744232这个值,一直不变。gid只能作为群消息发送的标识,若要获取群组成员的信息,则是code作为群组标识,这个在发送临时会话消息时会提到。

发送群消息的请求如下:

Request URL:http://d.web2.qq.com/channel/send_qun_msg2
Request Method:POST
Content-Type:application/x-www-form-urlencoded
Referer:http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=2
Form-Data:r={"group_uin":1068943425,"content":"[\"123\",[\"font\",{\"name\":\"宋体\",\"size\":10,\"style\":[0,0,0],\"color\":\"000000\"}]]","face":564,"clientid":53999199,"msg_id":38600002,"psessionid":"8368046764001d636f6e6e7365727665725f77656271714031302e3133392e372e313630000054bd00000bcd026e04003654298d6d0000000a404e364b386b707858676d000000286740432cf4f2628258046027ab71e7c932587058acf842d2c727a076b663ff32b4082a088f3c4521"}

基本同发送好友消息一致,json数据中group_uin即之前获取到的gid,其他同发送好友消息无区别。

3.发送临时会话消息

这边的临时会话仅指和已有群的群内成员发送会话。毕竟发送消息要获取对象的标识,这个标识又不是qq账号,而是uin,如果你只知道一个人的QQ号,但是和他又不是好友,又不在同一个群里,那么是没法获取到他相对于你的uin的,即发送消息不成立。

回归正题,如上所说,我们是要通过群来获取群成员相对于自身的uin。首先,我们要先获取群内所有成员的信息,这里要用到之前提到的code。post请求如下:

Request URL:http://s.web2.qq.com/api/get_group_info_ext2?gcode=1244601995&vfwebqq=670f701a39ab1b21c05007564cf8936d6000b1f5a34093689aaa7ff67e8a3ede932d3ecb1b98f27c&t=1433068633058
Request Method:GET
Referer:http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1

这里很简单,仅仅一个get方法就获取到的一个群内的所有成员信息,gcode即之前说的code,vfwebqq不谈了,t即时间戳,直接用System.currentTimeMillis()获取就好。

返回的json数据如下:

{"retcode":0,"result":{"stats":[{"client_type":41,"uin":2368295990,"stat":10}],"minfo":[{"nick":"               ScumVirus","province":"湖北","gender":"male","uin":2741681712,"country":"中国","city":"武汉"},{"nick":"ScumVirus","province":"湖北","gender":"male","uin":570904041,"country":"中国","city":"武汉"},{"nick":"No Game No Bot","province":"湖北","gender":"female","uin":2368295990,"country":"中国","city":"武汉"},{"nick":"ScumVirus","province":"湖北","gender":"male","uin":2117029336,"country":"中国","city":"武汉"}],"ginfo":{"face":0,"memo":"yy108371257","class":25,"fingermemo":"","code":1244601995,"createtime":1321090723,"flag":17826817,"level":0,"name":"ScumVirus","gid":1068943425,"owner":2741681712,"members":[{"muin":2741681712,"mflag":192},{"muin":570904041,"mflag":0},{"muin":2368295990,"mflag":0},{"muin":2117029336,"mflag":0}],"option":2},"vipinfo":[{"vip_level":0,"u":2741681712,"is_vip":0},{"vip_level":0,"u":570904041,"is_vip":0},{"vip_level":0,"u":2368295990,"is_vip":0},{"vip_level":0,"u":2117029336,"is_vip":0}]}}

这里只关注minfo即可,里面既有用户昵称,居住地,性别,也有我们要的uin标识。

接下来就是发送临时消息了,不过在这个方法比之前的2种方法要多出一步,他要获取group_sid这个参数才能发送临时会话消息,不过这个参数也很好拿到,一个get请求就行了。请求如下:

Request URL:http://d.web2.qq.com/channel/get_c2cmsg_sig2?id=<span style="font-family: Arial, Helvetica, sans-serif;">1068943425</span>&to_uin=570904041&clientid=53999199&psessionid=8368046764001d636f6e6e7365727665725f77656271714031302e3133392e372e313630000054bd00000bcd026e04003654298d6d0000000a404e364b386b707858676d000000285f293205986c0c9381ea5471ac8bdfd996fb8ca4765bcebab0230c3b0fb85cf513378825ebe2ade8&service_type=0&t=1433069146558
Request Method:GET
Referer:http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=2

id即群标识gid,to_uin即你要发送对象的uin标识,service_type我也不知道是什么,默认填0也不会错,其他参数之前都提过不多说了。

返回的json数据如下:

{"retcode":0,"result":{"type":0,"value":"b1a949941bc21ea0e56529d6c71b9065083e0ab74ca8ee8cedb0135440fe17b54fb8a807e202a0e491f40cf403d5e22e","flags":{"text":1,"pic":1,"file":1,"audio":1,"video":1}}}

只取其中的value,即是我们要的group_sig。

下面就到发送消息了,请求如下:

Request URL:http://d.web2.qq.com/channel/send_sess_msg2
Request Method:POST
Referer:http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=2
Form-Data:r={"to":570904041,"content":"[\"123\",[\"font\",{\"name\":\"宋体\",\"size\":10,\"style\":[0,0,0],\"color\":\"000000\"}]]","face":564,"clientid":53999199,"msg_id":93440002,"psessionid":"8368046764001d636f6e6e7365727665725f77656271714031302e3133392e372e313630000054bd00000bcd026e04003654298d6d0000000a404e364b386b707858676d00000028d173ff0fccee9875162f70075476dfb3712e59456440efca2a0db0fb063216d74084919fd7185f16","group_sig":"b1a949941bc21ea0e56529d6c71b9065083e0ab74ca8ee8cedb0135440fe17b54fb8a807e202a0e491f40cf403d5e22e","service_type":0}

to即目标uin,group_sig即我们刚获取到的参数,service_type默认填0吧,反正不会错。

3种消息发送都有返回值,只判断recode是否为0就可知道是否发送成功。以上即是本篇介绍的所有内容。

注:若消息内容带回车,则可能发送失败。我目前也不知道回车字符该如何转码,反正怎么发都是失败,易语言论坛有人在15年1月写了一个解决方案被采纳了,不过我按照java的方式写了还是发送失败,因为我不懂易语言,所以可能我理解错了。

再稍微说点其他的。

目前我见到过2种QQ机器人,一种是酷Q,它是仿QQ老版界面做的,可以看到好友列表(这个上面我也提到过如何获取好友列表,它只是将列表显示出来了而已,群也一样),如果想给指定的某些人或群发送消息,那么你也可以做个列表,每个item前加上个jcheckbox让用户选择即可。另外一种是晨风QQ机器人。不过那个跟我做的差不多,没有列表展示,只是一堆功能设置放在上面。不过方法都有了,界面如何设计就看用户的需求了。

1068943425

时间: 2024-12-27 18:43:27

qq聊天机器人 群发工具 (java版) (二)的相关文章

qq聊天机器人 群发工具 (java版) (三)

本篇简单讲解一下如何接收QQ消息. 在成功登陆QQ后,要每隔一段时间发一个POST请求,用来维持登陆状态,同时也是用来接收消息的,请求如下: Request URL:http://d.web2.qq.com/channel/poll2 Request Method:POST Content-Type:application/x-www-form-urlencoded Referer:http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&a

qq聊天机器人 群发工具 (java版) (一)

这是最近因为感兴趣才写的小东西,网上大多是易语言版,java仅有的版本也偏老,老版webqq协议早失效了,所以现在我写了一个最新版本的.要实现群发和自动回复消息以及更多自定义功能,首先要实现登陆QQ,这边主要介绍一下如何分析QQ协议以及如何登陆. 我并没有使用很专业的抓包工具,事实上现在的浏览器一般都能查看到get,post请求的主要内容,而我们所需要的也就是请求的内容和地址,所以一个360浏览器或者google浏览器足够我们分析了. 首先分析流程,再讲方法.第一步登陆webqq的网站,我们会看

QQ聊天机器人 Delphi代码

QQ聊天机器人 前几日,看到杂志上有一篇关于开发QQ聊天机器人的文章.谈到了对QQ循环发送消息内容,感觉倒也很好玩,于是拿起Delphi开始了我的QQ聊天机器人之路. 首先要明白自己要做什么,大家都用过QQ,知道给别人发送消息的整个过程吧!要实现循环发送消息的功能该有以下几个条件: 1.必须是在聊天模式里进行.这样发送完一条消息后,QQ窗体还存在. 2.其次是要找到QQ文本窗体的句柄. 3.向QQ文本窗体中贴上你想说的话.然后自己点击发送按钮. 思路很简单,接着我们就要开始实施了. 首先要找到Q

QQ 聊天机器人API

QQ机器人是腾讯陆续推出的的人工智能聊天机器人的总称.都说小Q妹妹聪明好学,我们可以教她说话,也可以请他帮忙查询邮编.手机号,或者解释成语.翻译成语,据说她还会查询手机号码归属地.应用科学计算器. 可是,在查新闻.查列车.车航班.查团购.查价格.查优惠.查酒店.查餐厅.查彩票等方面,小Q妹妹就弱爆了,"逆水行舟,不进则退"小Q妹妹真应该被pass掉了.笔者已经开始使用一款功能更强的机器人--图灵机器人.试一下这个高智商的机器人,她永远有耐心陪您聊天,不怕你调戏她,就怕你被她调戏.点这里

C#制作简易QQ聊天机器人

最近对QQ聊天机器人比较感兴趣,奈何一直没找到C#的源码,就自己摸索,好了废话不多说了,开始正题. 首先我们要准备的是C# 的SDK下载地址:https://cqp.cc/t-24088-1-1,Newtonsoft.Json.dll插件 打开C#SDK源码后找到MyApp.cs(QQ发送消模块) 在里面找到QQ私聊消息 HttpWebResponse Response = null; string result = null; String _strMessage = msg(收到的QQ消息)

Android学习之智能聊天机器人(图灵机器人)

今天我们来分享一个有趣的应用:Android版的智能聊天机器人 开发工具:Eclipse 开发时间:2015/07/07 所用技术:图灵机器人API  网络通信之异步请求 接口回调  自定义Adapter 下面我将详细叙述开发的步骤: 第一步:申请图灵机器人的API KEY 方法很简单,只需要在图灵机器人API官网注册一个账号,注册成功之后,会显示一个API KEY 图灵机器人API 账号注册网址:图灵机器人 注册成功后,点击平台接入,认真看一下API接入的流程 第二步:开始创建工程进行编码,首

使用图灵机器人高速开发智能聊天机器人

聊天机器人如今已经成为一个流行的话题.不管微信公共帐号,还是qq聊天机器人,能够智能交互聊天的机器人帐号越来越多.相信非常多开发者也想自己实现这样一个好玩的智能聊天机器人. 以下就给广大的技术开发人员提供一个通过图灵机器人简单高速得实现这样一个智能聊天机器人的方法. 先看一下图灵机器人官方体验页的截图.相信大家会很感兴趣: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGFtY2hlbg==/font/5a6L5L2T/fontsize/400/fi

java qr二维条码生成器

原文:java qr二维条码生成器 代码下载地址:http://www.zuidaima.com/share/1550463250156544.htm qr二维码,不过是未加密的 标签: java 二维码 qr二维码话题: 文本解析和文件处理 脚本和工具 java qr二维条码生成器

仿QQ聊天软件2.0版

仿QQ聊天软件2.0版 转载请标明出处:牟尼的专栏 http://blog.csdn.net/u012027907     上次课设做了Java版的仿QQ聊天程序,这次软件实训,我们继续完善了仿QQ聊天程序,将上次未完成及不完善的地方进行完善和改进,还新加了部分功能:表情输入.气泡模式.文件传输.截屏.语音聊天.逐步向QQ的基本功能靠齐.通过这次软件实训,又有了很多收获. 一.设计内容及要求 1.1综述 A.系统概述 我们要做的就是类似QQ这样的面向企业内部的聊天软件,基本功能和QQ类似.首先,