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>

其中包含有图片地址。用buffer的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;
}
}
}
}
上一篇:腾讯大规模Hadoop集群实践 [转程序员杂志]


下一篇:jmeter压测