程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java爬蟲實戰抓取一個網站上的全體鏈接

Java爬蟲實戰抓取一個網站上的全體鏈接

編輯:關於JAVA

Java爬蟲實戰抓取一個網站上的全體鏈接。本站提示廣大學習愛好者:(Java爬蟲實戰抓取一個網站上的全體鏈接)文章只能為提供參考,不一定能成為您想要的結果。以下是Java爬蟲實戰抓取一個網站上的全體鏈接正文


媒介:寫這篇文章之前,重要是我看了幾篇相似的爬蟲寫法,有的是用的隊列來寫,感到不是很直不雅,還有的只要一個要求然落後行頁面解析,基本就沒有主動爬起來這也叫爬蟲?是以我聯合本身的思緒寫了一下簡略的爬蟲。

一 算法簡介

法式在思緒上采取了廣度優先算法,對未遍歷過的鏈接逐次提議GET要求,然後對前往來的頁面用正則表達式停止解析,掏出個中未被發明的新鏈接,參加聚集中,待下一次輪回時遍歷。

詳細完成上應用了Map<String, Boolean>,鍵值對分離是鏈接和能否被遍歷標記。法式中應用了兩個Map聚集,分離是:oldMap和newMap,初始的鏈接在oldMap中,然後對oldMap外面的標記為false的鏈接提議要求,解析頁面,用正則掏出<a>標簽下的鏈接,假如這個鏈接未在oldMap和newMap中,則解釋這是一條新的鏈接,同時如果這條鏈接是我們須要獲得的目的網站的鏈接的話,我們就將這條鏈接放入newMap中,一向解析下去,等這個頁面解析完成,把oldMap中以後頁面的那條鏈接的值設為true,表現曾經遍歷過了。

最初是當全部oldMap未遍歷過的鏈接都遍歷停止後,假如發明newMap不為空,則解釋這一次輪回有新的鏈接發生,是以將這些新的鏈接參加oldMap中,持續遞歸遍歷,反之則解釋此次輪回沒有發生新的鏈接,持續輪回下去曾經不克不及發生新鏈接了,由於義務停止,前往鏈接聚集oldMap

二 法式完成

下面相干思緒曾經說得很清晰了,而且代碼中症結處所有正文,是以這裡就不多說了,代碼以下:

package action;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class WebCrawlerDemo {
 public static void main(String[] args) {
    WebCrawlerDemo webCrawlerDemo = new WebCrawlerDemo();
    webCrawlerDemo.myPrint("http://www.zifangsky.cn");
  }
 
  public void myPrint(String baseUrl) {
    Map<String, Boolean> oldMap = new LinkedHashMap<String, Boolean>(); // 存儲鏈接-能否被遍歷
                                      // 鍵值對
    String oldLinkHost = ""; //host
 
    Pattern p = Pattern.compile("(https?://)?[^/\\s]*"); //好比:http://www.zifangsky.cn
    Matcher m = p.matcher(baseUrl);
    if (m.find()) {
      oldLinkHost = m.group();
    }
 
    oldMap.put(baseUrl, false);
    oldMap = crawlLinks(oldLinkHost, oldMap);
    for (Map.Entry<String, Boolean> mapping : oldMap.entrySet()) {
      System.out.println("鏈接:" + mapping.getKey());
 
    }
 
  }
 
  /**
   * 抓取一個網站一切可以抓取的網頁鏈接,在思緒上應用了廣度優先算法
   * 對未遍歷過的新鏈接赓續提議GET要求,一向到遍歷完全個聚集都沒能發明新的鏈接
   * 則表現不克不及發明新的鏈接了,義務停止
   * 
   * @param oldLinkHost 域名,如:http://www.zifangsky.cn
   * @param oldMap 待遍歷的鏈接聚集
   * 
   * @return 前往一切抓取到的鏈接聚集
   * */
  private Map<String, Boolean> crawlLinks(String oldLinkHost,
      Map<String, Boolean> oldMap) {
    Map<String, Boolean> newMap = new LinkedHashMap<String, Boolean>();
    String oldLink = "";
 
    for (Map.Entry<String, Boolean> mapping : oldMap.entrySet()) {
      System.out.println("link:" + mapping.getKey() + "--------check:"
          + mapping.getValue());
      // 假如沒有被遍歷過
      if (!mapping.getValue()) {
        oldLink = mapping.getKey();
        // 提議GET要求
        try {
          URL url = new URL(oldLink);
          HttpURLConnection connection = (HttpURLConnection) url
              .openConnection();
          connection.setRequestMethod("GET");
          connection.setConnectTimeout(2000);
          connection.setReadTimeout(2000);
 
          if (connection.getResponseCode() == 200) {
            InputStream inputStream = connection.getInputStream();
            BufferedReader reader = new BufferedReader(
                new InputStreamReader(inputStream, "UTF-8"));
            String line = "";
            Pattern pattern = Pattern
                .compile("<a.*?href=[\"']?((https?://)?/?[^\"']+)[\"']?.*?>(.+)</a>");
            Matcher matcher = null;
            while ((line = reader.readLine()) != null) {
              matcher = pattern.matcher(line);
              if (matcher.find()) {
                String newLink = matcher.group(1).trim(); // 鏈接
                // String title = matcher.group(3).trim(); //題目
                // 斷定獲得到的鏈接能否以http開首
                if (!newLink.startsWith("http")) {
                  if (newLink.startsWith("/"))
                    newLink = oldLinkHost + newLink;
                  else
                    newLink = oldLinkHost + "/" + newLink;
                }
                //去除鏈接末尾的 /
                if(newLink.endsWith("/"))
                  newLink = newLink.substring(0, newLink.length() - 1);
                //去重,而且拋棄其他網站的鏈接
                if (!oldMap.containsKey(newLink)
                    && !newMap.containsKey(newLink)
                    && newLink.startsWith(oldLinkHost)) {
                  // System.out.println("temp2: " + newLink);
                  newMap.put(newLink, false);
                }
              }
            }
          }
        } catch (MalformedURLException e) {
          e.printStackTrace();
        } catch (IOException e) {
          e.printStackTrace();
        }
 
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        oldMap.replace(oldLink, false, true);
      }
    }
    //有新鏈接,持續遍歷
    if (!newMap.isEmpty()) {
      oldMap.putAll(newMap);
      oldMap.putAll(crawlLinks(oldLinkHost, oldMap)); //因為Map的特征,不會招致湧現反復的鍵值對
    }
    return oldMap;
  }
}

三 最初的測試後果

PS:其適用遞歸這類方法不是太好,由於如果網站頁面比擬多的話,法式運轉時光長了對內存的消費會異常年夜

感激浏覽,願望能贊助到年夜家,感謝年夜家對本站的支撐!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved