上周看了西乔的博客“西乔的九卦”。《神秘的程序员们》系列漫画感觉很喜欢,很搞笑。这些漫画经常出现在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. (转)原始图像数据和PDF中的图像数据

    比较原始图像数据和PDF中的图像数据,结果见表1.1.表1.1中各种“解码器”的解释见本文后续的“PDF支持的图像格式”部分,“PDF中的图像数据”各栏中的数据来自开源的PdfView.如果您有兴趣查 ...

  2. 通过dblink的方式查看表的结构

    有dba权限: SELECT * FROM DBA_TAB_COLUMNS@DBLINK_TEST WHERE TABLE_NAME = '表名'; 没有dba权限:SELECT * FROM USE ...

  3. No.1__C#

    这是第一篇C#的日记,到现在为止已经学习了一个礼拜的C#了.由于是实习中才开始学习,所以这次不准备像在大学学习那样,拿着课本划重点,背概念.这应当是一门实践的课程,应该一边编程,一边学.这是到公司第一 ...

  4. [VB.NET]取消按钮按下的默认事件响应

    大家应该有过这样的经历:有两个文本框a,b.通过编程,当我们在A中回车后,光标会移动到B文本框. 但是,不可避免的会听到一声“铛”的声音. 解决办法: 在Keydown或者KeyUp事件中,设置e.S ...

  5. BVT & BAT & SVT

    1. BVT(Build Verification Test) a. BVT概念 Build Verification test is a set of tests run on every new ...

  6. 做一个高效的IOS开发工程师

    最近觉得自己的开发效率太慢了,总结了一下:熟练度不够是一方面,经常用到东西查看一下,积累问题?一方面,这个无法分享的.现在主要分享的是:如何高效的用好自己的时间. 1.善用xcode. xcode实在 ...

  7. 删除sde用户问题

    删除SDE用户(GIS地图数据用户),长时间删除没反应,结束drop user sde cascade命令后,重新执行,结果报ORA-00604 ORA-21700 select user_id,us ...

  8. js图片变换

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. js 小工具-- 获取主机名

    <script type="text/javascript"> function getHostName(url) { var host = "null&qu ...

  10. Dictionary和IDictionary

    Dictionary<string> s = new Dictionary<string>(); 这个是s是Dictionary类型.是个类 类型,实现了接口,提供了更多的方法 ...