java网络爬虫:

来源:互联网 发布:mac怎么切换独立显卡 编辑:程序博客网 时间:2024/05/17 16:57
需要导入jar包:
commons-httpclient-3.1.jar
htmlparser.jar

import java.io.FileOutputStream;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.Queue;

import org.apache.commons.httpclient.HttpClient;

import org.apache.commons.httpclient.HttpMethod;

import org.apache.commons.httpclient.HttpStatus;

import org.apache.commons.httpclient.methods.GetMethod;

/**

 * 下载类 完成 下载给定URL的网页

 * 实现下载函数 download()

 */

public class DownloadPage implements Runnable{

   int statusCode = 200;         // 执行 下载返回的状态码200为执行成功

   String path = "";            // 下载之后保存的本地地址

// HttpClient httpClient;       // 用于执行下载的 httpClient

   String url = "";         // 要下载的地址

   Queue<String> newPath;

   public DownloadPage(String url, Queue<String> table){

      this.url = url;

      newPath = table;

   }

   /**

    * 下载制定URL的网页

    * @param url 下载地址

    * @return 本地地址

    */

   public void download() {

      try {

         HttpClient httpClient = new HttpClient();

         InputStream input = null;

         OutputStream output = null// 初始化 输入输出流

         HttpMethod  getMethod = new GetMethod(url);

         statusCode = httpClient.executeMethod(getMethod);   

         if (statusCode == HttpStatus.SC_OK) {// 针对状态码200进行处理

            input = getMethod.getResponseBodyAsStream(); // 将得到的返回用流表达  

//           String filename = path.substring(path.lastIndexOf('/')+1); //得到文件名   

            path = "e:\\" + (Spider.i++) +".html";

             output = new FileOutputStream(path); // 获得文件输出流     

             int tempByte = -1;

             while((tempByte=input.read())>0){ // 输出到文件

                output.write(tempByte);       // 开始写

            }                 

            input.close();

            output.close();// 关闭输入输出流

         }

         updateGetPageURL();

       }         

      catch (Exception e) {

         e.printStackTrace();

      }

   }

   /**

    * start 执行的方法

    */

    public void run(){

       download();

    }

    public synchronized void updateGetPageURL(){

       newPath.add(path);

    }

}


import java.util.Iterator;

import java.util.LinkedList;

import java.util.Queue;

import org.htmlparser.Parser;

import org.htmlparser.filters.NodeClassFilter;

import org.htmlparser.tags.LinkTag;

import org.htmlparser.util.NodeList;

import org.htmlparser.util.ParserException;

/**

 * 下载类 包含 一个文件路径和一个 URL链表

 * 实现 了从 一个html文件中获取 超链接的功能

 */

public class GetPageURL implements Runnable{

    Queue<String> pageToGetURL// 带分析的 网页 路径队列

    URLQueue urlQueue;      //  得到的 URL 加入该队列中

    /**

     * 构造方法

     * @param urlQueue

     */

    public GetPageURL(URLQueue urlQueue){

       pageToGetURL = new LinkedList<String>(); // 实例化网页路径队列

       this.urlQueue = urlQueue;                // 接收 存储 URL的队列

    }

    /**

     * 最重要的一个函数从给定的html文件中获取URL

     */

   public void getURLFromFile(String filePath){

      NodeList nodeList = null;

      try{

         Parser parser = new Parser(filePath); // 分析类parser 将会把网页分析成树

         parser.setEncoding("GB2312");         // 设置编码格式

         nodeList = parser.parse(new NodeClassFilter(LinkTag.class)); // 根据过滤器的要求分析html 形成节点

      }                                                 // 要求tag  LinkTag 即我们要求的超链接

      catch(ParserException e){

         e.printStackTrace();

      }

      if(nodeList != null && nodeList.size() > 0){ // 遍历 节点

        

         String urlLink;

         for(int i = 0;i < nodeList.size();i++){

            urlLink  = ((LinkTag)nodeList.elementAt(i)).extractLink(); // 得到超链接

            String linkName = ((LinkTag)nodeList.elementAt(i)).getLinkText();  // 得到超链接的名字即在网页显示的展现

            urlLink = URLUtility.Encode(urlLink);

            urlQueue.add(urlLink);                                         // 添加到 ArrayList 里面

            System.out.println(linkName+":"+urlLink);

         }

      }

   }

   /**

    * 为了方便测试添加的打印函数

    * 完成打印已经分析完成的超链接功能

    */

   public void print(){

      Iterator<String> urlIterator = pageToGetURL.iterator(); // 设置迭代器

      while(urlIterator.hasNext()){

         System.out.println(urlIterator.next());    

      }

   }

   /**

    * start 执行的方法

    */

   public void run(){

      try{

         String filePath = null;

         while(true){

            if(pageToGetURL.isEmpty()){        // 如果队列为空的话则暂停1S然后继续检查

                Thread.sleep(1000);

                continue;

            }

            while(!pageToGetURL.isEmpty()){               

                filePath = pageToGetURL.poll();// 从队列中取出来一个路径

                getURLFromFile(filePath);      // 从该文件中获取URL

            }

         }

      }

      catch(Exception e){

         e.printStackTrace();

      }

   }

}


import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

/**

 * 主类 Spider 实现多线程爬虫

 */

public class Spider implements Runnable{

   URLQueue urlQueue;    // 放置URL的队列

   GetPageURL getPageURL;  // 从下载页面中获取URL

   private static int NumberofMaxThreads = 4; // 线程池中线程的最大个数

   static int i = 1;       // 用于对网页进行编号

   /**

    * 构造方法

    * @param url

    */

   public Spider(String url){

      urlQueue = new URLQueue();           // 实例化 URLQueue

      urlQueue.add(url);                // 初始化 URLQueue

      getPageURL = new GetPageURL(urlQueue);  // 实例化 GetPageURL

      new Thread(getPageURL).start();      // 开始运行 GetPageURL

   }

   /**

    * 实现Runnablerun方法

    */

   public void run(){

      ExecutorService pool = null;         // 声明线程池

      try{

         pool = Executors.newFixedThreadPool(NumberofMaxThreads); // 实例化一个确定的线程池

          while (true) {

             if(!urlQueue.isEmpty()){// 如果 队列不为空的话 则从线程池中开启一个线程

                DownloadPage download = new DownloadPage(urlQueue.get(),getPageURL.pageToGetURL);

                pool.execute(download);  //URL交给下载类

             }        

             else{

                Thread.sleep(2000); // 如果队列不为空的话 sleep 2S 再次运行

                continue;

             }              

         }       

      }

      catch(Exception e){

         e.printStackTrace();

//       System.exit(0);

      }

      finally{pool.shutdown();}     

   }

   public static void main(String []args){

      Spider spider = new Spider("http://news.baidu.com/");

      Thread t = new Thread(spider);

      t.start();

   }

}


import java.util.ArrayList;

import java.util.HashSet;

import java.util.Iterator;

import java.util.LinkedList;

import java.util.Queue;

/**

 * 队列类 包含 一个队列和一个 哈希集合

 * 实现 添加元素 读取元素 是否为空等函数

 */

public class URLQueue {

   private Queue<String> urlQueue;     // URL的队列 爬虫将从此队列中取得下一个下载的地址

   private HashSet<String> visitedURL// 已经访问过的地址集合 每次添加的需要根据此集合进行判断

   /**

    * 构造方法 初始化 队列和 集合

    */

   public URLQueue(){

      urlQueue = new LinkedList<String>();

      visitedURL = new HashSet<String>();

   }

   /**

    * 向队列中添加一个地址

    * @param url

    * @return

    */

   public boolean add(String url){

      if(visitedURL.contains(url)){ // 如果已经访问过 则不添加返回

         return false;

      }

      urlQueue.offer(url); // 添加到队列中

      return true;

   }

   /**

    * 添加一系列的地址 根据需要所添加的函数

    * @param urls

    */

   public void add(ArrayList<String> urls){

      Iterator<String> urlIterator = urls.iterator();

      while(urlIterator.hasNext()){

         add(urlIterator.next());

      }

   }

   /**

    * 返回 是否为空

    * @return

    */

   public boolean isEmpty(){

      return urlQueue.isEmpty();

   }

   /**

    * 返回一个元素

    * @return

    */

   public String get(){

      String firstMember = urlQueue.poll();// 从队列中读取第一个地址数据

      if(!visitedURL.contains(firstMember)){  // 将该即将被访问的地址加入到已经访问的集合中

         visitedURL.add(firstMember);       

      }

      return firstMember;

   }

   /**

    * 返回 队列的长度

    * @return

    */

   public int size(){

      return urlQueue.size();// 返回队列的大小

   }

}

 

import java.io.UnsupportedEncodingException;

import java.net.URLEncoder;

import java.util.regex.Pattern;

public class URLUtility {

   private static String m_urlPatternString = "(?i)(?s)<\\s*?a.*?href=\"(.*?)\".*?>";

   private static Pattern m_urlPattern = Pattern.compile(m_urlPatternString);

   /**

    * "url"变为编码为合法的URL

    */

   public static String Encode(String url) {

      String res = "";

      for(char c : url.toCharArray()) {

         if( !":/.?&#=".contains("" + c) ) {// 这些字符不能出现于URL

            try {

                res += URLEncoder.encode("" + c, "UTF-8"); // 转成UTF-8

            } catch (UnsupportedEncodingException e){}

         } else {

            res += c;

         }

      }

      return res;

   }

   public static String Normalizer(String url) {

      url = url.replaceAll("&amp;""&");

      if( url.endsWith("/") ) {

         url = url.substring(0, url.length() - 1);

      }

      return url;

   }

   //拼接URL

   public static String Refine(String baseUrl, String relative) {

      if( baseUrl == null || relative == null ) {

         return null;

      }

     

      final Url base = Parse(baseUrl), url = Parse(relative);   

      if( base == null || url == null ) {

         return null;

      }

     

      if( url.scheme == null ) {

         url.scheme = base.scheme;

         if( url.host == null ) {

            url.host = base.host;

         }

      }

      if( url.path.startsWith("../") ) {

         String prefix = "";

         int idx = base.path.lastIndexOf('/');

         if( (idx = base.path.lastIndexOf('/', idx - 1)) > 0 ) prefix = base.path.substring(0, idx);

         url.path = prefix + url.path.substring(3);       

      }                          

      return Normalizer(url.ToUrl());

   }

   //拆分URLscheme, host, path

   private static Url Parse(String link) {

      int idx, endIndex;

      final Url url = new Url(); 

     

      if( (idx = link.indexOf("#")) >= 0 ) {  //ignore fragment

         if( idx == 0 ) return null;

         else           link = link.substring(0, idx - 1);

      }

      if( (idx = link.indexOf(":")) > 0 ) {

         url.scheme = link.substring(0, idx).trim();

         ifIsLegalScheme(url.scheme) ) {

            link = link.substring(idx + 1);

         }

         else {

            return null;

         }

      }

      if( link.startsWith("//") ) {

         if( (endIndex = link.indexOf('/', 2)) > 0 ) {

            url.host = link.substring(2, endIndex).trim();

            link = link.substring(endIndex + 1);

         }

         else {

            url.host = link.substring(2).trim();

            link = null;

         }

      }

      if( link != null )

         url.path = link.trim();

      else              

         url.path = "";

     

      return url;    

   }

   /**

    * 判断scheme是否合法(要处理的scheme类型)

    */

   private static boolean IsLegalScheme(String scheme) {

      if( scheme.equals("http") || scheme.equals("https") || scheme.equals("ftp") )

         return true;

      else                                                                      

         return false;

   } 

   private static class Url {

      public Url() {}

      public String ToUrl() {

         String prefix = null;

         ifpath.startsWith("/") )

            prefix =  scheme + "://" + host;

         else                 

            prefix =  scheme + "://" + host + "/";

         return prefix + path;

      }

      public String scheme;

      public String host;

      public String path;

   }

}









0 0