Java实现批量下载《神秘的程序员》漫画

上周看了西乔的博客“西乔的九卦”。《神秘的程序员们》系列漫画感觉很喜欢,很搞笑。这些漫画经常出现在CSDN“程序员”杂志末页的,以前也看过一些。

后来就想下载下来,但是一张一张的点击右键“另存为”,还有很多时候要点击“下一页,”确实让人淡疼。就想着写个程序搞定,自认确实水平一般,查阅了很多资料后,终于搞定。。。

大体的下载过程就是从网页url不断获取html源码的字符串,遇到图片地址,就下载,遇到下一页的地址,就修改原来的url为下一页的url,然后重复上一过程。

1.下载网络图片

首先要解决的是根据url下载单个网络图片的问题。之前确实没有这方面的经验。于是就问度娘,百度多了好几份代码,大都下载的图片效果很差。后来终于找到一个可行的,在此感谢作者。http://www.open-open.com/lib/view/open1329995970842.html

先贴出作者原代码,最终还要修改

package action;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class Getpic {
	public Getpic() {
	}

	public static boolean saveUrlAs(String fileUrl, String savePath)/* fileUrl网络资源地址 */
	{

		try {
			/* 将网络资源地址传给,即赋值给url */
			URL url = new URL(fileUrl);
			
			/* 此为联系获得网络资源的固定格式用法,以便后面的in变量获得url截取网络资源的输入流 */
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			DataInputStream in = new DataInputStream(connection.getInputStream());
			
			/* 此处也可用BufferedInputStream与BufferedOutputStream  需要保存的路径*/
			DataOutputStream out = new DataOutputStream(new FileOutputStream(savePath));
			
			
			/* 将参数savePath,即将截取的图片的存储在本地地址赋值给out输出流所指定的地址 */
			byte[] buffer = new byte[4096];
			int count = 0;
			while ((count = in.read(buffer)) > 0)/* 将输入流以字节的形式读取并写入buffer中 */
			{
				out.write(buffer, 0, count);
			}
			out.close();/* 后面三行为关闭输入输出流以及网络资源的固定格式 */
			in.close();
			connection.disconnect();
			return true;/* 网络资源截取并存储本地成功返回true */

		} catch (Exception e) {
			System.out.println(e + fileUrl + savePath);
			return false;
		}
	}

	public static void main(String[] args) {
		Getpic pic = new Getpic();/* 创建实例 */
		
		//需要下载的URL
		String photoUrl = "http://hiphotos.baidu.com/yanshennan/pic/item/03a505c8bcbaf6557f3e6f8a.jpg";

		// 截取最后/后的字符串
		String fileName = photoUrl.substring(photoUrl.lastIndexOf("/"));
		
		//图片保存路径
		String filePath = "E:";
		
		/* 调用函数,并且进行传参 */
		boolean flag = pic.saveUrlAs(photoUrl, filePath + fileName);
		
		System.out.println("Run ok!\n Get URL file " + flag);
		System.out.println(filePath);
		System.out.println(fileName);
	}

}

2.提取出图片URL

我们可以轻松的获得一个html网页的源代码,图片地址也包含其中,接下来要做的就是如何从这些html代码中分析出图片的网络地址。我想到的就是“正则表达式”,原来只是用正则表达式在android里面匹配过电话号码-_-#,正则表达式确实博大精深。。一时半会真的吃不透。。以后慢慢学习啦。

这里我们看一点西乔博客的html源码

<a href="http://blog.xiqiao.info/blogimg/programmers/53_run_result.gif">点击看大图</a></p>
<p style="text-align: center;"><a href="http://blog.xiqiao.info/blogimg/programmers/53_run_result.gif" target="_blank"><img title=" 运行结果——《神秘的程序员们》系列漫画" src="http://blog.xiqiao.info/blogimg/programmers/53_run_result_thumb.gif" alt=" 运行结果——《神秘的程序员们》系列漫画" /></a></p>
其中包含有图片地址。用BufferedReader的readLine方法得到的是一行行的字符串,也就是遇到\r,\n结束的字符串,所以虽然下面那一行很长,但是也是只会得到一个字符串。

开始我的想法是截取第一段中的图片地址,但是后来发现问题,这段代码代表的是原网页中“点击看大图”的链接。而《神秘的程序员》系列博文里有的是没有这个“点击看大图”的文字链接。于是我就想截取下一段,字符串。

但是这段字符串包含两个图片网址,其中一个是高清大图,另一个是一般的大小。你或许会说那就下高清的吧,确实,但是有的博文图片偏偏是没有高清的,这样匹配起来又会出问题,或许你可以根据判断语句来区别对待,优先下载高清的,没有就下载普通的。但是我这里为了实现起来简单,就统一下载一般大小的图片了。

下面是我蛋疼的正则表达式,写法有很多。。

Pattern p1 = Pattern.compile(".*src.*[gif|jpg].*");
匹配出来,还要再提取出来,正则应该也可以做到,但是我还是选择用字符串取子串的方法来写,更简单。

String line = inputLine.substring(inputLine.indexOf("src"),inputLine.lastIndexOf("\" alt"));
Url = line.substring(line.indexOf("http"));

3.获取下一页

实际上漫画是在很多个网页中的。你看漫画的时候也要点击,下一页,下一页。就是网页上的“← Older Entries

原网页html代码

<ul class="navigation">
        <li class="left"><a href="http://blog.xiqiao.info/category/programmers/page/3" >← Older Entries</a></li>
	<li class="right"><a href="http://blog.xiqiao.info/category/programmers/" >Newer Entries →</a></li>
</ul>
上面,是一个上一页,一个下一页。要找出他,同样使用正则匹配。我写的烂,大家可自由发挥。

Pattern p2 = Pattern.compile(".*<li class=\"left\"><a href=\"http://blog.xiqiao.info/category/programmers/page/.*");
提取比较简单

Url = "http"+inputLine.substring(inputLine.indexOf(':'),inputLine.lastIndexOf('"'));

4.完整代码

//package com.xiqiao;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
/**
 * 批量下载“西乔的九卦”中的系列漫画《神秘的程序员》
 * @author guodongxiaren
 * 2013/11/14
 */
public class DownLoad {

    private String path = "http://blog.xiqiao.info/category/programmers";
    private String filePath = "D:/day/net/pic";//可以改成你自己的路径,注意必须是已存在的路径
    private String fileName = null;
    private String Url = null;
    private Pattern p1 = Pattern.compile(".*src.*[gif|jpg].*");
    private Pattern p2 = Pattern.compile(".*<li class=\"left\"><a href=\"http://blog.xiqiao.info/category/programmers/page/.*");
    
    public static void  main(String[]args)throws IOException{
	DownLoad ia = new DownLoad();
	ia.start();
    }
/**
 * 解析出图片下载地址及图片名称
 * @param inputLine
 */
	public void AddResolution(String inputLine)
	{
	    String line = inputLine.substring(inputLine.indexOf("src"),inputLine.lastIndexOf("\" alt"));
	    Url = line.substring(line.indexOf("http"));
	    System.out.println(Url);
             //为了便于查看图片,我把所有图片都改成jpg。。因为gif图片经常会用浏览器打开-_-#
         fileName = Url.substring(Url.lastIndexOf("/"),Url.lastIndexOf("."))+".jpg";
    }
	
/**
 * 开始下载
 * @throws IOException
 */
	public void start() throws IOException{
		URL name = new URL(path);
		URLConnection conn = name.openConnection();
		InputStream input = conn.getInputStream();
		InputStreamReader isr = new InputStreamReader(input);
		BufferedReader buffer = new BufferedReader(isr);
		String inputLine=null;

		Getpic pic = new Getpic();
		while((inputLine=buffer.readLine())!=null){
			Matcher matcher1 = p1.matcher(inputLine);
			Matcher matcher2 = p2.matcher(inputLine);
			try{
			if(matcher1.matches()){
				AddResolution(inputLine);
				boolean flag = pic.saveUrlAs(Url, filePath + fileName);
		
				System.out.println("Get URL file " + flag);
				System.out.println(filePath);
				System.out.println(fileName+" save successful");
				}
			}catch(StringIndexOutOfBoundsException e){}
			if(matcher2.matches()){
		         Url = "http"+inputLine.substring(inputLine.indexOf(':'),inputLine.lastIndexOf('"'));
				name = new URL(Url);
				conn = name.openConnection();
				input = conn.getInputStream();
				isr = new InputStreamReader(input);
				buffer = new BufferedReader(isr);
			}
		}
		System.out.println("Successful");
	}


/**
 * 感谢这段代码原作者
 * @author http://www.open-open.com/lib/view/open1329995970842.html
 * 内部类Getpic
 */
    class Getpic {
	public  boolean saveUrlAs(String fileUrl, String savePath)
	{
		try {
			URL url = new URL(fileUrl);
			
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			DataInputStream in = new DataInputStream(connection.getInputStream());
			
			DataOutputStream out = new DataOutputStream(new FileOutputStream(savePath));
			
			byte[] buffer = new byte[4096];
			int count = 0;
			while ((count = in.read(buffer)) > 0)
			{
				out.write(buffer, 0, count);
			}
			out.close();
			in.close();
			connection.disconnect();
			return true;

		} catch (Exception e) {
			System.out.println(e + fileUrl + savePath);
			return false;
		}
	}
  }
}


posted on 2013-11-14 14:41  果冻虾仁  阅读(186)  评论(0编辑  收藏  举报

导航