您的位置:首页 > 其它

iQQ 学习笔记2 :借助新浪微博输入验证码、远程控制退出

2013-06-01 21:21 411 查看
iQQ 学习笔记声明
本文仅供学习研究使用,不得用于任何非法及侵权用途。

转贴请注明原发位置:
http://xuekaiyuan.com/forum.php?mod=viewthread&tid=5

讨论请加QQ群:306320259

iQQ 学习笔记2说明 :借助新浪微博输入验证码、远程控制退出

在第1个案例中实现了iQQ的登录、验证码和收消息,其中有两处需要人工参与,第一处是需要打开验证码图片,然后输入验证码,第二处是退出程序需要强制退出。验证码暂时还不能自动识别,不过可以改进交互方式,本例中将借助新浪微博实现显示验证码图片和输入验证码。退出程序改成收到QQ消息后按消息内容操作。

iQQ 学习笔记2程序 :借助新浪微博输入验证码、远程控制退出

这是主程序,其中的username常量的值应替换为QQ号,password常量的值应替换为该QQ号对应的QQ密码。

package test_2;

import java.util.logging.Logger;

import iqq.im.QQClient;
import iqq.im.QQException;
import iqq.im.QQNotifyListener;
import iqq.im.WebQQClient;
import iqq.im.actor.ThreadActorDispatcher;
import iqq.im.bean.QQMsg;
import iqq.im.bean.QQStatus;
import iqq.im.bean.content.ContentItem;
import iqq.im.bean.content.TextItem;
import iqq.im.event.QQActionEvent;
import iqq.im.event.QQActionFuture;
import iqq.im.event.QQNotifyEvent;
import iqq.im.event.QQNotifyEventArgs;
import iqq.im.event.QQActionEvent.Type;

public class Test_2 {
private static final String username = "**********";
private static final String password = "**********";
private static final Logger logger = java.util.logging.Logger.getLogger("");
private static QQClient client;
public static void main(String[] args) {
client = new WebQQClient(username, password, new QQNotifyListener() {
@Override
public void onNotifyEvent(QQNotifyEvent event) {
if (event.getType() == QQNotifyEvent.Type.CHAT_MSG) {
if (event.getTarget() instanceof QQMsg) {
QQMsg msg = (QQMsg) event.getTarget();
for (ContentItem contentItem : msg.getContentList()) {
if (contentItem instanceof TextItem) {
TextItem textItem = (TextItem) contentItem;
logger.info(textItem.getContent());
if (textItem.getContent().startsWith("logout ")) {
client.logout(null);
}
}
}
}
} else if (event.getType() == QQNotifyEvent.Type.CAPACHA_VERIFY) {
if (event.getTarget() instanceof QQNotifyEventArgs.ImageVerify) {
QQNotifyEventArgs.ImageVerify imageVerify = (QQNotifyEventArgs.ImageVerify) event.getTarget();
String code = ImageVerifyQuestioners.ImageVeiryQuestion(imageVerify);
client.submitVerify(code, event);
} else {
logger.info(event.getTarget().getClass().getName());
}
} else {
logger.info("TODO QQNotifyEvent: " + event.getType() + ", " + event.getTarget());
}
}
}, new ThreadActorDispatcher());
QQActionFuture future = client.login(QQStatus.ONLINE, null);
try {
QQActionEvent event = future.waitFinalEvent();
if (event.getType() == Type.EVT_OK) {
client.beginPollMsg();
}
} catch (QQException e) {
e.printStackTrace();
}
}
}


为了便于实现多种图片验证码的输入方式,设计一个图片验证码接口。

package test_2;

import iqq.im.event.QQNotifyEventArgs.ImageVerify;

public abstract class ImageVerifyQuestioner {
private ImageVerify imageVerify;
private String Code;
public ImageVerifyQuestioner(ImageVerify imageVerify) {
this.imageVerify = imageVerify;
this.Code = "";
}
protected final ImageVerify getImageVerify() {
return imageVerify;
}
public final String getCode() {
return Code;
}
protected final void setCode(String code) {
Code = code;
}
public abstract void loop ();
}


通过一个调度程序管理多种图片验证码的输入方式,当一种输入方式获取验证码时,其他输入方式退出。

package test_2;

import java.util.ArrayList;
import java.util.List;

import iqq.im.event.QQNotifyEventArgs.ImageVerify;

public class ImageVerifyQuestioners {
public static String ImageVeiryQuestion (ImageVerify imageVerify) {
String code = "";
List<ImageVerifyQuestioner> imageVerifyQuestionerList = new ArrayList<ImageVerifyQuestioner>();
imageVerifyQuestionerList.add(new ImageVerifyConsoleQuestioner(imageVerify));
imageVerifyQuestionerList.add(new ImageVerifyWeiboQuestioner(imageVerify));
boolean alive = true;
while (alive) {
for(ImageVerifyQuestioner imageVerifyQuestioner : imageVerifyQuestionerList) {
if (true == alive) {
imageVerifyQuestioner.loop();
if (imageVerifyQuestioner.getCode() != "") {
code = imageVerifyQuestioner.getCode();
alive = false;
}
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return code;
}
}


保持原有的命令行交互输入图片验证码的输入方式。

/**
*
*/
package test_2;

import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

import iqq.im.event.QQNotifyEventArgs.ImageVerify;

public class ImageVerifyConsoleQuestioner extends ImageVerifyQuestioner {
private boolean isPrompt;
private StringBuilder codeStringBuilder = new StringBuilder();
public ImageVerifyConsoleQuestioner(ImageVerify imageVerify) {
super(imageVerify);
}
private void prompt () {
try {
ImageIO.write(this.getImageVerify().image, "png", new File("verify.png"));
System.out.println(this.getImageVerify().reason);
System.out.print("请输入在项目根目录下 verify.png 图片里面的验证码: ");
isPrompt = true;
} catch (IOException e) {
e.printStackTrace();
}
}
private void read () {
try {
int available = System.in.available();
if (0 < available) {
int inChar = System.in.read();
switch (Character.getType(inChar)) {
case Character.UPPERCASE_LETTER:
case Character.LOWERCASE_LETTER:
case Character.DECIMAL_DIGIT_NUMBER:
codeStringBuilder.append((char) inChar);
break;
case Character.CONTROL:
this.setCode(codeStringBuilder.toString());
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void loop() {
if (false == this.isPrompt) {
this.prompt();
}
if (this.getCode() == "") {
this.read();
}
}
}


新增通过新浪微博输入图片验证码的输入方式,其中的accessTokenFile的值应替换为保存新浪微博Access Token的路径。

/**
*
*/
package test_2;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Logger;

import javax.imageio.ImageIO;
import javax.net.ssl.HttpsURLConnection;

import org.json.JSONObject;

import iqq.im.event.QQNotifyEventArgs.ImageVerify;

public class ImageVerifyWeiboQuestioner extends ImageVerifyQuestioner {
private static final String accessTokenFile = "**********";
private static final Logger logger = java.util.logging.Logger.getLogger("");
private String accessToken;
private long weiboId;
private long lastCheckTime;
public ImageVerifyWeiboQuestioner(ImageVerify imageVerify) {
super(imageVerify);
}
private void readAccessToken () {
FileReader fileReaderAccessToken;
try {
fileReaderAccessToken = new FileReader(accessTokenFile);
BufferedReader bufferedReaderAccessToken = new BufferedReader(fileReaderAccessToken);
accessToken = bufferedReaderAccessToken.readLine();
bufferedReaderAccessToken.close();
fileReaderAccessToken.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void uploadVerifyImage () {
try {
//Status
StringBuilder statusStringBuilder = new StringBuilder();
statusStringBuilder.append("请@胡争辉 输入验证码 ");
statusStringBuilder.append((new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date()));
//URL
StringBuilder urlStringBuilder = new StringBuilder();
urlStringBuilder.append("https://api.weibo.com/2/statuses/upload.json?access_token=");
urlStringBuilder.append(accessToken);
URL url = new URL(urlStringBuilder.toString());
URLConnection urlConnection =url.openConnection();
if (urlConnection instanceof HttpsURLConnection) {
String BOUNDARY = "---------------------------" + String.valueOf(System.currentTimeMillis());
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream.write(("--" + BOUNDARY + "\r\n").getBytes());
byteArrayOutputStream.write(("Content-Disposition: form-data; name=\"pic\"; filename=\"verifyimage.png\"\r\n").getBytes());
byteArrayOutputStream.write(("Content-Type: image/png\r\n").getBytes());
byteArrayOutputStream.write(("\r\n").getBytes());
ImageIO.write(this.getImageVerify().image, "png", byteArrayOutputStream);
byteArrayOutputStream.write(("\r\n").getBytes());
byteArrayOutputStream.write(("--" + BOUNDARY + "\r\n").getBytes());
byteArrayOutputStream.write(("Content-Disposition: form-data; name=\"status\"\r\n").getBytes());
byteArrayOutputStream.write(("\r\n").getBytes());
byteArrayOutputStream.write(statusStringBuilder.toString().getBytes());
byteArrayOutputStream.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes());
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) urlConnection;
httpsURLConnection.setRequestMethod("POST");
httpsURLConnection.addRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
httpsURLConnection.setDoOutput(true);
httpsURLConnection.setDoInput(true);
OutputStream outputStream = httpsURLConnection.getOutputStream();
outputStream.write(byteArrayOutputStream.toByteArray());
outputStream.flush();
outputStream.close();
StringBuilder response = new StringBuilder();
InputStreamReader inputStreamReader = new InputStreamReader(httpsURLConnection.getInputStream());
int readChar = inputStreamReader.read();
while (-1 != readChar) {
response.append((char) readChar);
readChar = inputStreamReader.read();
}
inputStreamReader.close();
httpsURLConnection.disconnect();
logger.info(response.toString());
JSONObject responseJson = new JSONObject(response.toString());
this.weiboId = responseJson.getLong("id");
logger.info("Weibo Id = " + String.valueOf(this.weiboId));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}
private void checkComment () {
try {
StringBuilder commentStringBuilder = new StringBuilder();
commentStringBuilder.append("https://api.weibo.com/2/comments/show.json?filter_by_author=1&access_token=");
commentStringBuilder.append(accessToken);
commentStringBuilder.append("&id=");
commentStringBuilder.append(weiboId);
URL comment = new URL(commentStringBuilder.toString());
URLConnection commentConnection = comment.openConnection();
if (commentConnection instanceof HttpsURLConnection) {
HttpsURLConnection commentHttpsURLConnection = (HttpsURLConnection) commentConnection;
commentHttpsURLConnection.setDoInput(true);
InputStreamReader commentStreamReader = new InputStreamReader(commentHttpsURLConnection.getInputStream());
StringBuilder commentResponse = new StringBuilder();
int commentChar = commentStreamReader.read();
while (-1 != commentChar) {
commentResponse.append((char) commentChar);
commentChar = commentStreamReader.read();
}
commentStreamReader.close();
commentHttpsURLConnection.disconnect();
JSONObject commentsJson = new JSONObject(commentResponse.toString());
int total_number = commentsJson.getInt("total_number");
logger.info("total_number = " + String.valueOf(total_number));
if (0 < total_number) {
JSONObject commentJson = commentsJson.getJSONArray("comments").getJSONObject(0);
logger.info("text=" + commentJson.getString("text"));
this.setCode(commentJson.getString("text"));
}

}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void loop () {
if (null == accessToken) {
this.readAccessToken();
}
if ((null != accessToken) && (0 == weiboId)) {
this.uploadVerifyImage();
lastCheckTime = System.currentTimeMillis();
}
if ((0 < weiboId) && (this.getCode() == "") && (10000 < System.currentTimeMillis() - lastCheckTime)) {
this.checkComment();
lastCheckTime = System.currentTimeMillis();
}
}
}


iQQ 学习笔记2测试 :借助新浪微博输入验证码、远程控制退出
测试本程序需要注册两个QQ号,并互相加为好友。保持一个QQ使用客户端登录,另一个QQ的QQ号和密码填写在程序中。

需要注册一个新浪微博APP帐号,需要注册两个新浪微博帐号,其中一个通过该新浪微博APP验证后保存Access Token,设定这两个帐号互相关注。

运行程序后不仅出现命令行提示,还将用一个新浪微博帐号发一条微博,另一个新浪微博帐号会显示该条微博,微博上包含有验证码图片,用另一个新浪微博帐号回复该条微博,内容为验证码图片上的文字。

在QQ上可以看到该QQ上线,如果输入logout,QQ将下线,程序自动退出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: