webqq2协议分析和qq聊天机器人简单实现

webqq2协议分析和qq聊天机器人简单实现

通过webqq接口,可以实现发送qq消息接收qq消息等,这样,想实现一个qq聊天机器人,就不是什么难事情了了,下面开始一步步做。


1。首先调用http://ptlogin2.qq.com/check?appid=1003903&uin=qq号码,来获取该qq号码验证码之类的信息。看返回结果决定是不是要输入验证码登陆。
如果返回:ptui_checkVC('1','95ab7db15e5ab17f50f25d33 598259e83ccc098c4af2f8a4 ');需要输入验证码,这里需要记住这个长字符串(获取验证码图片用)以及cookie
如果返回:ptui_checkVC('0','!MPG');不需要输入验证码,验证码值用!MPG代替。可能为其他字符串,但是以感叹号开头
如果需要输入验证码:则调用
http://captcha.qq.com/getimage?aid=1003903&&uin=qq号码&vc_type=95ab7db15e5ab17f50f25d33 598259e83ccc098c4af2f8a4
获取验证码图片。。。
2。开始登陆,在登陆之前,需要将密码加密,tx的加密方法很复杂,不过还好,弄到了他的js文件,然后通过java的ScriptEnginee来执行这个js来获取加密后的字符串。。。
代码:
Java代码   收藏代码

      ScriptEngineManager m = new ScriptEngineManager();  
      ScriptEngine se = m.getEngineByName("javascript");  
      se.eval_r(new FileReader(new File("1.js")));  
      Object t = se.eval_r("md5(md5_3(""+p+"")+""+code.toUpperCase()+"");");  
      return t.toString();  

 

现在调用登陆接口,以获得相关的cookie。注意Referer。这个一定得加上,否则不成功:Referer : http://web2-b.qq.com/proxy.html
http://ptlogin2.qq.com/login?u=qq号码&p=密码和验证码加密后的字符串&verifycode=验证码&remember_uin=1&aid=1003903&u1=http://web2.qq.com/loginproxy.html?strong%

3Dtrue&h=1&ptredirect=0&ptlang=2052&from_ui=1&pttype=1&dumy=&fp=loginerroralert

登陆成功后,要记住返回的cookie值。
如其中ptwebqq,skey等。

3。这还没有完成,还需要再次登录,这个好像就是qq聊天接口登陆了(刚才的登陆可以理解为登陆qq网站),只有这次登陆,才算真正登陆qq,这个时候,如果你qq已经登陆,会把你的qq踢下线,而且此次登陆才算上线时间。
地址:http://web2-b.qq.com/channel/login,把一个数据结构post给它就够了
r={"status":"","ptwebqq":"{1}","passwd_sig":"","clientid":"{2}"}
其中{1}是ptwebqq,在第2步登陆后cookie返回的,{2}clientId,自己随便定义一个数字吧。

如果成功:
会返回一个json数据结构:
{"retcode":0,"result":

{"uin":qq号码,"mode":"master","index":1055,"port":38138,"status":"online","vfwebqq":"f72a8722c988252aef4e0268 f1d26a3d647f06f6ff353a5c 6cdaaa49abb2fcdf0cee2d8d 64373ac2","psessionid":"

8368046764001D636F6E6E73 65727665725F776562717140 31302E3133332E332E323430 0000235100000B79026E0400 43F60C166D0000000A404746 365677767041316D00000028 F72A8722C988252AEF4E0268 F1D26A3D647F06F6

FF353A5C6CDAAA49ABB2FCDF 0CEE2D8D64373AC2"}}
记住其中的psessionid。后面在发送消息和获取qq消息都需要这个参数。

4。发送一个qq消息给好友
地址:http://web2-b.qq.com/channel/send_msg
同样是post:r={"to":qq号码,"face":0,"content":"["23",["font",{"name":"宋体","size":"10","style":

[0,0,0],"color":"000000

"}]]","msg_id":7780001,"clientid":"15778909","psessionid":"8368046764001D636F6E6E73 65727665725F776562717140 31302E3133332E332E323430 0000326F00000B71026E0400 43F60C166D0000000A404272 5946

34574676716D00000028E7D8 E44718236B0C17365E824FD3 817ED2EF6C879FEE88D07EA9 2D030CEA72EE8E5930986312 8A3E"}
{"retcode":0,"result":"ok"}
需要把这个json UrlEncode一下再发送,否则会返回错误。

发送成功返回:{"retcode":0,"result":"ok"}

5。循环获取消息接口:
通过这个接口你可以实时的不间断的获取最新的消息。
http://web2-b.qq.com/channel/poll?

clientid=15778909&psessionid=8368046764001D636F6E6E73 65727665725F776562717140 31302E3133332E332E323430 0000326F00000B71026E0400 43F60C166D0000000A404272 594634574676716D00000028 E7D8E447182

36B0C17365E824FD3817ED2E F6C879FEE88D07EA92D030CE A72EE8E59309863128A3E&t=1288591644319

返回格式:
{"retcode":0,"result":[{"poll_type":"message","value":{"msg_id":9712,"from_uin":qq号码,"to_uin":qq号码,"msg_id2":217523,"msg_type":9,"reply_ip":2887452740,"time":1288591740,"content":[["font",{"size":9,"color":"000000","style":

[0,0,0],"name":"\u5B8B\u4F53"}],"hello world"],"raw_content":"hello world"}}]}
其中的poll_type表示消息格式,message就是普通的qq消息,可以看到发送人,发送时间,以及消息的内容等。
此接口很特殊,在实现时,需要循环不间断调用,如果没有消息返回,该接口会一直等待到,有消息,读取完后要立即再调用该接口。



6.其他接口
获取头像
http://face7.qun.qq.com/cgi/svr/face/getface?cache=0&type=1&fid=0&uin=号码

获取个人信息
http://web2-b.qq.com/api/get_single_info?tuin=qq号码
获取签名
http://web2-b.qq.com/api/get_single_long_nick?tuin=qq号码&t=1288751545148
获取好友列表
http://web2-b.qq.com/api/get_user_friends
r      {"vfwebqq":"8f1383ba2239bb7295b100af 215274aff1ee4be177b467cb c386fc53ff6606a8e5941aca 61d0eb51"}
获取在线的qq好友
http://web2-b.qq.com/channel/get_online_buddies?clientid=9547083&psessionid=8368046764001D636F6E6E73 65727665725F776562717140 31302E3133332E332E323430 000062F000000B86026E0400 43F60C166D0000000A404F52 6B7558357668476D00000028 8F1383BA2239BB7295B100AF 215274AFF1EE4BE177B467CB C386FC53FF6606A8E5941ACA 61D0EB51&t=1288751548600
获取最近联系人
http://web2-b.qq.com/api/get_recent_contact
r      {"vfwebqq":"8f1383ba2239bb7295b100af 215274aff1ee4be177b467cb c386fc53ff6606a8e5941aca 61d0eb51"}


等等。。。

7.附件这是本人通过java写的一个实例客户端,启动后,处于接受qq消息状态,当收到好友发来的消息时,回返回"然后呢?"。。。。
类似qq聊天机器人吧。。。
1.js是qq密码的加密js文件。

。。

 

完整代码:
Java代码   收藏代码

      import java.awt.image.BufferedImage;  
      import java.io.BufferedReader;  
      import java.io.File;  
      import java.io.FileReader;  
      import java.io.InputStream;  
      import java.io.InputStreamReader;  
      import java.net.HttpURLConnection;  
      import java.net.URL;  
      import java.net.URLEncoder;  
      import java.util.Date;  
      import java.util.Random;  
      import java.util.regex.Matcher;  
      import java.util.regex.Pattern;  
         
      import javax.imageio.ImageIO;  
      import javax.script.ScriptEngine;  
      import javax.script.ScriptEngineManager;  
         
      import atg.taglib.json.util.JSONArray;  
      import atg.taglib.json.util.JSONException;  
      import atg.taglib.json.util.JSONObject;  
         
         
      public class QQClient {  
         
            private int qq = -1;  
            private String pwd = null;  
               
            private int clientid = 66933334;//这个可以随便写  
            private String psessionid = "";  
               
            private String ptwebqq;  
            private String vfwebqq;  
               
            private String skey;  
               
            private String refer = "http://web2-b.qq.com/proxy.html";  
               
            private String cookie = "";  
            //读取消息线程  
            private boolean isrun = false;  
            private Thread poolThread =new PollThread();  
            public Thread getPoolThread() {  
                  return poolThread;  
            }  
             
            private void log(String msg){  
                  System.out.println(new Date().toLocaleString()+":"+msg);  
            }  
               
               
            public QQClient(int qq, String pwd) {    
                  this.qq = qq;  
                  this.pwd = pwd;  
                  try {  
                        boolean rs = checkAndLogin();  
                        if(rs){    
                              isrun = true;  
                              poolThread.start();//开始循环接收  
                              log("启动成功");  
                        }  
                  } catch (Exception e) {    
                        e.printStackTrace();  
                  }  
            }  
             
            //测试  
            public static void main(String[] args) throws Exception{  
                  QQClient q = new QQClient(qq号码, "123");    
                  q.getPoolThread().join();  
            }  
               
             
             
            public boolean sendMsg(int toQQ, String message){  
                  try {  
                        JSONObject json = new JSONObject();  
                        json.put("to", toQQ);//要发送的人  
                        json.put("face", 0);  
                           
                        JSONArray msg = new JSONArray();  
                        msg.add(message);  
                        JSONArray font = new JSONArray();  
                        font.add("font");  
                           
                        JSONObject font1 = new JSONObject().put("name", "宋体").put("size", "10");  
                           
                        JSONArray style = new JSONArray();  
                        style.add(0);  
                        style.add(0);  
                        style.add(0);             
                        font1.put("style", style);  
                        font1.put("color", "000000");  
                           
                        font.add(font1);          
                        msg.add(font);  
                           
                        json.put("content", msg.toString());  
                        json.put("msg_id", new Random().nextInt(10000000));  
                        json.put("clientid", clientid);  
                        json.put("psessionid", psessionid);//需要这个才能发送  
                        String sendMsgUrl = "http://web2-b.qq.com/channel/send_msg";  
                        String content = json.toString();  
                            
                        content = URLEncoder.encode(content);//他要需要编码  
                        content ="r="+content;  
                        //发送  
                        String res = postUrl(sendMsgUrl, content);  
                        //不出意外,这是返回结果:{"retcode":0,"result":"ok"}  
                        JSONObject rh = new JSONObject(res);  
                        if("ok".equals(rh.getString("result"))){  
                              return true;  
                        }    
                  } catch (JSONException e) {    
                        e.printStackTrace();  
                  }  
                     
                  return false;  
            }  
               
             
            private boolean checkAndLogin() throws Exception{  
                  if(qq == -1 || pwd == null)  
                        throw new IllegalArgumentException ("qq和密码不能为空");  
                  String checkIdUrl = "http://ptlogin2.qq.com/check?appid=1003903&uin="+qq;  
                  String res = getUrl(checkIdUrl);  
                  //ptui_checkVC('0','!ZLE');返回这个就不需要获取验证码了。验证码就是!ZLE    
                  //ptui_checkVC('1','95ab7db15e5ab17f50f25d33 598259e83ccc098c4af2f8a4 ');这个长字符串就需要使用了  
                  Pattern p = Pattern. compile("\\,\\'([!\\w]+)\\'");  
                  Matcher m = p. matcher(res);  
                  String checkType = "";  
                  if(m.find()){  
                        checkType = m.group(1);    
                  }  
                  String check = "";    
                  if(!checkType.startsWith("!")){  
                        //需要输入验证码  
                        String getCheckImageUrl = "http://captcha.qq.com/getimage?aid=1003903&uin="+qq+"&vc_type="+checkType;  
                        String file = readCheckImage(getCheckImageUrl);  
                        log("请打开"+file+",并且在这里输入其中的字符串,然后回车:");  
                        InputStreamReader ins = new InputStreamReader(System.in);  
                        BufferedReader br = new BufferedReader(ins);  
                        check = br.readLine();     
                  }else{  
                        //不需要输入验证码  
                        check = checkType;  
                  }  
                     
                  //开始登陆  
                  String loginUrl = "http://ptlogin2.qq.com/login?u="+qq+"&" +  
                              "p=" +mdP(pwd, check)+  
                              "&verifycode="+check+"&remember_uin=1&aid=1003903" +  
                              "&u1=http://web2.qq.com/loginproxy.html?strong=true" +  
                              "&h=1&ptredirect=0&ptlang=2052&from_ui=1&pttype=1&dumy=&fp=loginerroralert";  
                  res = getUrl(loginUrl);  
      //         ptuiCB('0','0','http://web2.qq.com/loginproxy.html?strong=true','0','登录成功!');  
      //         ptuiCB('4','0','','0','您输入的验证码有误,请重试。');  
                
                  p = Pattern.compile("登录成功!");//提取最后一个字符串,看看是不是 登录成功!  
                  m = p. matcher(res);  
                  if(m.find()){  
                        log("登陆成功");    
                  }else{  
                        //登陆失败  
                        log(checkType);  
                        return false;  
                  }  
                  //从cookie中提取ptwebqq,skey  
                  p = Pattern.compile("ptwebqq=(\\w+);");  
                  m = p.matcher(cookie);  
                  if(m.find()){  
                        ptwebqq = m.group(1);  
                  }  
                  p = Pattern.compile("skey=(@\\w+);");  
                  m = p.matcher(cookie);  
                  if(m.find()){  
                        skey = m.group(1);  
                  }  
                  log("ptwebqq="+ptwebqq+",skey="+skey);  
                     
                  //再次登陆,只有这次登陆,才算真正登陆qq,这个时候,如果你qq已经登陆,会把你的qq踢下线,而且此次登陆才算上线。  
                  String channelLoginUrl = "http://web2-b.qq.com/channel/login";  
                  String content = "{"status":"","ptwebqq":""+ptwebqq+"","passwd_sig":"","clientid":""+clientid+""}";  
                  content = URLEncoder.encode(content);//urlencode    
                  content = "r="+content;//post的数据  
                  res = postUrl(channelLoginUrl, content);//post  
                  //这次登陆基本上不会发生什么问题  
                  //下面提取很重要的2个数据psessionid ,vwebqq,通用采用正则表达式,虽然结果是个json  
                  p = Pattern.compile(""vfwebqq":"(\\w+)"");  
                  m = p.matcher(res);  
                  if(m.find()){  
                        vfwebqq = m.group(1);  
                  }  
                  p = Pattern.compile(""psessionid":"(\\w+)"");  
                  m = p.matcher(res);  
                  if(m.find()){  
                        psessionid = m.group(1);  
                  }  
                  log("vwebqq="+vfwebqq+","+"psessionid="+psessionid);  
                  //到此,登陆就算完成了,后面可以调用发送qq信息等接口了             
                    return true;  
            }  
               
         
               
               
             
            public   String mdP(String p, String code){  
                  try {  
                        ScriptEngineManager m = new ScriptEngineManager();  
                        ScriptEngine se = m.getEngineByName("javascript");  
                        se.eval_r(new FileReader(new File("1.js")));  
                        Object t = se.eval_r("md5(md5_3(""+p+"")+""+code.toUpperCase()+"");");  
                        return t.toString();  
                  }catch (Exception e) {  
                        e.printStackTrace();  
                  }    
                  return null;  
            }  
             
            private   String postUrl(String url, String contents){  
                  try{    
                        System.out.println("post>>>"+url);  
                            
                        URL serverUrl = new URL(url);  
                        HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();    
                        conn.setRequestMethod("POST");//"POST" ,"GET"    
                         
                        if(refer != null){  
                              conn.addRequestProperty("Referer", refer);  
                        }  
                        conn.addRequestProperty("Cookie", cookie);  
                        conn.addRequestProperty("Accept-Charset", "UTF-8;");//GB2312,  
                        conn.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Firefox/3.6.8");  
                        conn.setDoOutput(true);    
                        conn.connect();  
                           
                        conn.getOutputStream().write(contents.getBytes());  
                           
                        if(conn.getHeaderFields().get("Set-Cookie") != null){  
                              for(String s:conn.getHeaderFields().get("Set-Cookie")){  
                                    cookie += s;  
                              }  
                        }  
                           
                        InputStream ins =   conn.getInputStream();  
                           
                        String charset = "UTF-8";    
                        InputStreamReader inr = new InputStreamReader(ins, charset);  
                        BufferedReader bfr = new BufferedReader(inr);  
                         
                        String line = "";  
                        StringBuffer res = new StringBuffer();    
                        do{  
                              res.append(line);  
                              line = bfr.readLine();  
                             //System.out.println(line);  
                        }while(line != null);  
                        
                        System.out.println(">>>==="+res);  
                           
                        return res.toString();  
                  }catch(Exception e){  
                        e.printStackTrace();  
                        return null;  
                  }  
            }  
               
               
             
            private   String getUrl(String url){  
                  try{    
                        System.out.println("get>>>"+url);  
                            
                        URL serverUrl = new URL(url);  
                        HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();    
                        conn.setRequestMethod("GET");//"POST" ,"GET"  
                       // conn.setDoOutput(true);    
                        if(refer != null){  
                              conn.addRequestProperty("Referer", refer);  
                        }  
                        conn.addRequestProperty("Cookie", cookie);  
                        conn.addRequestProperty("Accept-Charset", "UTF-8;");//GB2312,  
                        conn.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Firefox/3.6.8");  
                        conn.connect();  
                         
                        if(conn.getHeaderFields().get("Set-Cookie") != null){  
                              for(String s:conn.getHeaderFields().get("Set-Cookie")){  
                                    cookie += s;  
                              }  
                        }  
                        InputStream ins =   conn.getInputStream();  
                           
                        String charset = "UTF-8";    
                        InputStreamReader inr = new InputStreamReader(ins, charset);  
                        BufferedReader bfr = new BufferedReader(inr);  
                         
                        String line = "";  
                        StringBuffer res = new StringBuffer();    
                        do{  
                              res.append(line);  
                              line = bfr.readLine();  
                             //System.out.println(line);  
                        }while(line != null);  
                        
                        System.out.println(">>>==="+res);  
                           
                        return res.toString();  
                  }catch(Exception e){  
                        e.printStackTrace();  
                        return null;  
                  }  
            }  
               
             
            private String readCheckImage(String url){  
                  try{    
                        System.out.println("get>>>"+url);  
                      
                        URL serverUrl = new URL(url);  
                        HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();    
                        conn.setRequestMethod("GET");//"POST" ,"GET"    
                           
                        conn.addRequestProperty("Accept-Charset", "UTF-8;");//GB2312,  
                        conn.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Firefox/3.6.8");  
                        conn.connect();  
                        //返回的cookie  
                        if(conn.getHeaderFields().get("Set-Cookie") != null)  
                              for(String s:conn.getHeaderFields().get("Set-Cookie")){  
                                    cookie += s;  
                              }  
                           
                        InputStream ins =   conn.getInputStream();  
                           
                        BufferedImage bi = ImageIO.read(ins);  
                        File f =new File("qqimg.jpg");  
                        ImageIO.write(bi, "jpg", f);  
                           
                        return f.getAbsolutePath();  
                  }catch(Exception e){  
                        e.printStackTrace();    
                  }    
                  return null;  
            }  
               
             
            public void receiveMsg(String message, int fromQQ){  
                  log("qq:"+fromQQ+"说:"+message);  
                  //test  
                  sendMsg(fromQQ, "然后呢?");  
            }  
               
             
            class PollThread extends Thread{  
                     
                  private String pollUrl = "http://web2-b.qq.com/channel/poll";  
                  @Override  
                  public void run() {    
                        String url = pollUrl+ "?clientid="+clientid+"&psessionid="+psessionid;    
                           
                        try {  
                              while(isrun){  
                                    //线程一直等待知道服务器有返回数据  
                                    String res = getUrl(url);  
                                       
                                    JSONObject retJ = new JSONObject(res);  
                                    if(retJ.getInt("retcode") == 0){  
                                          JSONArray result = retJ.getJSONArray("result");  
                                          String poll_type = result.getJSONObject(0).getString("poll_type");  
                                          if("message".equals(poll_type)){  
                                                //说明有人发qq消息给我,                                         
                                                String raw_content = result.getJSONObject(0).getJSONObject("value").get("raw_content").toString();    
                                                int from_uin = result.getJSONObject(0).getJSONObject("value").getInt("from_uin");  
                                                log("收到来自:"+from_uin+":"+raw_content);  
                                                //通知客户端收到了  
                                                receiveMsg(raw_content, from_uin);  
                                          }  
                                          //system_message 是系统消息  
                                    }  
                              }  
                        } catch (JSONException e) {    
                              e.printStackTrace();  
                        }  
                  }  
                     
            }  
         
               
      }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值