1. 程式人生 > >The wind of freedom blows

The wind of freedom blows

World Wide Web,縮寫WWW、W3或者Web,是一個因特網的相互連線的超文字文件。使用Web瀏覽器,可以檢視一個文件,以及跟隨超連結檢視其它文件。這裡,我們將開發一個簡單的程式,可以跟隨超連結來自動遍歷Web。這類程式通常稱為Web爬蟲。為簡單起見,我們的程式跟隨以http://開始的超連結。

在寫程式之前有必要了解一下什麼是URL(Uniform Resource Location),即Web上的檔案提供的唯一地址,可以叫做統一資源定位器,知道了這個便可以從Web上訪問資料。

為了讀取一個檔案,首先要使用java.net.URL類的構造方法,為該檔案建立一個URL物件。例如,下面給出的語句為http://www.google.com/index.html

建立一個URL物件。

try {
   URL url1=new URL("http://www.google.com/index.html");
}
catch (MalformedURLException ex) {
   ex.printStackTrace();
}

建立一個URL物件後,可以使用URL類中定義的openStream()方法來開啟輸入流和用輸入流建立Scanner物件。
Scanner input=new Scaner(url.openStream());

現在可以從輸入流讀取資料了,如同從本地檔案中讀取資料一樣。

如圖給出了一個遍歷Web的例子。從一個包含了三個分別名為URL1,URL2,URL3的網址的頁面開始,跟隨URL2將到達一個包含兩個名為URL21和URL22的網址的頁面,跟隨URL3將到達一個包含名為URL31、URL32、URL33、URL44的網址的頁面。可以繼續跟隨新的超連結對Web進行遍歷。這個過程可以一直進行下去,但是我們將在遍歷了100個頁面後退出程式。

這裡寫圖片描述

程式跟隨URL來遍歷Web。為保證每一個URL只被遍歷一次,程式包含兩個網址的列表。一個列表儲存將被遍歷的網址,另一個儲存已經被遍歷的網址。程式的演算法描述如下:

將起始URL新增到名為listOfPendingURLs的列表中;
    當listOfPendingURLs不為空並且listOfTraversedURLs的長度<=100 {
        從listOfPendingURLs移除一個URL;
        如果該URL不在listOfTraversedURLs中 {
            將其新增到listOfTraversedURLs中;
            顯示該URL;
            讀取該URL的頁面,並且對該頁面中包含的每個URL進行如下操作 {
                如果不在listOfPendingURLs中,則將其新增到listOfPendingURLs中;
            }
} }

實現該演算法的完整程式如下:

package com.company;

import java.util.Scanner;
import java.util.ArrayList;

public class WebCrawler {
    public static void main(String[] args) {
        java.util.Scanner input=new java.util.Scanner(System.in);
        System.out.print("Enter a URL: ");
        String url=input.nextLine();
        craweler(url);
    }

    public static void craweler(String startingURL) {
        ArrayList<String> listOfPendingURLs=new ArrayList<>();
        ArrayList<String> listOfTraversedURLs=new ArrayList<>();
//將起始的URL新增到listOfPendingURLs,然後通過一個while迴圈重複處理listOfPendingURLs中每一個URL
        listOfPendingURLs.add(startingURL);
        while(!listOfPendingURLs.isEmpty()&&listOfTraversedURLs.size()<=100) {
        //將列表中第一個RUL去除,如果該RUL沒有被處理過則對其進行處理
            String urlString=listOfPendingURLs.remove(0);
            if(!listOfTraversedURLs.contains(urlString)) {
                listOfTraversedURLs.add(urlString);
                System.out.println("Crawl"+urlString);
//程式使用foreach迴圈,將頁面中的每個不存在listOfTraversedURLs中的URL新增到listOfPendingURLs中
                for(String s:getSubURLs(urlString)) {
                    if(!listOfTraversedURLs.contains(s)) listOfPendingURLs.add(s);
                }

        }
        }
    }

    public static ArrayList<String> getSubURLs(String urlString) {
        //該方法為每個給定的URL返回一個URL列表
        ArrayList<String> list=new ArrayList<>();
        try {
            java.net.URL url=new java.net.URL(urlString);
            Scanner input=new Scanner(url.openStream());
            int current=0;
            while(input.hasNext()) {
                String line=input.nextLine();//從Web讀取每一行
                current=line.indexOf("http:",current);//尋找該行中的URL
                while(current>0) {
                    int endIndex=line.indexOf("\"",current);//假設URL以引號"結束
                    if(endIndex>0) {
                        list.add(line.substring(current,endIndex));//一行中可能包含多個URL,
                        current=line.indexOf("http:",endIndex);//方法繼續尋找下一個URL
                    }
                    else current=-1;//如果該行中沒有發現URL,curr設為-1
                }
            }
        }
        catch (Exception ex) {
            System.out.println("Error: "+ex.getMessage());
        }
        return list;//頁面中包含的URL以一個列表的形式返回
    }
}

執行結果如下:

這裡寫圖片描述