上周看了西乔的博客“西乔的九卦”。《神秘的程序员们》系列漫画感觉很喜欢,很搞笑。这些漫画经常出现在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. ubuntu 下rar解压工具安装方法

    1.压缩功能安装 sudo apt-get install rar卸载 sudo apt-get remove rar2.解压功能安装 sudo apt-get install unrar卸载 sud ...

  2. PHP For Windows/php-5.6.11-Win32-VC11-x64启动脚本

    启动php-cgi.bat @echo off E: cd E:\php-5.6.11-Win32-VC11-x64 php-cgi.exe -b 127.0.0.1:9000 -c php.ini- ...

  3. linux 多个python版本的切换

    源码安装新的python版本,我的安装路径: /usr/self/Python3.5.2 修改软链接到你所安装的python版本中: 默认python命令是在/usr/bin/目录下 1 sudo m ...

  4. 洛谷P3368 【模板】树状数组 2

    P3368 [模板]树状数组 2 102通过 206提交 题目提供者HansBug 标签 难度普及/提高- 提交  讨论  题解 最新讨论 暂时没有讨论 题目描述 如题,已知一个数列,你需要进行下面两 ...

  5. http的响应对象

    Servlet 服务器 HTTP 响应 正如前面的章节中讨论的那样,当一个 Web 服务器响应一个 HTTP 请求时,响应通常包括一个状态行.一些响应报头.一个空行和文档.一个典型的响应如下所示: H ...

  6. 【EF学习笔记06】----------加载关联表的数据 延迟加载

    讲解之前,先来看一下我们的数据库结构:班级表 学生表 延迟加载 //延迟加载 using (var db = new Entities()) { //查询班级 var classes = (from ...

  7. noip2006 2^k进制数

    设r是个2k进制数,并满足以下条件: (1)r至少是个2位的2k进制数. (2)作为2k进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. (3)将r转换为2进制数q后,则q的总位数不超过w ...

  8. Android菜鸟成长记4-button点击事件

    Button 1.button按钮的创建 一般来说,在我们新建一个Android项目的时候,会有会默认有一个activity_main.xml的文件 如果你在新建项目的时候,把Create Activ ...

  9. afterTextChanged() callback being called without the text being actually changed

    afterTextChanged() callback being called without the text being actually changed up vote8down votefa ...

  10. anyexec

    http://www.codesec.net/view/420386.html http://www.cnblogs.com/qiyebao/p/5362101.html http://www.mon ...