此文章完全转自他人博客(用于个人学习记录)
这个功能的实现关键在于找到每张图片的链接地址,之前一直不知道怎么找到,后来发现用SmartSniff分析数据包,很容易就找到了
/**
* core class
*
* @author wensefu.jerry.Ling<br/>
* wrote on 2011-1-28
*/
public class PhotoDownLoad {
/*
* sample uri: album:
* http://xalist.photo.qq.com/fcgi-bin/fcg_list_album?uin=
* 419758768&outstyle=2&t=0.7253889227680141&g_tk=5381 photo:
* http://xaplist.
* photo.qq.com/fcgi-bin/fcg_list_photo?uin=419758768&albumid=
* e3b63b1c-2dce-4f86-ad02-c0f81a878615
* &outstyle=json&t=0.9962191131376609&g_tk=5381
*/
private static final String albumbase = "http://xalist.photo.qq.com/fcgi-bin/fcg_list_album?uin=";
private static final String photobase = "http://xaplist.photo.qq.com/fcgi-bin/fcg_list_photo?uin=";
private static final String charset = "gb2312";
private static List<Album> albums; // 获取的所有相册
private static final String savePath = "e://qqPhoto//"; // 图片保存位置的父目录
private int curIndex = 0; // 每个相册当前正在下载的图片指针
/**
* 获取用户相册
*
* @param qq
* @return
*/
public List<Album> getAlbums(String qq) {
List<Album> result = new ArrayList<Album>();
HttpClient client = new HttpClient();
String getUri = albumbase + qq + "&outstyle=2"; // outstyle!=2服务器将以xml的形式返回结果,
// 这里只以简单文本解析提取相关信息,不做xml解析了.
HttpMethod method = new GetMethod(getUri);
method.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET,
charset);
int status = 0;
try {
status = client.executeMethod(method);
if (status != HttpStatus.SC_OK) {
System.err.println("发生网络错误!");
return null;
}
} catch (HttpException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
InputStream is = null;
BufferedReader br = null;
InputStreamReader isr = null;
List<String> ids = new ArrayList<String>();
List<String> names = new ArrayList<String>();
List<Integer> totals = new ArrayList<Integer>();
try {
is = method.getResponseBodyAsStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
String temp = null;
while ((temp = br.readLine()) != null) {
if (temp.contains("/"id/" :")) {
String id = temp.substring(temp.indexOf("/"id/" :") + 8,
temp.length() - 2);
ids.add(id);
}
if (temp.contains("/"name/" :")) {
String name = temp.substring(
temp.indexOf("/"name/" :") + 10, temp.length() - 3);
names.add(name);
}
if (temp.contains("/"total/" :")) {
String total = temp
.substring(temp.indexOf("/"total/" :") + 10,
temp.length() - 1);
totals.add(Integer.parseInt(total));
}
if (temp.contains("/"left/" :")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
method.releaseConnection();
try {
br.close();
isr.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
for (int i = 0; i < ids.size(); i++) {
Album album = new Album(ids.get(i), names.get(i), totals.get(i));
result.add(album);
}
return result;
}
/**
* 获取一个相册的图片信息
*
* @param pid
* @return
*/
public List<Photo> getPhotoByAlbum(Album album, String qq) {
List<Photo> result = new ArrayList<Photo>();
HttpClient client = new HttpClient();
System.out.println(album.getId());
String getUri = photobase + qq + "&albumid=" + album.getId()
+ "&outstyle=json";
HttpMethod method = new GetMethod(getUri);
method.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET,
charset);
int status = 0;
try {
status = client.executeMethod(method);
if (status != HttpStatus.SC_OK) {
System.err.println("发生网络错误!");
return null;
}
} catch (HttpException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
InputStream is = null;
BufferedReader br = null;
InputStreamReader isr = null;
List<String> names = new ArrayList<String>();
List<String> urls = new ArrayList<String>();
try {
is = method.getResponseBodyAsStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
String temp = null;
boolean sign = false;
while ((temp = br.readLine()) != null) {
int len = temp.length();
if (temp.contains("/"pic/" : [")) {
sign = true;
}
if (sign && temp.contains("/"name/" :")) {
String name = temp.substring(
temp.indexOf("/"name/" :") + 10, len - 2);
names.add(name);
}
if (temp.contains("/"url/" :")) {
String url = temp.substring(temp.indexOf("/"url/" :") + 9,
len - 3);
urls.add(url);
}
if (temp.contains(" ],")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
method.releaseConnection();
try {
br.close();
isr.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
for (int i = 0; i < names.size(); i++) {
Photo photo = new Photo();
photo.setName(names.get(i));
photo.setUrl(urls.get(i));
photo.setAlbum(album);
result.add(photo);
}
return result;
}
/**
* 通过uri下载远程图片到本地
*
* @param uri
* @param name
* 要保存的图片名(非路径)
*/
public void saveImgFromUrl(Photo photo, String qq) {
URL imgurl = null;
BufferedInputStream bis = null;
OutputStream os = null;
try {
imgurl = new URL(photo.getUrl());
bis = new BufferedInputStream(imgurl.openStream());
byte[] buffer = new byte[512];
File path = new File(savePath + "//" + qq + "//"
+ photo.getAlbum().getName().trim());
if (!path.exists()) {
path.mkdirs();
}
os = new FileOutputStream(new File(path, photo.getName().trim()
+ ".jpeg"));
int len = 0;
while ((len = bis.read(buffer)) > 0) {
os.write(buffer, 0, len);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bis.close();
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 下载一个相册的图片
*
* @param index
* 相册序号
*/
public void savePhoto(final int index, final String qq) {
Album album = albums.get(index);
final List<Photo> photos = this.getPhotoByAlbum(album, qq);
if (photos == null || photos.size() == 0) {
System.out.println("相册" + album.getName() + "为空.");
return;
}
final int maxThreadCnt = 10; // 每个相册最多开启10个线程进行下载
final int total = album.getCnt();
int realThreadCnt = total >= maxThreadCnt ? maxThreadCnt : total; // 实际下载一个相册的线程数
/**
* 线程驱动下载任务
*
* @author wensefu.jerry.Ling<br/>
* wrote on 2011-1-29
*/
class DownLoadTask implements Runnable {
int id; // 线程标识
int pindex;// 下载的图片指针
public DownLoadTask(int id, int pindex) {
this.id = id;
this.pindex = pindex;
}
@Override
public void run() {
while (curIndex <= total - 1) {
int temp = pindex;
pindex = curIndex;
curIndex++;
Photo photo = photos.get(temp);
System.out.println("线程" + (index + 1) + "_" + id + "开始下载第"
+ (index + 1) + "个相册第" + (pindex + 1) + "张图片...");
saveImgFromUrl(photo, qq);
System.out.println("线程" + (index + 1) + "_" + id + "完成第"
+ (index + 1) + "个相册第" + (pindex + 1) + "张图片下载");
}
}
}
ExecutorService exec = Executors.newCachedThreadPool();
/*
* 初始化各线程状态 此处给每个线程分配一个下载起始点
*/
for (int i = 0; i < realThreadCnt; i++) {
DownLoadTask task = new DownLoadTask(i + 1, i);
exec.execute(task);
}
exec.shutdown();
}
public static void main(String[] args) {
PhotoDownLoad pdl = new PhotoDownLoad();
String qq = "402493283";
albums = pdl.getAlbums(qq);
if (albums == null || albums.size() == 0) {
System.err.println("相册信息获取失败,可能是用户没有开放权限.");
return;
}
int len = albums.size();
System.out.println("相册信息获取成功,用户共有" + len + "个相册.");
for (int i = 0; i < len; i++) { // 考虑到相册数量不会很多,相册采用顺序下载,不使用异步下载
System.out.println("开始下载第" + (i + 1) + "个相册...");
pdl.savePhoto(i, qq);
pdl.curIndex = 0;
System.out.println("第" + (i + 1) + "个相册下载完成.");
}
}
}
/**
* 图片实体类
*
* @author wensefu.jerry.Ling<br/>
* wrote on 2011-1-28
*/
public class Photo {
private Album album;
private String url;
private String name;
//getter and setter
....
}
/**
* 相册实体类
*
* @author wensefu.jerry.Ling<br/>
* wrote on 2011-1-28
*/
public class Album {
private String id;
private String name;
private int cnt; // 图片张数
public Album() {
}
/**
* @param id
* @param name
* @param cnt
*/
public Album(String id, String name, int cnt) {
super();
this.id = id;
this.name = name;
this.cnt = cnt;
}
//getter and setter
....
}