上周看了西乔的博客“西乔的九卦”。《神秘的程序员们》系列漫画感觉很喜欢,很搞笑。这些漫画经常出现在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;
}
}
}
}

Java实现批量下载《神秘的程序员》漫画的更多相关文章

  1. java+文件批量下载

    这篇文章主要介绍了Java实现批量下载选中文件功能,非常不错,具有参考借鉴价值,需要的朋友可以参考下 1.在action中定义变量 private List<String> downLoa ...

  2. 《程序员漫画》| 萌新面试Google

    Hello,大家好.今天的更新有点不一样.我给大家带来了一些程序员漫画.这些都是我自己画的哦.希望大家喜欢. 今天的漫画有简约的画风,也有一些写实的风格(漂亮MM总是有特殊待遇).不知道大家喜欢哪种呢 ...

  3. java/resteasy批量下载存储在阿里云OSS上的文件,并打包压缩

    现在需要从oss上面批量下载文件并压缩打包,搜了很多相关博客,均是缺胳膊少腿,要么是和官网说法不一,要么就压缩包工具类不给出 官方API https://help.aliyun.com/documen ...

  4. [置顶] think in java interview番外篇-谈程序员如何修练英语

    一.程序员对英语能力的重视度和能力要求应该是在各行各业中排在比较靠前的 这样说吧,英语程度的好坏直接影响着一个程序员的编程.开发.创新能力. 道理很简单: 1. 计算机和软件是用英语创造出来的 2. ...

  5. JAVA内存关注总结,作为个程序员需要对自己系统的每块内存做到了如指掌

    服务器的JAVA进程使用的内存是否正常 服务器中,JAVA进程的内存占用= JVM内存+ JAVA堆最大内存大小(Xmx)+JAVA堆外内存大小+栈区( 线程数* Xss) 最需要关注: 1., 服务 ...

  6. Java进阶之路——从初级程序员到架构师,从小工到专家

    原创文章 怎样学习才能从一名Java初级程序员成长为一名合格的架构师,或者说一名合格的架构师应该有怎样的技术知识体系,这是不仅一个刚刚踏入职场的初级程序员也是工作三五年之后开始迷茫的老程序员经常会问到 ...

  7. Java实现批量下载选中文件功能

    1.在action中定义变量 ? 1 2 3 4 5 6 private List<String> downLoadPaths = new ArrayList<String>( ...

  8. java实现批量下载百度图片搜索到的图片

    就是写的个小程序,用于记录一下,方便后续查看,首先感谢下面这个博客,从这篇文章衍生的吧,大家可以学习下: http://www.cnblogs.com/lichenwei/p/4610298.html ...

  9. 基于Java实现批量下载网络图片

    昨天朋友做项目遇到一个需求,需要把上千个的微博表情图片下载到本地磁盘,并做好规范命名,塞给我一堆Json数据,让我帮忙处理下,反正闲着也没事干,就帮忙写了.(很简单的一个功能,随手记录下,刚好填补下最 ...

随机推荐

  1. springboot教程

    http://www.cnblogs.com/java-zhao/tag/spring-boot/ http://blog.csdn.net/liaokailin/article/category/5 ...

  2. C#中定义数组

    C#定义数组 一.一维:int[] numbers = new int[]{1,2,3,4,5,6}; //不定长 int[] numbers = new int[3]{1,2,3};//定长   二 ...

  3. UUID生成

    >>>Arch Linux # uuidgen From: http://os.51cto.com/art/200709/56613.htm >>>Debian j ...

  4. QBC分页查询

    1.第一种方式 public class DetailDaoImpl extends HibernateTemplate implements DetailDaoInterface { private ...

  5. U盘分区之后如何恢复

    操作步骤: 1.插入U盘. 2.按windows键,右键点击“运行”,再左键点击以管理员身份运行. 3.输入diskpart,按enter. 4.输入list disk,按enter. 5.之后会看到 ...

  6. dedecms代码研究五

    上一次留几个疑问: 1)DedeTagParse类LoadTemplet方法. 2)MakeOneTag到底在搞什么. 从DedeTagParse开始前面,我们一直在dedecms的外围,被各种全局变 ...

  7. 在python中处理XML

    XML是实现不同语言或程序之间进行数据交换的协议,XML文件格式如下: <data> <country name="Liechtenstein"> < ...

  8. SQL笔记-第八章,子查询

    一.SELECT列表中的标量子查询 查询每种书籍类型中的最早出版的书籍.在SQL 查询中,需要将一本书籍的出版年份与该类型的所有书籍的出版年份进行比较,并且仅仅在它们匹配时,才返回一个记录 SELEC ...

  9. 初学javaweb,远离各自框架

    OSCHINA 软件库有一个分类--Web框架,该分类中包含多种编程语言的将近500个项目. Web框架是开发者在使用某种语言编写Web应用服务端时关于架构的最佳实践.很多Web框架是从实际的Web项 ...

  10. eclipse与myeclipse恢复已删除的文件和代码

    1.类文件的恢复 选择项目后右键-->选择Restore from Local history-->出现下面的界面: 勾选后按Restore就恢复了,真的很强大很方便:但我没有就此罢手,我 ...