搜索Web爬行者

http://playfish.iteye.com/blog/150126

 

 

这是一个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>
下面是这个程序的源码

Java代码 复制代码
  1. import java.util.*;   
  2. import java.net.*;   
  3. import java.io.*;   
  4. import java.util.regex.*;   
  5.   
  6. // 搜索Web爬行者   
  7. public class SearchCrawler implements Runnable{   
  8.     
  9. /* disallowListCache缓存robot不允许搜索的URL。 Robot协议在Web站点的根目录下设置一个robots.txt文件,  
  10.   *规定站点上的哪些页面是限制搜索的。 搜索程序应该在搜索过程中跳过这些区域,下面是robots.txt的一个例子:  
  11.  # robots.txt for http://somehost.com/  
  12.    User-agent: *  
  13.    Disallow: /cgi-bin/  
  14.    Disallow: /registration # /Disallow robots on registration page  
  15.    Disallow: /login  
  16.   */  
  17.   
  18.   
  19.   private HashMap< String,ArrayList< String>> disallowListCache = new HashMap< String,ArrayList< String>>();    
  20.   ArrayList< String> errorList= new ArrayList< String>();//错误信息    
  21.   ArrayList< String> result=new ArrayList< String>(); //搜索到的结果    
  22.   String startUrl;//开始搜索的起点   
  23.   int maxUrl;//最大处理的url数   
  24.   String searchString;//要搜索的字符串(英文)   
  25.   boolean caseSensitive=false;//是否区分大小写   
  26.   boolean limitHost=false;//是否在限制的主机内搜索   
  27.      
  28.   public SearchCrawler(String startUrl,int maxUrl,String searchString){   
  29.    this.startUrl=startUrl;   
  30.    this.maxUrl=maxUrl;   
  31.    this.searchString=searchString;   
  32.   }   
  33.   
  34.    public ArrayList< String> getResult(){   
  35.        return result;   
  36.    }   
  37.   
  38.   public void run(){//启动搜索线程   
  39.          
  40.        crawl(startUrl,maxUrl, searchString,limitHost,caseSensitive);   
  41.   }   
  42.       
  43.   
  44.     //检测URL格式   
  45.   private URL verifyUrl(String url) {   
  46.     // 只处理HTTP URLs.   
  47.     if (!url.toLowerCase().startsWith("http://"))   
  48.       return null;   
  49.   
  50.     URL verifiedUrl = null;   
  51.     try {   
  52.       verifiedUrl = new URL(url);   
  53.     } catch (Exception e) {   
  54.       return null;   
  55.     }   
  56.   
  57.     return verifiedUrl;   
  58.   }   
  59.   
  60.   // 检测robot是否允许访问给出的URL.   
  61.  private boolean isRobotAllowed(URL urlToCheck) {    
  62.     String host = urlToCheck.getHost().toLowerCase();//获取给出RUL的主机    
  63.     //System.out.println("主机="+host);   
  64.   
  65.     // 获取主机不允许搜索的URL缓存    
  66.     ArrayList< String> disallowList =disallowListCache.get(host);    
  67.   
  68.     // 如果还没有缓存,下载并缓存。    
  69.     if (disallowList == null) {    
  70.       disallowList = new ArrayList< String>();    
  71.       try {    
  72.         URL robotsFileUrl =new URL("http://" + host + "/robots.txt");    
  73.         BufferedReader reader =new BufferedReader(new InputStreamReader(robotsFileUrl.openStream()));    
  74.   
  75.         // 读robot文件,创建不允许访问的路径列表。    
  76.         String line;    
  77.         while ((line = reader.readLine()) != null) {    
  78.           if (line.indexOf("Disallow:") == 0) {//是否包含"Disallow:"    
  79.             String disallowPath =line.substring("Disallow:".length());//获取不允许访问路径    
  80.   
  81.             // 检查是否有注释。    
  82.             int commentIndex = disallowPath.indexOf("#");    
  83.             if (commentIndex != - 1) {    
  84.               disallowPath =disallowPath.substring(0, commentIndex);//去掉注释    
  85.             }    
  86.                 
  87.             disallowPath = disallowPath.trim();    
  88.             disallowList.add(disallowPath);    
  89.            }    
  90.          }    
  91.   
  92.         // 缓存此主机不允许访问的路径。    
  93.         disallowListCache.put(host, disallowList);    
  94.       } catch (Exception e) {    
  95.               return true//web站点根目录下没有robots.txt文件,返回真   
  96.       }    
  97.     }    
  98.   
  99.         
  100.     String file = urlToCheck.getFile();    
  101.     //System.out.println("文件getFile()="+file);   
  102.     for (int i = 0; i < disallowList.size(); i++) {    
  103.       String disallow = disallowList.get(i);    
  104.       if (file.startsWith(disallow)) {    
  105.         return false;    
  106.       }    
  107.     }    
  108.   
  109.     return true;    
  110.   }    
  111.   
  112.   
  113.   
  114.     
  115.   private String downloadPage(URL pageUrl) {   
  116.      try {   
  117.         // Open connection to URL for reading.   
  118.         BufferedReader reader =   
  119.           new BufferedReader(new InputStreamReader(pageUrl.openStream()));   
  120.   
  121.         // Read page into buffer.   
  122.         String line;   
  123.         StringBuffer pageBuffer = new StringBuffer();   
  124.         while ((line = reader.readLine()) != null) {   
  125.           pageBuffer.append(line);   
  126.         }   
  127.            
  128.         return pageBuffer.toString();   
  129.      } catch (Exception e) {   
  130.      }   
  131.   
  132.      return null;   
  133.   }   
  134.   
  135.   // 从URL中去掉"www"   
  136.   private String removeWwwFromUrl(String url) {   
  137.     int index = url.indexOf("://www.");   
  138.     if (index != -1) {   
  139.       return url.substring(0, index + 3) +   
  140.         url.substring(index + 7);   
  141.     }   
  142.   
  143.     return (url);   
  144.   }   
  145.   
  146.   // 解析页面并找出链接   
  147.   private ArrayList< String> retrieveLinks(URL pageUrl, String pageContents, HashSet crawledList,   
  148.     boolean limitHost)   
  149.   {   
  150.     // 用正则表达式编译链接的匹配模式。   
  151.     Pattern p =Pattern.compile("<a\\s+href\\s*=\\s*\"?(.*?)[\"|>]",Pattern.CASE_INSENSITIVE);   
  152.     Matcher m = p.matcher(pageContents);   
  153.   
  154.        
  155.     ArrayList< String> linkList = new ArrayList< String>();   
  156.     while (m.find()) {   
  157.       String link = m.group(1).trim();   
  158.          
  159.       if (link.length() < 1) {   
  160.         continue;   
  161.       }   
  162.   
  163.       // 跳过链到本页面内链接。   
  164.       if (link.charAt(0) == '#') {   
  165.         continue;   
  166.       }   
  167.   
  168.          
  169.       if (link.indexOf("mailto:") != -1) {   
  170.         continue;   
  171.       }   
  172.         
  173.       if (link.toLowerCase().indexOf("javascript") != -1) {   
  174.         continue;   
  175.       }   
  176.   
  177.       if (link.indexOf("://") == -1){   
  178.         if (link.charAt(0) == '/') {//处理绝对地     
  179.           link = "http://" + pageUrl.getHost()+":"+pageUrl.getPort()+ link;   
  180.         } else {            
  181.           String file = pageUrl.getFile();   
  182.           if (file.indexOf('/') == -1) {//处理相对地址   
  183.             link = "http://" + pageUrl.getHost()+":"+pageUrl.getPort() + "/" + link;   
  184.           } else {   
  185.             String path =file.substring(0, file.lastIndexOf('/') + 1);   
  186.             link = "http://" + pageUrl.getHost() +":"+pageUrl.getPort()+ path + link;   
  187.           }   
  188.         }   
  189.       }   
  190.   
  191.       int index = link.indexOf('#');   
  192.       if (index != -1) {   
  193.         link = link.substring(0, index);   
  194.       }   
  195.   
  196.       link = removeWwwFromUrl(link);   
  197.   
  198.       URL verifiedLink = verifyUrl(link);   
  199.       if (verifiedLink == null) {   
  200.         continue;   
  201.       }   
  202.   
  203.       /* 如果限定主机,排除那些不合条件的URL*/  
  204.       if (limitHost &&   
  205.           !pageUrl.getHost().toLowerCase().equals(   
  206.             verifiedLink.getHost().toLowerCase()))   
  207.       {   
  208.         continue;   
  209.       }   
  210.   
  211.       // 跳过那些已经处理的链接.   
  212.       if (crawledList.contains(link)) {   
  213.         continue;   
  214.       }   
  215.   
  216.        linkList.add(link);   
  217.     }   
  218.   
  219.    return (linkList);   
  220.   }   
  221.   
  222.  // 搜索下载Web页面的内容,判断在该页面内有没有指定的搜索字符串   
  223.   
  224.   private boolean searchStringMatches(String pageContents, String searchString, boolean caseSensitive){   
  225.        String searchContents = pageContents;    
  226.        if (!caseSensitive) {//如果不区分大小写   
  227.           searchContents = pageContents.toLowerCase();   
  228.        }   
  229.   
  230.        
  231.     Pattern p = Pattern.compile("[\\s]+");   
  232.     String[] terms = p.split(searchString);   
  233.     for (int i = 0; i < terms.length; i++) {   
  234.       if (caseSensitive) {   
  235.         if (searchContents.indexOf(terms[i]) == -1) {   
  236.           return false;   
  237.         }   
  238.       } else {   
  239.         if (searchContents.indexOf(terms[i].toLowerCase()) == -1) {   
  240.           return false;   
  241.         }   
  242.       }     }   
  243.   
  244.     return true;   
  245.   }   
  246.   
  247.      
  248.   //执行实际的搜索操作   
  249.   public ArrayList< String> crawl(String startUrl, int maxUrls, String searchString,boolean limithost,boolean caseSensitive )   
  250.   {    
  251.        
  252.     System.out.println("searchString="+searchString);   
  253.     HashSet< String> crawledList = new HashSet< String>();   
  254.     LinkedHashSet< String> toCrawlList = new LinkedHashSet< String>();   
  255.   
  256.      if (maxUrls < 1) {   
  257.         errorList.add("Invalid Max URLs value.");   
  258.         System.out.println("Invalid Max URLs value.");   
  259.       }   
  260.      
  261.        
  262.     if (searchString.length() < 1) {   
  263.       errorList.add("Missing Search String.");   
  264.       System.out.println("Missing search String");   
  265.     }   
  266.   
  267.        
  268.     if (errorList.size() > 0) {   
  269.       System.out.println("err!!!");   
  270.       return errorList;   
  271.       }   
  272.   
  273.        
  274.     // 从开始URL中移出www   
  275.     startUrl = removeWwwFromUrl(startUrl);   
  276.   
  277.        
  278.     toCrawlList.add(startUrl);   
  279.     while (toCrawlList.size() > 0) {   
  280.          
  281.       if (maxUrls != -1) {   
  282.         if (crawledList.size() == maxUrls) {   
  283.           break;   
  284.         }   
  285.       }   
  286.   
  287.       // Get URL at bottom of the list.   
  288.       String url =  toCrawlList.iterator().next();   
  289.   
  290.       // Remove URL from the to crawl list.   
  291.       toCrawlList.remove(url);   
  292.   
  293.       // Convert string url to URL object.   
  294.       URL verifiedUrl = verifyUrl(url);   
  295.   
  296.       // Skip URL if robots are not allowed to access it.   
  297.       if (!isRobotAllowed(verifiedUrl)) {   
  298.         continue;   
  299.       }   
  300.   
  301.        
  302.       // 增加已处理的URL到crawledList   
  303.       crawledList.add(url);   
  304.       String pageContents = downloadPage(verifiedUrl);   
  305.   
  306.          
  307.       if (pageContents != null && pageContents.length() > 0){   
  308.         // 从页面中获取有效的链接   
  309.         ArrayList< String> links =retrieveLinks(verifiedUrl, pageContents, crawledList,limitHost);   
  310.         
  311.         toCrawlList.addAll(links);   
  312.   
  313.         if (searchStringMatches(pageContents, searchString,caseSensitive))   
  314.         {   
  315.           result.add(url);   
  316.           System.out.println(url);   
  317.         }   
  318.      }   
  319.   
  320.        
  321.     }   
  322.    return result;   
  323.   }   
  324.   
  325.   // 主函数   
  326.   public static void main(String[] args) {   
  327.      if(args.length!=3){   
  328.         System.out.println("Usage:java SearchCrawler startUrl maxUrl searchString");   
  329.         return;   
  330.      }   
  331.     int max=Integer.parseInt(args[1]);   
  332.     SearchCrawler crawler = new SearchCrawler(args[0],max,args[2]);   
  333.     Thread  search=new Thread(crawler);   
  334.     System.out.println("Start searching...");   
  335.     System.out.println("result:");   
  336.     search.start();   
  337.       
  338.   }   
  339. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值