解析出一个网页中所有的图片

题目是为了说明我这篇文章要实现的功能
实际上,知识点就是“正则表达式的介绍和使用”。

问题来源

在做项目的时候遇到了一个问题,就是如何从网页中解析所有的图片,注意!!!这里是“所有”。当时我的第一反应是立刻到网上寻找第三方库,但是,找到的最好的第三方库都和我的问题没有关系,最有关系的就是Java中知道的JavaScript脚本引擎ScriptEngine,可是看了半天还是没看懂这个引擎是在干嘛,所有并没有什么卵用。

既然网上没有现成的第三方库,那么就退而求其次,解析图片的没有,解析HTML的工具总会是有的吧,这里到网上随便搜一搜,就出来了一个工具HtmlParser,这个工具可以帮我们解析HTML正文,包括标签对里面的内容,比如balabala,可以解析balabala;也可以解析标签中的属性,比如可以解析img标签中的src属性,这就是一个图片的地址。

说到这里,似乎有了点头绪,总算有一些图片可以被解析出来了,就是提取img标签中的src属性中的地址,我就试着提取了一下,将提取出来的地址做了一下记录。然后用普通的文本编辑器,比如sublime,我把整个网页的源码粘贴到了编辑器中,搜索以.jpg”这五个连续字符,虽然这中方法很不严谨,但是依然可以粗略的观察到,我们所提取出来的图片地址远远少于整个网页中应该有的图片数量。继续在sublime编辑器里面观察,发现有大量的图片地址出现在JavaScript脚本中,因为我之前不熟悉JavaEE方面的开发,咋看之下存在于JavaScript脚本语言中的地址似乎是以JSON格式存放的,一分钟以后我就发现我想多了,那真的是地地道道的JavaScript。。。

前面说到我搜索了Java中的JavaScript脚本引擎的用法,原因就在这里。但是由于时间紧迫,不得不想一个稍微简单一点的办法,在同学的提议下,使用了正则表达式,准确来说是开始学习正则表达式了,这里要感叹一句,正则表达式不愧是一个很强大的工具。

程序的执行过程

    //下面是简单的通过代码来进行网络连接,写的不好,欢迎指责,这里不是武汉话说的韵炸子啊,真的是欢迎指责
    String url = request.getParameter("url");
    HttpURLConnection connection = (HttpURLConnection) new URL(url)
            .openConnection();
    connection.setReadTimeout(5000);
    connection.setRequestMethod("GET");
    connection.setDoInput(true);
    connection.connect();

    //下面是通过包装流来获取整个网页中的内容,一行一行的读取,并且进行一下处理
    BufferedReader reader = new BufferedReader(new InputStreamReader(
            connection.getInputStream()));
    StringBuffer buffer = new StringBuffer();
    String tmp = null;
    while ((tmp = reader.readLine()) != null) {
        buffer.append(tmp.replaceAll("\\s", "").trim());
    }
    //这里的result就是整个网页代码,去掉了空格和空白,并且拼成了一个字符串
    String result = buffer.toString();

    DataOutputStream dataOutputStream = new DataOutputStream(response.getOutputStream());
    //将正则表达式编译成一个模板,并且对所需要的字符串进行匹配,得到匹配类matcher
    Pattern pattern = Pattern
            .compile(
    "(https?:)?((\\/\\/)|(\\\\\\/\\\\\\/)){1}[\\w\\.\\/%\\=\\-\\&\\,\\\\]*?(jpg|png|jpeg){1}");
    Matcher matcher = pattern.matcher(result);
    ArrayList<String> list = new ArrayList<String>();

    //下面就是每find()一次就可以获取一个子串的开始索引和结束索引,然后用subString方法对子串进行截取,最后保存到一个容器中
    while(matcher.find()) {
        tmp = result.substring(matcher.start(), matcher.end());
        tmp = tmp.replaceAll("\\\\\\/", "/");
        list.add(tmp);
    }

    //下面是多文件传输相关的代码,在这里不是重点
    dataOutputStream.writeInt(list.size());

    for(int i = 0; i < list.size(); i ++) {
        dataOutputStream.writeUTF(list.get(i));
        dataOutputStream.flush();
    }

    dataOutputStream.close();
    reader.close();

三个需要学习的知识点

正则表达式的基本知识

虽然我很想向各位网友们分享我的见解,特别是初学者,但是我这篇文章的目的不是来讲正则表达式中的基本知识的,所以我向各位推荐一个慕课网的视频,这也是我入门正则表达式的视频,虽然使用的语言是PHP,但是换汤不换药,只是写法不同。
http://www.imooc.com/learn/350

Java中正则表达式的相关API

这里先介绍本文中需要使用的API和类

类名 说明
Pattern 我翻译的是正则表达式的模板类,使用静态的构造方法Pattern.compile(String s)来进行构造,执行这个方法之后获取一个Pattern,进行下一步的操作,本方法中传递的参数就是所需要的正则表达式
Matcher 我翻译的是正则表达式的匹配类,也是通过静态的方法得到,使用方法为pattern.matcher(String s),这个方法中的pattern是前一个类通过上述方法得到的pattern,本方法中的s为要匹配的字符串

为了避免读者还要去官方网站看英文API麻烦,我这里也列出方法的说明,也是为了给初学者节约时间

方法名 说明
boolean matches() 这个方法通过上面介绍的类中的Matcher的实例来调用,这个方法的作用是让正则表达式去匹配整个字符串,匹配的模式为贪婪匹配,至于什么是贪婪匹配,下面我会说明,其实也不难
boolean find() 这个方法同样通过matcher来调用,和matches()不同,这个方法是要找出符合正则表达式的子串
int start() 和上面的find()方法一起使用,每find一次,就可以通过matcher.start()方法来获取子串的其实索引
int end() 同于start(),获得的是子串的结束索引

正则表达式的构成

我的构成式比较冗长,但是我觉得可以真实的反应出我的思路。
Pattern pattern = Pattern
.compile(
"(https?:)?((\\/\\/)|(\\\\\\/\\\\\\/)){1}[\\w\\.\\/%\\=\\-\\&\\,\\\\]*?(jpg|png|jpeg){1}");

下面我将表达式分成几个部分来说明我的思路
1. 最前面的(https?:)?。这里是URL开头的协议,是http或者是https,而且这两者要么有,要么没有,对应的就是给出的地址是绝对地址还是相对地址。
2. 再就是之后的((\\/\\/)|(\\\\\\/\\\\\\/)){1}。很好理解,每个地址的http或者是https后面都要跟上//,但是由于“/”是正则表达式中的保留字符,在捕获组中会得到使用,所以,必须要执行转义。而后面为什么还要跟上很难看的(\\\\\\/\\\\\\/),这是因为,我发现在百度中搜索资源,得到的图片可能会是下面的一种奇怪的格式。
http:\/\/www.baidu.com\/afdsa\/fdafda.jpg
由于有了上面这种奇葩的格式,才诞生了上面一串奇怪的正则表达式(\\\\\\/\\\\\\/)
3. 再就是之后的[\\w\\.\\/%\\=\\-\\&\\,\\\\]*?,这里面规定了哪些字符是可以在URL中存在的,如果既在URL中允许存在,又是正则表达式中的保留字符,记得一定要进行转义。至于哪些是URL中的保留字符,可以参看知乎中的一个回答https://www.zhihu.com/question/24474922。还有后面的*?,这就是懒惰匹配,什么意思呢,很容易懂,就是如果你不加这个懒惰匹配,那么正则表达式默认的是贪婪匹配,那么会从整个字符串的第一个http一直匹配到整个字符串的最后一个jpg,这很明显是错的,使用了*?,那么就会匹配和任何一个http最近的右侧的jpg,这样就可以顺利的取出字串啦。
4. 最后一个(jpg|png|jpeg){1},看字面意思也能够猜出来,就是要以jpg或者png或者jpeg结尾即可。

猜你喜欢

转载自blog.csdn.net/u014713475/article/details/51550456