这是一个web搜索的基本程序,从命令行输入搜索条件(起始的URL、处理url的最大数、要搜索的字符串),
它就会逐个对Internet上的URL进行实时搜索,查找并输出匹配搜索条件的页面。 这个程序的原型来自《java编程艺术》,
为了更好的分析,站长去掉了其中的GUI部分,并稍作修改以适用jdk1.5。以这个程序为基础,可以写出在互联网上搜索
诸如图像、邮件、网页下载之类的“爬虫”。
先请看程序运行的过程:

D:\java>javac SearchCrawler.java(编译)

D:\java>java SearchCrawler http://127.0.0.1:8080/zz3zcwbwebhome/index.jsp 20 java

Start searching...
result:
searchString=java
http://127.0.0.1:8080/zz3zcwbwebhome/index.jsp
http://127.0.0.1:8080/zz3zcwbwebhome/reply.jsp
http://127.0.0.1:8080/zz3zcwbwebhome/learn.jsp
http://127.0.0.1:8080/zz3zcwbwebhome/download.jsp
http://127.0.0.1:8080/zz3zcwbwebhome/article.jsp
http://127.0.0.1:8080/zz3zcwbwebhome/myexample/jlGUIOverview.htm
http://127.0.0.1:8080/zz3zcwbwebhome/myexample/Proxooldoc/index.html
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=301
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=297
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=291
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=286
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=285
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=284
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=276
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=272

又如:
D:\java>java SearchCrawler http://www.sina.com 20 java
Start searching...
result:
searchString=java
http://sina.com
http://redirect.sina.com/WWW/sinaCN/www.sina.com.cn class="a2"
http://redirect.sina.com/WWW/sinaCN/www.sina.com.cn class="a8"
http://redirect.sina.com/WWW/sinaHK/www.sina.com.hk class="a2"
http://redirect.sina.com/WWW/sinaTW/www.sina.com.tw class="a8"
http://redirect.sina.com/WWW/sinaUS/home.sina.com class="a8"
http://redirect.sina.com/WWW/smsCN/sms.sina.com.cn/ class="a2"
http://redirect.sina.com/WWW/smsCN/sms.sina.com.cn/ class="a3"
http://redirect.sina.com/WWW/sinaNet/www.sina.net/ class="a3"

D:\java>
下面是这个程序的源码

import java.util.*;
import java.net.*;
import java.io.*;
import java.util.regex.*;

// 搜索Web爬行者
public class SearchCrawler implements Runnable{

/* disallowListCache缓存robot不允许搜索的URL。 Robot协议在Web站点的根目录下设置一个robots.txt文件,
*规定站点上的哪些页面是限制搜索的。 搜索程序应该在搜索过程中跳过这些区域,下面是robots.txt的一个例子:
# robots.txt for http://somehost.com/
User-agent: *
Disallow: /cgi-bin/
Disallow: /registration # /Disallow robots on registration page
Disallow: /login
*/

private HashMap< String,ArrayList< String>> disallowListCache = new HashMap< String,ArrayList< String>>();
ArrayList< String> errorList= new ArrayList< String>();//错误信息
ArrayList< String> result=new ArrayList< String>(); //搜索到的结果
String startUrl;//开始搜索的起点
int maxUrl;//最大处理的url数
String searchString;//要搜索的字符串(英文)
boolean caseSensitive=false;//是否区分大小写
boolean limitHost=false;//是否在限制的主机内搜索

public SearchCrawler(String startUrl,int maxUrl,String searchString){
this.startUrl=startUrl;
this.maxUrl=maxUrl;
this.searchString=searchString;
}

public ArrayList< String> getResult(){
return result;
}

public void run(){//启动搜索线程

crawl(startUrl,maxUrl, searchString,limitHost,caseSensitive);
}

//检测URL格式
private URL verifyUrl(String url) {
// 只处理HTTP URLs.
if (!url.toLowerCase().startsWith("http://"))
return null;

URL verifiedUrl = null;
try {
verifiedUrl = new URL(url);
} catch (Exception e) {
return null;
}

return verifiedUrl;
}

// 检测robot是否允许访问给出的URL.
private boolean isRobotAllowed(URL urlToCheck) {
String host = urlToCheck.getHost().toLowerCase();//获取给出RUL的主机
//System.out.println("主机="+host);

// 获取主机不允许搜索的URL缓存
ArrayList< String> disallowList =disallowListCache.get(host);

// 如果还没有缓存,下载并缓存。
if (disallowList == null) {
disallowList = new ArrayList< String>();
try {
URL robotsFileUrl =new URL("http://" + host + "/robots.txt");
BufferedReader reader =new BufferedReader(new InputStreamReader(robotsFileUrl.openStream()));

// 读robot文件,创建不允许访问的路径列表。
String line;
while ((line = reader.readLine()) != null) {
if (line.indexOf("Disallow:") == 0) {//是否包含"Disallow:"
String disallowPath =line.substring("Disallow:".length());//获取不允许访问路径

// 检查是否有注释。
int commentIndex = disallowPath.indexOf("#");
if (commentIndex != - 1) {
disallowPath =disallowPath.substring(0, commentIndex);//去掉注释
}

disallowPath = disallowPath.trim();
disallowList.add(disallowPath);
}
}

// 缓存此主机不允许访问的路径。
disallowListCache.put(host, disallowList);
} catch (Exception e) {
return true; //web站点根目录下没有robots.txt文件,返回真
}
}

String file = urlToCheck.getFile();
//System.out.println("文件getFile()="+file);
for (int i = 0; i < disallowList.size(); i++) {
String disallow = disallowList.get(i);
if (file.startsWith(disallow)) {
return false;
}
}

return true;
}

private String downloadPage(URL pageUrl) {
try {
// Open connection to URL for reading.
BufferedReader reader =
new BufferedReader(new InputStreamReader(pageUrl.openStream()));

// Read page into buffer.
String line;
StringBuffer pageBuffer = new StringBuffer();
while ((line = reader.readLine()) != null) {
pageBuffer.append(line);
}

return pageBuffer.toString();
} catch (Exception e) {
}

return null;
}

// 从URL中去掉"www"
private String removeWwwFromUrl(String url) {
int index = url.indexOf("://www.");
if (index != -1) {
return url.substring(0, index + 3) +
url.substring(index + 7);
}

return (url);
}

// 解析页面并找出链接
private ArrayList< String> retrieveLinks(URL pageUrl, String pageContents, HashSet crawledList,
boolean limitHost)
{
// 用正则表达式编译链接的匹配模式。
Pattern p =Pattern.compile("<a\\s+href\\s*=\\s*\"?(.*?)[\"|>]",Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(pageContents);

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 (link.indexOf("mailto:") != -1) {
continue;
}

if (link.toLowerCase().indexOf("javascript") != -1) {
continue;
}

if (link.indexOf("://") == -1){
if (link.charAt(0) == '/') {//处理绝对地
link = "http://" + pageUrl.getHost()+":"+pageUrl.getPort()+ link;
} else {
String file = pageUrl.getFile();
if (file.indexOf('/') == -1) {//处理相对地址
link = "http://" + pageUrl.getHost()+":"+pageUrl.getPort() + "/" + link;
} else {
String path =file.substring(0, file.lastIndexOf('/') + 1);
link = "http://" + pageUrl.getHost() +":"+pageUrl.getPort()+ path + link;
}
}
}

int index = link.indexOf('#');
if (index != -1) {
link = link.substring(0, index);
}

link = removeWwwFromUrl(link);

URL verifiedLink = verifyUrl(link);
if (verifiedLink == null) {
continue;
}

/* 如果限定主机,排除那些不合条件的URL*/
if (limitHost &&
!pageUrl.getHost().toLowerCase().equals(
verifiedLink.getHost().toLowerCase()))
{
continue;
}

// 跳过那些已经处理的链接.
if (crawledList.contains(link)) {
continue;
}

linkList.add(link);
}

return (linkList);
}

// 搜索下载Web页面的内容,判断在该页面内有没有指定的搜索字符串

private boolean searchStringMatches(String pageContents, String searchString, boolean caseSensitive){
String searchContents = pageContents;
if (!caseSensitive) {//如果不区分大小写
searchContents = pageContents.toLowerCase();
}

Pattern p = Pattern.compile("[\\s]+");
String[] terms = p.split(searchString);
for (int i = 0; i < terms.length; i++) {
if (caseSensitive) {
if (searchContents.indexOf(terms[i]) == -1) {
return false;
}
} else {
if (searchContents.indexOf(terms[i].toLowerCase()) == -1) {
return false;
}
} }

return true;
}

//执行实际的搜索操作
public ArrayList< String> crawl(String startUrl, int maxUrls, String searchString,boolean limithost,boolean caseSensitive )
{

System.out.println("searchString="+searchString);
HashSet< String> crawledList = new HashSet< String>();
LinkedHashSet< String> toCrawlList = new LinkedHashSet< String>();

if (maxUrls < 1) {
errorList.add("Invalid Max URLs value.");
System.out.println("Invalid Max URLs value.");
}

if (searchString.length() < 1) {
errorList.add("Missing Search String.");
System.out.println("Missing search String");
}

if (errorList.size() > 0) {
System.out.println("err!!!");
return errorList;
}

// 从开始URL中移出www
startUrl = removeWwwFromUrl(startUrl);

toCrawlList.add(startUrl);
while (toCrawlList.size() > 0) {

if (maxUrls != -1) {
if (crawledList.size() == maxUrls) {
break;
}
}

// Get URL at bottom of the list.
String url = toCrawlList.iterator().next();

// Remove URL from the to crawl list.
toCrawlList.remove(url);

// Convert string url to URL object.
URL verifiedUrl = verifyUrl(url);

// Skip URL if robots are not allowed to access it.
if (!isRobotAllowed(verifiedUrl)) {
continue;
}

// 增加已处理的URL到crawledList
crawledList.add(url);
String pageContents = downloadPage(verifiedUrl);

if (pageContents != null && pageContents.length() > 0){
// 从页面中获取有效的链接
ArrayList< String> links =retrieveLinks(verifiedUrl, pageContents, crawledList,limitHost);

toCrawlList.addAll(links);

if (searchStringMatches(pageContents, searchString,caseSensitive))
{
result.add(url);
System.out.println(url);
}
}

}
return result;
}

// 主函数
public static void main(String[] args) {
if(args.length!=3){
System.out.println("Usage:java SearchCrawler startUrl maxUrl searchString");
return;
}
int max=Integer.parseInt(args[1]);
SearchCrawler crawler = new SearchCrawler(args[0],max,args[2]);
Thread search=new Thread(crawler);
System.out.println("Start searching...");
System.out.println("result:");
search.start();

}
}

注意 connection和inputstream都没有关闭的功能,变量也没有最后申明为null,导致内存消耗很大,也就是没有考虑到java的垃圾回收机制

ps: 这个爬虫我本人看了一次以后觉得很不错!

Java写的爬虫的基本程序的更多相关文章

  1. 《用Java写一个通用的服务器程序》02 监听器

    在一个服务器程序中,监听器的作用类似于公司前台,起引导作用,因此监听器花在每个新连接上的时间应该尽可能短,这样才能保证最快响应. 回到编程本身来说: 1. 监听器最好由单独的线程运行 2. 监听器在接 ...

  2. 《用Java写一个通用的服务器程序》01 综述

    最近一两年用C++写了好几个基于TCP通信类型程序,都是写一个小型的服务器,监听请求,解析自定义的协议,处理请求,返回结果.每次写新程序时都把老代码拿来,修改一下协议解析部分和业务处理部分,然后就一个 ...

  3. 《用Java写一个通用的服务器程序》03 处理新socket

    在讲监听器时说过处理的新的socket要尽快返回,监听器调用的是ClientFactory的createPhysicalConnection方法,那么就来看这个方法: public boolean c ...

  4. 【转】零基础写Java知乎爬虫之进阶篇

    转自:脚本之家 说到爬虫,使用Java本身自带的URLConnection可以实现一些基本的抓取页面的功能,但是对于一些比较高级的功能,比如重定向的处理,HTML标记的去除,仅仅使用URLConnec ...

  5. 五:用JAVA写一个阿里云VPC Open API调用程序

    用JAVA写一个阿里云VPC Open API调用程序 摘要:用JAVA拼出来Open API的URL 引言 VPC提供了丰富的API接口,让网络工程是可以通过API调用的方式管理网络资源.用程序和软 ...

  6. 终于解决了用JAVA写窗口程序在不同的windows界面下的显示保持一致。

    好像是两三年前的时候发现这个问题. 由于在windows经典界面与windows xp界面下,窗口的标题栏的高度是不一样的. 所以我们在用Java写GUI程序的时候,会遇到一个问题. 当我把一个JFr ...

  7. 用JAVA写一个多线程程序,写四个线程,其中二个对一个变量加1,另外二个对一个变量减1

    package com.ljn.base; /** * @author lijinnan * @date:2013-9-12 上午9:55:32 */ public class IncDecThrea ...

  8. Java豆瓣电影爬虫——抓取电影详情和电影短评数据

    一直想做个这样的爬虫:定制自己的种子,爬取想要的数据,做点力所能及的小分析.正好,这段时间宝宝出生,一边陪宝宝和宝妈,一边把自己做的这个豆瓣电影爬虫的数据采集部分跑起来.现在做一个概要的介绍和演示. ...

  9. 基于java的网络爬虫框架(实现京东数据的爬取,并将插入数据库)

    原文地址http://blog.csdn.net/qy20115549/article/details/52203722 本文为原创博客,仅供技术学习使用.未经允许,禁止将其复制下来上传到百度文库等平 ...

随机推荐

  1. jQuery基础 -- 如何判断页面元素存在与否

    在传统的Javascript里,当我们对某个页面元素进行某种操作前,最好先判断这个元素是否存在.原因是对一个不存在的元素进行操作是不允许的.例如: document.getElementById(&q ...

  2. Device Path in WinPrefetchView

    As we know that the Prefetch file is used for optimizing the loading time of the application in the ...

  3. ORACLE SQL前端补0的三种方式。

    前端补0的三种方式. select lpad(sal,8,'0') from emp;select to_char(sal,'00000000') from emp;select substr('00 ...

  4. oracle 认证方式

    Oracle登录的时候有两种认证方式,一种是“操作系统认证”,一种是“口令文件认证”.1.当采取操作系统认证的时候,在本地用任何用户都可以以sysdba登陆:(默认方式)2.当采取口令文件认证的时候, ...

  5. (http://fonts.googleapis.com/css?)打开很慢解决方案

    把fonts.googleapis.com替换为fonts.useso.com即可

  6. Python 前端之JS

    JavaScript由浏览器编译运行 JS的导入方式有两种,一种直接定义,第二种通过src引入:可以存放在<head>头部,但是强烈建议放在<body>的最下面,因为如果你引入 ...

  7. 第一零二天上课 PHP TP框架 引入文件路径问题和调用验证码的方式

    外部文件引入到视图模板的方式       1,将外部文件放在Public文件夹下,用load标签引入       2,在模板出书写引入代码(方法有很多,只有以下方法不容易出问题) <load h ...

  8. C++ MFC获取软件运行目录 (包含软件名)

    TCHAR *path = new TCHAR[MAX_PATH];   GetModuleFileName(NULL,path,MAX_PATH); AfxMessageBox(path);

  9. [wechall] Time to Reset (Exploit, Coding, PHP)

    Time to Reset (Exploit, Coding, PHP) <?php $start=1453000000; $cstf="nipNlJ6ZQPuGQ3i90QUTP8J ...

  10. Android Studio鼠标悬停显示注释

    Android Studio鼠标悬停显示注释 在AS中配置 如果你想从网上查看注释,到这一步就操作完成. 下面说明让软件使用本地注释: 使用本地注释 以Windows为例: 找到下面文件 C:\Use ...