本篇简单讲解一下如何接收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&id=2 Form-Data:r={"ptwebqq":"97b4ceaed7cc09c57e331db5785b7ee96253652a66f54ba1465176ac24b5d5dd","clientid":53999199,"psessionid":"8368046764001d636f6e6e7365727665725f77656271714031302e3133392e372e3136300000084800000c0c026e04003654298d6d0000000a403659485759383574506d00000028ac185599dd47fa9fbed98f818cf0219db1c21dc1b8d71c4309b1c1d60d1d5a6d99b14133835981f4","key":""}
post请求所带的数据参数前面都已经介绍过了,key默认为空就好。json字符串依旧要经过url编码。不过这个请求成功返回的时间不一定,不过最长也有一个时间限制。一般情况下若有消息发给你(或者刚登陆会收到离线消息),请求会立刻返回,但若一直没收到消息,腾讯服务器那边也会返回给你一个结果(一般是1分钟左右就返回)。所以,这个请求的延迟时间要设的长一点。下面附上我的代码:
// 获取QQ消息 收到消息就立刻再执行一次 public static String getQQMessage() throws Exception { // post 请求 DefaultHttpClient client = new DefaultHttpClient(); HttpPost postjson = new HttpPost("http://d.web2.qq.com/channel/poll2"); postjson.setHeader("Referer", "http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=2"); HttpClientParams.setCookiePolicy(client.getParams(), CookiePolicy.BROWSER_COMPATIBILITY); client.getParams().setParameter( CoreConnectionPNames.CONNECTION_TIMEOUT, 1000 * 300); client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 1000 * 300); StringEntity entity = new StringEntity(poll2Str); 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 code = String.valueOf(httpResponse.getStatusLine() .getStatusCode()); 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(); } return sb.toString(); }
这边我是单独做了一个线程接收消息,在登陆成功后发送一次这个post请求,在得到返回值后再次post这个请求,如此来维持登陆状态,并一直获取消息(webqq就是这样实现的)。下面简单分析一下几种返回格式:
1.1分钟内无消息,则返回以下数据:
{"retcode":102,"errmsg":""}
这样的话直接再post下一个请求就好。
2.好友消息
{"retcode":0,"result":[{"poll_type":"message","value":{"msg_id":27785,"from_uin":2208444277,"to_uin":2368295990,"msg_id2":538127,"msg_type":9,"reply_ip":178854715,"time":1433158432,"content":[["font",{"size":10,"color":"000000","style":[0,0,0],"name":"\u5FAE\u8F6F\u96C5\u9ED1"}],"123 "]}}]}
poll_type为消息类型,message为好友消息,group_message为群消息,sess_message为临时会话。同样的,我没去分析讨论组的消息类型,有兴趣的可以自己试试。
value内即为消息的基本信息。msg_id和msg_id2不知道有什么区别,不管不知道也不影响大局。from_uin为发送好友相对于你的uin,和你获取好友时他的uin一样,to_uin即是你自己的标识(QQ号),msg_type是哪几种类型我也不清楚,我一般也无视了,reply_ip应该是发送人的ip地址,不过处理过了,我不知道该如何解密。time即发送的说剑戳,content内即是msg的主要信息,同发送消息一样,提取出消息文字即可。
注:如果发送了表情消息,内容中会带上表情的格式 如[face],或自定义表情[cface],这个时候提取消息的过程会变的比较复杂,所以我在接收到带有图片的消息时都直接无视了。
3.群消息
{"retcode":0,"result":[{"poll_type":"group_message","value":{"msg_id":18042,"from_uin":2381142083,"to_uin":2368295990,"msg_id2":793507,"msg_type":43,"reply_ip":180064295,"group_code":478233785,"send_uin":2208444277,"seq":3615,"time":1433158906,"info_seq":189429357,"content":[["font",{"size":10,"color":"000000","style":[0,0,0],"name":"\u5FAE\u8F6F\u96C5\u9ED1"}],"123 "]}}]}
如之前所说,poll_type为group_message,代表群消息,from_uin和上篇提到的gid一样即群标识,to_uin依旧是自己的标识,send_uin即发送人的uin,即群内成员相对于你的uin,和上篇介绍的获取群成员的uin一样。消息内容的格式同好友消息一致。
4.临时会话消息
{"retcode":0,"result":[{"poll_type":"sess_message","value":{"msg_id":2329,"from_uin":3921021009,"to_uin":2368295990,"msg_id2":62551,"msg_type":140,"reply_ip":180061935,"time":1433159288,"id":2381142083,"ruin":3277086849,"service_type":0,"flags":{"text":1,"pic":1,"file":1,"audio":1,"video":1},"content":[["font",{"size":9,"color":"000000","style":[0,0,0],"name":"\u5FAE\u8F6F\u96C5\u9ED1"}],"123 "]}}]}
from_uin为这个陌生人相对于你的标识,其他参数没什么区别了。
前几天我也仔细看过关于聊天机器人的实现方式。事实上真正的智能聊天机器人(能学习,会成长)实现难度太大了。现在的QQ聊天机器人一般都是设定关键字和回复内容,在消息内容中出现指定字段匹配上了即发送设定好的回复内容,这样的机器人实在是无趣,太僵硬了。不过,若是只做一个客服机器人,那么还是挺合适的。用以上方法接收消息,回复制定内容给客户即可,也不需要多高的智商,回答内容自己设定好即可。
今天又看了下各种免费的API,在百度API开放接口上看到了图灵机器人的API。相对我们自己设计而言算不错了,词库也比较强大(毕竟每个人教它的内容,都入了同一个库,而我们调用的也是同一个库)。不仅能进行简单的聊天,也提供了很多其他功能,所以如果觉得自己设计麻烦,可以把程序当成一个中转站,在接收到消息内容后,调用图灵机器人的API,再将返回的数据发送回对象即可。(不过图灵机器人API返回的格式并不是固定的,因为功能比较强大,会有很多种类型的返回结果,我也不太懂它的API,所以我不知道该如何去控制返回结果,结果处理起来比较麻烦)