此文章完全转自他人博客(用于个人学习记录)
这个功能的实现关键在于找到每张图片的链接地址,之前一直不知道怎么找到,后来发现用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 .... }