广告位,联系QQ:910488011
当前位置: 首页 > Q协分析 > webqq2协议分析和qq聊天机器人简单实现(3)
Q协分析
webqq2协议分析和qq聊天机器人简单实现(3)
作者: admin  时间: 2012-05-10  点击: 4713
125. /**
126. * 检查并且登陆
127. */
128. private boolean checkAndLogin() throws Exception{
129. if(qq == -1 || pwd == null)
130. throw new IllegalArgumentException("qq和密码不能为空");
131. String checkIdUrl = "http://ptlogin2.qq.com/check?appid=1003903&uin="+qq;
132. String res = getUrl(checkIdUrl);
133. //ptui_checkVC('0','!ZLE');返回这个就不需要获取验证码了。验证码就是!ZLE
134. //ptui_checkVC('1','95ab7db15e5ab17f50f25d33598259e83ccc098c4af2f8a4');这个长字符串就需要使用了
135. Pattern p = Pattern. compile("\\,\\'([!\\w]+)\\'");
136. Matcher m = p. matcher(res);
137. String checkType = "";
138. if(m.find()){
139. checkType = m.group(1);
140. }
141. String check = "";
142. if(!checkType.startsWith("!")){
143. //需要输入验证码
144. String getCheckImageUrl = "http://captcha.qq.com/getimage?aid=1003903&uin="+qq+"&vc_type="+checkType;
145. String file = readCheckImage(getCheckImageUrl);
146. log("请打开"+file+",并且在这里输入其中的字符串,然后回车:");
147. InputStreamReader ins = new InputStreamReader(System.in);
148. BufferedReader br = new BufferedReader(ins);
149. check = br.readLine();
150. }else{
151. //不需要输入验证码
152. check = checkType;
153. }
154.
155. //开始登陆
156. String loginUrl = "http://ptlogin2.qq.com/login?u="+qq+"&" +
157. "p=" +mdP(pwd, check)+
158. "&verifycode="+check+"&remember_uin=1&aid=1003903" +
159. "&u1=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html%3Fstrong%3Dtrue" +
160. "&h=1&ptredirect=0&ptlang=2052&from_ui=1&pttype=1&dumy=&fp=loginerroralert";
161. res = getUrl(loginUrl);
162. // ptuiCB('0','0','http://web2.qq.com/loginproxy.html?strong=true','0','登录成功!');
163. // ptuiCB('4','0','','0','您输入的验证码有误,请重试。');
164.
165. p = Pattern.compile("登录成功!");//提取最后一个字符串,看看是不是 登录成功!
166. m = p. matcher(res);
167. if(m.find()){
168. log("登陆成功");
169. }else{
170. //登陆失败
171. log(checkType);
172. return false;
173. }
174. //从cookie中提取ptwebqq,skey
175. p = Pattern.compile("ptwebqq=(\\w+);");
176. m = p.matcher(cookie);
177. if(m.find()){
178. ptwebqq = m.group(1);
179. }
180. p = Pattern.compile("skey=(@\\w+);");
181. m = p.matcher(cookie);
182. if(m.find()){
183. skey = m.group(1);
184. }
185. log("ptwebqq="+ptwebqq+",skey="+skey);
186.
187. //再次登陆,只有这次登陆,才算真正登陆qq,这个时候,如果你qq已经登陆,会把你的qq踢下线,而且此次登陆才算上线。
188. String channelLoginUrl = "http://web2-b.qq.com/channel/login";
189. String content = "{\"status\":\"\",\"ptwebqq\":\""+ptwebqq+"\",\"passwd_sig\":\"\",\"clientid\":\""+clientid+"\"}";
190. content = URLEncoder.encode(content);//urlencode
191. content = "r="+content;//post的数据
192. res = postUrl(channelLoginUrl, content);//post
193. //这次登陆基本上不会发生什么问题
194. //下面提取很重要的2个数据psessionid ,vwebqq,通用采用正则表达式,虽然结果是个json
195. p = Pattern.compile("\"vfwebqq\":\"(\\w+)\"");
196. m = p.matcher(res);
197. if(m.find()){
198. vfwebqq = m.group(1);
199. }
200. p = Pattern.compile("\"psessionid\":\"(\\w+)\"");
201. m = p.matcher(res);
202. if(m.find()){
203. psessionid = m.group(1);
204. }
205. log("vwebqq="+vfwebqq+","+"psessionid="+psessionid);
206. //到此,登陆就算完成了,后面可以调用发送qq信息等接口了
207. return true;
208. }
209.
210.
211.
212.
213. /**
214. * 调用tx的js来生成密钥
215. */
216. public String mdP(String p, String code){
217. try {
218. ScriptEngineManager m = new ScriptEngineManager();
219. ScriptEngine se = m.getEngineByName("javascript");
220. se.eval(new FileReader(new File("1.js")));
221. Object t = se.eval("md5(md5_3(\""+p+"\")+\""+code.toUpperCase()+"\");");
222. return t.toString();
223. }catch (Exception e) {
224. e.printStackTrace();
225. }
226. return null;
227. }
228. /**
229. * POST一个url,contents是输入的内容
230. */
231. private String postUrl(String url, String contents){
232. try{
233. System.out.println("post>>>"+url);
234.
235. URL serverUrl = new URL(url);
236. HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();
237. conn.setRequestMethod("POST");//"POST" ,"GET"
238.
239. if(refer != null){
240. conn.addRequestProperty("Referer", refer);
241. }
242. conn.addRequestProperty("Cookie", cookie);
243. conn.addRequestProperty("Accept-Charset", "UTF-8;");//GB2312,
244. conn.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Firefox/3.6.8");
245. conn.setDoOutput(true);
246. conn.connect();
247.
248. conn.getOutputStream().write(contents.getBytes());
249.
250. if(conn.getHeaderFields().get("Set-Cookie") != null){
251. for(String s:conn.getHeaderFields().get("Set-Cookie")){
252. cookie += s;
253. }
254. }
255.
256. InputStream ins = conn.getInputStream();
257.
258. String charset = "UTF-8";
259. InputStreamReader inr = new InputStreamReader(ins, charset);
260. BufferedReader bfr = new BufferedReader(inr);
261.
262. String line = "";
263. StringBuffer res = new StringBuffer();
264. do{
265. res.append(line);
266. line = bfr.readLine();
267. //System.out.println(line);
268. }while(line != null);
269.
270. System.out.println(">>>==="+res);
271.
272. return res.toString();
273. }catch(Exception e){
274. e.printStackTrace();
275. return null;
276. }
277. }
278.
279.
280. /**
281. * GET 一个url
282. */
283. private String getUrl(String url){
284. try{
285. System.out.println("get>>>"+url);
286.
287. URL serverUrl = new URL(url);
288. HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();
289. conn.setRequestMethod("GET");//"POST" ,"GET"
290. // conn.setDoOutput(true);
291. if(refer != null){
292. conn.addRequestProperty("Referer", refer);
293. }
294. conn.addRequestProperty("Cookie", cookie);
295. conn.addRequestProperty("Accept-Charset", "UTF-8;");//GB2312,
296. conn.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Firefox/3.6.8");
297. conn.connect();
298.
299. if(conn.getHeaderFields().get("Set-Cookie") != null){
300. for(String s:conn.getHeaderFields().get("Set-Cookie")){
301. cookie += s;
302. }
303. }
304. InputStream ins = conn.getInputStream();
305.
306. String charset = "UTF-8";
307. InputStreamReader inr = new InputStreamReader(ins, charset);
308. BufferedReader bfr = new BufferedReader(inr);
309.
310. String line = "";
311. StringBuffer res = new StringBuffer();
312. do{
313. res.append(line);
314. line = bfr.readLine();
315. //System.out.println(line);
316. }while(line != null);
317.
318. System.out.println(">>>==="+res);
319.
320. return res.toString();
321. }catch(Exception e){
322. e.printStackTrace();
323. return null;
324. }
325. }
326.
327. /**
328. * 读取验证码。返回验证码文件保存的路径
329. */
330. private String readCheckImage(String url){
331. try{
332. System.out.println("get>>>"+url);
333.
334. URL serverUrl = new URL(url);
335. HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();
336. conn.setRequestMethod("GET");//"POST" ,"GET"
337.
338. conn.addRequestProperty("Accept-Charset", "UTF-8;");//GB2312,
339. conn.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Firefox/3.6.8");
340. conn.connect();
341. //返回的cookie
342. if(conn.getHeaderFields().get("Set-Cookie") != null)
343. for(String s:conn.getHeaderFields().get("Set-Cookie")){
344. cookie += s;
345. }
346.
347. InputStream ins = conn.getInputStream();
348.
349. BufferedImage bi = ImageIO.read(ins);
350. File f =new File("qqimg.jpg");
351. ImageIO.write(bi, "jpg", f);
352.
353. return f.getAbsolutePath();
354. }catch(Exception e){
355. e.printStackTrace();
356. }
357. return null;
358. }
359.
360. /**
361. * 当有qq消息是回调此函数
362. */
363. public void receiveMsg(String message, int fromQQ){
364. log("qq:"+fromQQ+"说:"+message);
365. //test
366. sendMsg(fromQQ, "然后呢?");
367. }
368.
369. /**
370. * 通过poll一直等待服务器回应。比如收到消息啊,好友上线啊,申请好友啊之类的各类消息都会通过此接口返回,在获得数据后,应该继续poll获取下个数据
371. * http://web2-b.qq.com/channel/poll
372. */
373. class PollThread extends Thread{
374.
375. private String pollUrl = "http://web2-b.qq.com/channel/poll";
376. @Override
377. public void run() {
378. String url = pollUrl+ "?clientid="+clientid+"&psessionid="+psessionid;
379.
380. try {
381. while(isrun){
382. //线程一直等待知道服务器有返回数据
383. String res = getUrl(url);
384.
385. JSONObject retJ = new JSONObject(res);
386. if(retJ.getInt("retcode") == 0){
387. JSONArray result = retJ.getJSONArray("result");
388. String poll_type = result.getJSONObject(0).getString("poll_type");
389. if("message".equals(poll_type)){
390. //说明有人发qq消息给我,
391. String raw_content = result.getJSONObject(0).getJSONObject("value").get("raw_content").toString();
392. int from_uin = result.getJSONObject(0).getJSONObject("value").getInt("from_uin");
393. log("收到来自:"+from_uin+":"+raw_content);
394. //通知客户端收到了
395. receiveMsg(raw_content, from_uin);
396. }
397. //system_message 是系统消息
398. }
399. }
400. } catch (JSONException e) {
401. e.printStackTrace();
402. }
403. }
404.
405. }
406.
407.
408. }