在我的上一篇博客中,通过URL就已经成功下载了第一个页面。然后我第二步的工作就是要通过这个已经下载好的页面得到更多的URL。
在这篇博客中主要完成了对页面中的链接进行解析,并将它们拼成可以访问的样子。更多细致的工作需要在后面进行完善。
事实上,这个步骤并不一定需要依靠程序来完成。或许我们可以通过人工来完成这个步骤。甚至通过人工操作,我们可以得到更加相关的链接。但这对于我这样的程序员而言确实是太麻烦了,所以,我想我需要一个程序来帮我完成第二部分,就是从已经下载好的页面中获得新的URL链接。
完成这个步骤之后,就可以从上一篇博客的例子中进行页面的下载,并将下载后的页面读取之后进行页面内链接的提取,再下载,再提取,照这样下去,理论上来说就拥有了整个互联网上的所有页面了。
显而易见,下一步,也就是下一篇博客的内容就是讲这两个步骤整合到一个体系中,让它自己完成爬取工作了。
一、部分代码解析
1、使用正则表达式来匹配需要的链接
Pattern p = Pattern.compile("<a\\s+href\\s*=\\s*\"?(.*?)[\"|>]",Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(pageContents.toString());
通过上面这一小段代码可以将页面中"<a href="xxx.xxx" target="_blank" rel="external nofollow" >"中xxx.xxx匹配出来。
比如说,匹配http://www.csu.edu.cn/,可以得到如下结果:总计35条
... ...
3:xxgk.htm
4:jgsz.htm
5:http://rsc.its.csu.edu.cn/
6:jyjx.htm
......
32:http://news.its.csu.edu.cn/readnewsarticle?atcid=20140401113051853
33:http://news.its.csu.edu.cn/readnewsarticle?atcid=20140402084415418
34:http://news.its.csu.edu.cn/readnewsarticle?atcid=20140401150605872
35:
2、可以看到结果中存在空的链接和重复的链接等可能是不需要的链接(如:第35条),所以还必须在代码中进行判断。(筛选后剩下32条)
3、并且其中有一部分链接地址是相对链接,是不能够直接访问到资源的,如:jgsz.htm,这样的链接必须在前面加上域名、端口等。。
二、程序源代码
package csdnBlog;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 此类用于解析页面中存在的链接
*
* @author <span style="color:blue"><b>胡征南</b></span>
*
*/
public class RetrieveLinks {
public static void main(String[] args) {
String urlString = "http://www.csu.edu.cn/";
List<String> links = retrieveLinks(urlString);
for (int i = 0; i < links.size(); i++) {
System.out.println(i + 1 + ":" + links.get(i));
}
}
/**
* 解析链接
*
* @param urlString
* @return
*/
public static ArrayList<String> retrieveLinks(String urlString) {
URL url = null;
try {
url = new URL(urlString);
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
// 判断链接是否已经存在
HashSet<String> crawledList = new HashSet<String>();
StringBuffer pageContents = new StringBuffer();
try {
String fileName = "download.html";
FileInputStream fis = new FileInputStream(fileName);
byte[] buffer = new byte[1204];
while (fis.read(buffer) != -1) {
String temp = new String(buffer, "utf-8");
pageContents.append(temp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 正则表达式校验
Pattern p = Pattern.compile("<a\\s+href\\s*=\\s*\"?(.*?)[\"|>]",
Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(pageContents.toString());
// 用于保存查找到的链接
ArrayList<String> linkList = new ArrayList<String>();
while (m.find()) {
String link = m.group(1).trim();
// 判断链接是否合法
if (link.length() < 1) {
continue;
}
if (link.charAt(0) == '#') {
continue;
}
// 判断链接是否已经存在
if (crawledList.contains(link)) {
continue;
}
crawledList.add(link);
// 将相对地址添加完整
if (link.indexOf("://") == -1) {
link = "http://" + url.getHost()
+ (url.getPort() == -1 ? "" : ":" + url.getPort())
+ "/" + link;
}
linkList.add(link);
}
return linkList;
}
}
三、运行截图
图1. 控制台运行截图
图2. 工程目录截图
通过这种方式,就可以从已经下载好的页面中获得更多的链接了。
-------------------------------------------------------------------分割线,2014年4月16日更新--------------------------------------------------------------------------
1、将判断绝对地址的方式改为了使用正则表达式判断
更新代码如下:
package csdnBlog;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 此类用于解析页面中存在的链接
*
* @author <span style="color:blue"><b>胡征南</b></span>
*
*/
public class RetrieveLinks {
public static void main(String[] args) {
String urlString = "http://www.163.com/";
List<String> links = retrieveLinks(urlString);
for (int i = 0; i < links.size(); i++) {
System.out.println(i + 1 + ":" + links.get(i));
}
}
/**
* 解析链接
*
* @param urlString
* @return
*/
public static ArrayList<String> retrieveLinks(String urlString) {
URL url = null;
try {
url = new URL(urlString);
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
// 判断链接是否已经存在
HashSet<String> crawledList = new HashSet<String>();
StringBuffer pageContents = new StringBuffer();
try {
String fileName = Utils.urlToFileName(urlString);
FileInputStream fis = new FileInputStream(fileName);
byte[] buffer = new byte[1204];
while (fis.read(buffer) != -1) {
String temp = new String(buffer, "utf-8");
pageContents.append(temp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 正则表达式校验
Pattern p = Pattern.compile("<a\\s+href\\s*=\\s*\"?(.*?)[\"|>]",
Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(pageContents.toString());
// 用于保存查找到的链接
ArrayList<String> linkList = new ArrayList<String>();
while (m.find()) {
String link = m.group(1).trim();
// 判断链接是否合法
if (link.length() < 1) {
continue;
}
if (link.charAt(0) == '#') {
continue;
}
// 判断链接是否已经存在
if (crawledList.contains(link)) {
continue;
}
crawledList.add(link);
// 将相对地址添加完整
// (\w+\.){2}\w+
Pattern p2 = Pattern.compile("(\\w+\\.){2}\\w+");
Matcher m2 = p2.matcher(link);
if (!m2.find()) {
link = "http://" + url.getHost()
+ (url.getPort() == -1 ? "" : ":" + url.getPort())
+ link;
}
if (link.indexOf("http://") == -1 && link.indexOf("https://") == -1) {
link = "http://" + link;
}
linkList.add(link);
}
return linkList;
}
}
其中使用到的工具类可以在第一篇博客中找到。。点此返回 上一篇博客。。
相关代码资源下载地址:http://download.csdn.net/detail/huzhengnan/7203185