本帖最后由 8457091 于 2018-8-2 23:57 编辑
查询qq历史头像效果图:
查询历史头像效果图
首先,这个接口不是我先发现的,从一位老铁那里拿过来的,这位老铁已经在我之前把接口公布了。
他是用易语言做的程序, 这里是传送门 。
下面我把自己用JAVA写的程序源码贴出来,仅供大家学习。有能力的也可以尝试把这个程序运行起来,有不懂的可以问我(虽然我不一定会回答)。
1.这个是启动类:
[Java] 纯文本查看 复制代码 package myapp.zjp.clent;
public class StartServer {
public static void main(String[] args) {
//初始化
new Config();
//启动socket服务
if (Config.socketServerSwitch==1){
new Thread(new SocketServer()).start();
}
//启动http服务
if (Config.httpServerSwitch==1){
new Thread(new HttpServer()).start();
}
}
}
2.这个是socket服务端程序
[Java] 纯文本查看 复制代码 package myapp.zjp.clent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.regex.Pattern;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;
/**
* 获取任意QQ历史头像服务器 code by 小七
*/
public class SocketServer implements Runnable{
private Logger log = Logger.getLogger(this.getClass());
public SocketServer() {
}
public void run() {
try {
// 建立服务器连接,设定客户连接请求队列的长度
ServerSocket server = new ServerSocket(Config.socketServerPort, Config.socketServerMaxlen);
log.info("socket服务器已启动,服务端口:["+Config.socketServerPort +"],最大连接数:["+ Config.socketServerMaxlen +"]");
while (true) {
// 等待客户连接
Socket socket = server.accept();
new Thread(new SocketServerThread(socket)).start();
}
} catch (IOException e) {
log.error("socket服务器启动失败", e);
}
}
}
class SocketServerThread implements Runnable {
private Logger log = Logger.getLogger(this.getClass());
private Socket socket;
public SocketServerThread(Socket socket) {
this.socket = socket;
}
// 为一个用户提供服务
public void run() {
String hostAddress = socket.getInetAddress().getHostAddress();
DataInputStream in = null;
DataOutputStream out = null;
try {
try {
// 读取客户端传过来信息的DataInputStream
in = new DataInputStream(socket.getInputStream());
// 向客户端发送信息的DataOutputStream
out = new DataOutputStream(socket.getOutputStream());
// 读取来自客户端的信息
String qqNumber = in.readUTF();
Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
if( qqNumber!= null && qqNumber.trim().length()>0
//判断字符串是否为整数
&& pattern.matcher(qqNumber.trim()).matches()){
JSONObject data = HttpUtils.getJSONResult(qqNumber, new getCookie().reader());
out.writeUTF(data.toString());
if (data.get("ret").toString().trim().equals("0")){
log.info("[" + hostAddress + "]查询QQ:[" + qqNumber +"]OK");
}else{
log.info("[" + hostAddress + "]查询QQ:[" + qqNumber +"]FAIL");
}
//停止线程
Thread.yield();
}else{
log.info("[" + socket.getInetAddress().getHostAddress() + "]查询QQ:[" + qqNumber +"]FAIL");
//停止线程
Thread.yield();
}
} finally {// 建立连接失败的话不会执行socket.close();
in.close();
out.close();
socket.close();
}
} catch (EOFException e){
log.error( "[" + hostAddress + "]读取失败",e);
//读取失败
}catch (IOException e) {
log.error("[" + hostAddress + "]系统异常",e);
}
}
public void htmlService(){
}
}
3.这个是http服务端程序源码:
[Java] 纯文本查看 复制代码 package myapp.zjp.clent;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.regex.Pattern;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;
/**
* 获取任意QQ历史头像服务器 code by 小七
*/
public class HttpServer implements Runnable{
private Logger log = Logger.getLogger(this.getClass());
public HttpServer() {
}
// 提供服务
public void run() {
try {
// 建立服务器连接,设定客户连接请求队列的长度
ServerSocket server = new ServerSocket(Config.httpServerPort, Config.httpServerMaxlen);
log.info("http服务器已启动,服务端口:["+Config.httpServerPort +"],最大连接数:["+ Config.httpServerMaxlen +"]");
while (true) {
// 等待客户连接
Socket socket = server.accept();
new Thread(new HttpServerThread(socket)).start();
}
} catch (IOException e) {
log.error("http服务器启动失败", e);
}
}
}
class HttpServerThread implements Runnable {
private Logger log = Logger.getLogger(this.getClass());
private Socket socket;
public HttpServerThread(Socket socket) {
this.socket = socket;
}
// 为一个用户提供服务
public void run() {
String hostAddress = socket.getInetAddress().getHostAddress();
BufferedReader in = null;
OutputStream out = null;
try {
try {
InputStream is = socket.getInputStream();
in = new BufferedReader(new InputStreamReader(is, "UTF-8"));
boolean flag = false;
// 读取返回的内容
String line = in.readLine();
String msg = "";
String qqNumber = "";
if(line.substring(0, 3).equalsIgnoreCase("GET")){
flag = true;
try{
qqNumber = line.split("=")[1].split(" ")[0];
Pattern pattern = Pattern.compile("^[-\\+]?[\\d]{4,10}$");
//判断字符串是否为整数
flag = pattern.matcher(qqNumber).matches();
if (!flag){
msg = "-1:请求参数有误";
log.error("["+hostAddress+"]请求参数不正确");
}
System.out.println(qqNumber);
}catch (Exception e){
flag = false;
msg = "-2:请求参数有误";
log.error("["+hostAddress+"]请求参数不正确",e);
}
} else {
flag = false;
msg = "-3:暂不支持post请求方式";
log.error("["+hostAddress+"]暂不支持post请求方式");
}
StringBuffer bodyStr = new StringBuffer();
if (flag){
JSONObject data = HttpUtils.getJSONResult(qqNumber, new getCookie().reader());
bodyStr.append(data.toString());
if (data.get("ret").toString().trim().equals("0")){
log.info("[" + hostAddress + "]查询QQ:[" + qqNumber +"]OK");
}else{
log.info("[" + hostAddress + "]查询QQ:[" + qqNumber +"]FAIL");
}
}else{
bodyStr.append("<h1>hello!</h1>");
bodyStr.append("<h3>" + msg + "!</h3>");
}
byte[] bodyByte = bodyStr.toString().getBytes();
StringBuffer headStr = new StringBuffer("HTTP/1.1 200 OK\r\n");
if(flag){
headStr.append("Content-Type:application/json;charset=utf-gbk\r\n");
headStr.append("dataType:json\r\n");
}else{
headStr.append("Content-Type:text/html;charset=utf-gbk\r\n");
}
headStr.append("Content-Length:"+ bodyByte.length +"\r\n");
headStr.append("Server:gybs\r\n");
headStr.append(("Date:"+new Date()+"\r\n"));
headStr.append("\r\n");
out = socket.getOutputStream();
out.write(headStr.toString().getBytes());
out.write(bodyByte);
out.flush();
} finally {// 建立连接失败的话不会执行socket.close();
if(in != null ){
in.close();
}
if(out != null){
out.close();
}
if (socket != null){
socket.close();
}
}
} catch (EOFException e){
log.error( "[" + hostAddress + "]读取失败",e);
//读取失败
}catch (IOException e) {
log.error("[" + hostAddress + "]系统异常",e);
}
}
public void htmlService(){
}
}
4.这个是HTTP工具类
[Asm] 纯文本查看 复制代码 package myapp.zjp.clent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;
/**
*
* 用于模拟HTTP请求中GET/POST方式
*
* [url=home.php?mod=space&uid=686208]@AuThor[/url] 小七
*
*/
public class HttpUtils {
private static Logger log = Logger.getLogger("log");
/**
* 发送GET请求
* @param url
* 目的地址
* [url=home.php?mod=space&uid=155549]@Return[/url] 远程响应结果
*/
public static String sendGet(String url, String cookie) {
String result = "";
BufferedReader in = null;// 读取响应输入流
try {
//System.out.println(full_url);
// 创建URL对象
java.net.URL connURL = new java.net.URL(url);
// 打开URL连接
java.net.HttpURLConnection conn = (java.net.HttpURLConnection) connURL
.openConnection();
// 设置通用属性
//conn.setRequestMethod("POST");
conn.setRequestProperty("Accept", "text/html, application/xhtml+xml, image/jxr, */*");
conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Cookie", cookie);
// 建立实际的连接
conn.connect();
// 响应头部获取
//Map<String, List<String>> headers = conn.getHeaderFields();
// 遍历所有的响应头字段
/*for (String key : headers.keySet()) {
System.out.println(key + "\t:\t" + headers.get(key));
}*/
// 定义BufferedReader输入流来读取URL的响应,并设置编码方式
in = new BufferedReader(new InputStreamReader(conn
.getInputStream(), "UTF-8"));
String line = "";
// 读取返回的内容
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
log.info("网络异常", e);
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
public static JSONObject getJSONResult(String qqNumber, String cookie){
String url = "http://qlist.qlogo.cn/file_list?src=1&uin="
+ qqNumber +"&md5=&start_idx=1&end_idx=500";
String result = HttpUtils.sendGet(url,cookie);
JSONObject json = JSONObject.fromObject(result);
String ret = json.get("ret").toString();
int index = 0;
//此处重发次数从配置文件取
int max = Config.resendRequestNumber;
while ((!ret.trim().equals("0")) && index<max){
result = HttpUtils.sendGet(url,cookie);
json = JSONObject.fromObject(result);
ret = json.get("ret").toString();
index++;
try {
Thread.sleep(1000*index);
} catch (InterruptedException e) {
log.error("线程休眠异常", e);
}
}
return json;
}
}
5.这个是读QQcookie数据的工具类:
[Asm] 纯文本查看 复制代码 package myapp.zjp.clent;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.log4j.Logger;
public class getCookie {
private Logger log = Logger.getLogger(this.getClass());
//读取session文件
public String reader(){
File cookiesFile = new File(Config.cookieFilepath);
String str = "";
try {
FileInputStream is = new FileInputStream(cookiesFile);
BufferedInputStream bis = new BufferedInputStream(is);
//自己定义一个缓冲区
byte[] buffer=new byte[10240];
int flag=0;
while((flag=bis.read(buffer))!=-1){
str+=new String(buffer, 0, flag);
}
} catch (FileNotFoundException e) {
log.error("session文件没有找到 [" + Config.cookieFilepath + "]",e);
} catch (IOException e) {
log.error("读取文件session失败",e);
}
return str;
}
}
6.这个是配置文件工具类(用配置文件是为了方便修改系统参数而不修改源代码):
[Asm] 纯文本查看 复制代码 package myapp.zjp.clent;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Map.Entry;
import org.apache.log4j.Logger;
/**
* 读取系统配置文件信息
*/
public class Config {
/** 日志类 */
private static Logger g_oLog = Logger.getLogger("log");
/** socket服务器开关 0关,1开*/
public static int socketServerSwitch = 1;
/** http服务器开关 0关,1开*/
public static int httpServerSwitch = 1;
/** 身份证系统服务器开关 0关,1开 */
public static int IdcardServerSwitch = 1;
/** socket服务器端口配置 */
public static int socketServerPort = 8080;
/** socket服务最大连接数配置 */
public static int socketServerMaxlen = 20;
/** http服务器端口配置 */
public static int httpServerPort = 8081;
/** http服务最大连接数配置 */
public static int httpServerMaxlen = 20;
/** cookie文件的存放路径 */
public static String cookieFilepath = "";
/** 系统返回错误码-80,重发请求次数 */
public static int resendRequestNumber = 3;
/** 身份证系统ip */
public static String IdcardServerIP = "127.0.0.1";
/** 身份证系统ip */
public static int IdcardServerPort = 8889;
private static Properties p;
public Config() {
}
static {
p = new Properties();
String m_sConfigFilePath = "C:" + File.separator + "config.ini";
File f = new File(m_sConfigFilePath);
InputStream is = null;
try {
if (!f.exists()) {
g_oLog.error("没有读取到系统配置文件:" + m_sConfigFilePath);
System.exit(1);
}
is = new FileInputStream(f);
p.load(is);
String tmp = null;
//socket服务开关
tmp = p.getProperty("socket.server.switch");
if(tmp == null || tmp.length()<1){
g_oLog.error("socket服务开关配置有误:[" + Config.socketServerSwitch + "="
+ tmp + "]取默认值");
}else{
Config.socketServerSwitch = Integer.valueOf(tmp.trim());
}
//http服务开关
tmp = p.getProperty("http.server.switch");
if(tmp == null || tmp.length()<1){
g_oLog.error("http服务开关配置有误:[" + Config.socketServerSwitch + "="
+ tmp + "]取默认值");
}else{
Config.httpServerSwitch = Integer.valueOf(tmp.trim());
}
//socket服务端口号
tmp = p.getProperty("socket.server.port");
if(tmp == null || tmp.length()<1){
g_oLog.error("socket服务端口号配置有误:[" + Config.socketServerPort + "="
+ tmp + "]取默认值");
}else{
Config.socketServerPort = Integer.valueOf(tmp.trim());
}
//socket服务最大连接数配置
tmp = p.getProperty("socket.server.maxlen");
if(tmp == null || tmp.length()<1){
g_oLog.error("socket服务最大连接数配置有误:[" + Config.socketServerMaxlen + "="
+ tmp + "]取默认值");
// System.exit(1);
}else{
Config.socketServerMaxlen = Integer.valueOf(tmp.trim());
}
//http服务端口号
tmp = p.getProperty("http.server.port");
if(tmp == null || tmp.length()<1){
g_oLog.error("http服务端口号配置有误:[" + Config.httpServerPort + "="
+ tmp + "]取默认值");
}else{
Config.httpServerPort = Integer.valueOf(tmp.trim());
}
//http服务最大连接数配置
tmp = p.getProperty("http.server.maxlen");
if(tmp == null || tmp.length()<1){
g_oLog.error("http服务最大连接数配置有误:[" + Config.httpServerMaxlen + "="
+ tmp + "]取默认值");
// System.exit(1);
}else{
Config.httpServerMaxlen = Integer.valueOf(tmp.trim());
}
//系统返回错误码-80,重发请求次数
tmp = p.getProperty("resend.request.number");
if(tmp == null || tmp.length()<1){
g_oLog.error("系统返回错误码-80,重发请求次数配置有误:[" + Config.resendRequestNumber + "="
+ tmp + "]取默认值");
// System.exit(1);
}else{
Config.resendRequestNumber = Integer.valueOf(tmp.trim());
}
//cookie文件的存放路径
tmp = p.getProperty("cookie.filepath");
if(tmp == null || tmp.length()<1){
g_oLog.error("cookie文件的存放路径配置有误:[" + Config.cookieFilepath + "="
+ tmp + "]取默认值");
}else{
Config.cookieFilepath = tmp.trim();
}
g_oLog.info("========当前系统配置为=========");
for (Entry<Object, Object> en : p.entrySet()) {
g_oLog.info(en.getKey() + "=" + en.getValue());
}
g_oLog.info("==========================");
} catch (IOException e) {
g_oLog.error("读取配置文件错误" + e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
}
/**
* 通过属性获得属性值.
*
* @param key
* 属性
* @return 属性对应的属性值
*/
public static String getProperty(final String key) {
if (p == null || key == null) {
return null;
}
return p.getProperty(key.trim());
}
}
7.系统配置文件附上:
[Java] 纯文本查看 复制代码 #服务器配置 放到C盘根目录
#是否开启socket服务器(0关闭 ,1开启)
socket.server.switch=1
#是否开启http服务器(0关闭 ,1开启)
http.server.switch=0
#cookie文件的存放路径配置
cookie.filepath=C:\\Cookies.txt
#socket服务ip配置
socket.server.ip=182.61.49.27
#socket服务端口配置
socket.server.port=9801
#socket服务最大连接数配置-最大值50
socket.server.maxlen=30
#http服务端口配置
http.server.port=8081
#http服务最大连接数配置-最大值50
http.server.maxlen=30
#系统返回错误码-80,重发请求次数配置
#(第1次重发延迟1秒发送,第2次延迟2秒发送
#以此类推,发送四次总延迟为1+2+3+4=10/秒)
resend.request.number=3
附上clent测试类
[Java] 纯文本查看 复制代码 package myapp.zjp.clent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
/**
* 客户端
*/
public class Clent {
private String host = "localhost";// 默认连接到本机
private int port = 8080;// 默认连接到端口8080
public Clent() {
}
// 连接到指定的主机和端口
public Clent(String host, int port) {
this.host = host;
this.port = port;
}
public void chat() {
try {
// 连接到服务器
Socket socket = new Socket(host, port);
try {
// 读取服务器端传过来信息的DataInputStream
DataInputStream in = new DataInputStream(socket
.getInputStream());
// 向服务器端发送信息的DataOutputStream
DataOutputStream out = new DataOutputStream(socket
.getOutputStream());
// 装饰标准输入流,用于从控制台输入
Scanner scanner = new Scanner(System.in);
String send = scanner.nextLine();
// 把从控制台得到的信息传送给服务器
out.writeUTF(send);
// 读取来自服务器的信息
String accpet = in.readUTF();
in.close();
out.close();
socket.close();
System.out.println(accpet);
} finally {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Clent("182.61.49.27",8080).chat();
}
}
附上html前台网页源码
[HTML] 纯文本查看 复制代码 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>任意QQ历史头像查询</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=2.0, user-scalable=yes" />
<meta http-equiv="description" content="This is my page">
<!--<link rel="stylesheet" href="zTreeStyle/zTreeStyle.css" type="text/css">
-->
<style type="text/css">
.title_box{
width: 90%;
font-size:30px;
overflow: hidden;
display: flex;
}
.title_left{width: 60px;height: 40px;float: left;}
.title_right{width: 60px;height: 40px;float: right;}
.title_right input{width: 60px;height: 40px; border: 1px solid black;}
.title_box input{width: 100%; font-size:20px;}
</style>
<script type="text/javascript" src="res/js/jquery-1.4.2.js"></script>
<script type="text/javascript">
function check(){
var qqnumber = document.getElementById('qqnumber').value;
if (qqnumber==null || qqnumber =="undefined" || qqnumber == "" || qqnumber.length<6){
var ss = $('message').innerHTML;
document.getElementById('submit').disabled = false;
document.getElementById('qqnumber').focus();
document.getElementById('message').innerHTML = "<p style=\"color: red;\" >提示:请输入正确的qq号!</p>";
return false;
}else{
document.getElementById('submit').disabled = true;
document.getElementById('message').innerHTML = "<p style=\"color: red;\" >提示:正在查询,请稍候...</p>";
console.log('start');
//1.创建AJAX对象
var ajax = new XMLHttpRequest();
//4.给AJAX设置事件(这里最多感知4[1-4]个状态)
ajax.onreadystatechange = function(){
//5.获取响应
//responseText 以字符串的形式接收服务器返回的信息
//console.log(ajax.readyState);
if(ajax.readyState == 4 && ajax.status == 200){
var msg = ajax.responseText;
var data = eval('(' + msg + ')');
console.log(msg);
setData(data);
document.getElementById('submit').disabled = false;
//alert(data.ret);
//alert(msg);
//var divtag = document.getElementById('his');
//divtag.innerHTML = msg;
}
}
//2.创建http请求,并设置请求地址
var username = document.getElementsByTagName('input')[0].value;
var email = document.getElementsByTagName('input')[1].value;
username = encodeURIComponent(username); //对输入的特殊符号(&,=等)进行编码
email = encodeURIComponent(email);
ajax.open('get','struts/demoAction_getHeadJson.action?qq='+ document.getElementById('qqnumber').value);
//3.发送请求(get--null post--数据)
ajax.send(null);
return false;
}
}
function setData(data){
if (data.ret=='0'){
var totalNum = data.total_num;
var uin = data.uin;
document.getElementById('message').innerHTML = "<p style=\"color: red;\" >提示:查询成功,QQ[" + uin + "]共" + totalNum + "个历史头像!</p>";
if (totalNum != "0"){
var imageUrl = "";
var fileList = data.file_list;
for (var i=0; i<totalNum; i++){
var big = fileList[i].big;
var small = fileList[i].small;
var baseUrl = fileList[i].base_url;
var timestamp = fileList[i].timestamp;
var date = formatDate(parseInt(timestamp * 1000));
//var dateTime = new Date(parseInt(timestamp) * 1000).toLocaleString().replace(/:\d{1,2}$/,' ');
big = big=="0"?small:big;
imageUrl += '<div style="float: left"><a href="' + baseUrl + big +'" target="_blank">' +
'<img src="' + baseUrl + small + '" /></a>' +
'<div align="center">' + date + '</div></div>';
var divtag = document.getElementById('his');
divtag.innerHTML = imageUrl;
}
}else{
document.getElementById('message').innerHTML = "<p style=\"color: red;\" >提示:查询成功,该qq号没有历史头像!</p>";
}
}else if(data.ret == "-80"){
document.getElementById('message').innerHTML = "<p style=\"color: red;\" >提示:当前服务器繁忙,请重试!</p>";
}else{
document.getElementById('message').innerHTML = "<p style=\"color: red;\" >提示:查询失败,请确定您输入的qq号是否正确!</p>";
}
}
function add0(m){
return m<10?'0'+m:m
}
function formatDate(timestamp){
//shijianchuo是整数,否则要parseInt转换
var time = new Date(timestamp);
var y = time.getFullYear();
var m = time.getMonth()+1;
var d = time.getDate();
var h = time.getHours();
var mm = time.getMinutes();
var s = time.getSeconds();
return y+'-'+add0(m)+'-'+add0(d);
//'+add0(h)+':'+add0(mm)+':'+add0(s);
}
</script>
</head>
<body>
<div id="text" align="center">
<h2 align='center'>任意QQ号码历史头像查询</h2>
<form action="#">
<div class="title_box">
<div class="title_left">QQ:</div>
<input id="qqnumber" name="qqnumber" type="text"
placeholder="请输入要查询的QQ号:";
maxlength="10" />
<div class="title_right">
<input id='submit' type="submit" value="确定" />
</div>
</div>
<span id="message" ></span>
</form>
</div>
<div id="his">
</div>
</body>
</html>
|