簡體   English   中英

Java中用於Web爬網程序的多線程DFS

[英]Multithreaded DFS for web crawler in Java

我正在使用Jsoup用Java編寫Web搜尋器。

目前,我有一個使用深度優先搜索的單線程實現(它只需要爬網一個域,因此我可以選擇DFS或BFS,並選擇DFS,因為這意味着我可以使用隊列而不是堆棧,並且因此,當我執行多線程版本時,請使用LinkedBlockingQueue

我有一個要訪問的鏈接Queue和一個已經訪問過的鏈接的HashSet ,我的主循環從隊列中彈出一個鏈接,訪問頁面,並將頁面中所有未訪問的鏈接添加到隊列中。

這是實現單線程實現的類的內容(如果任何throws聲明是虛假的,請讓我知道為什么,因為我需要解決這個問題)

private static LinkedBlockingQueue<String> URLSToCrawl = new LinkedBlockingQueue<String>();
private static String baseURL;
private static String HTTPSBaseURL;
private static HashSet<String> alreadyCrawledSet = new HashSet<String>();
private static List<String> deadLinks = new LinkedList<String>();

public static void main(String[] args) throws IOException, InterruptedException {

    // should output a site map, showing the static assets for each page. 

    Validate.isTrue(args.length == 1, "usage: supply url to fetch");

    baseURL = args[0];
    HTTPSBaseURL = baseURL.replace("http://", "https://");

    alreadyCrawledSet.add(baseURL);
    URLSToCrawl.add(baseURL);

    while (!URLSToCrawl.isEmpty() ) {
        String url = URLSToCrawl.take();
        crawlURL(url);
    }


}

private static void crawlURL(String url) throws IOException, InterruptedException {
    print("%s", url);
    try {
        Document doc = Jsoup.connect(url).get();
        Elements links = doc.select("a[href]");

        for (Element link : links) {
            String linkURL = link.attr("abs:href");
            if (sameDomain(linkURL) && !alreadyCrawled(linkURL)) {
                alreadyCrawledSet.add(linkURL);
                URLSToCrawl.put(linkURL);
            }
        }
    } catch (HttpStatusException e) {
        deadLinks.add(url);
    }
}   

private static boolean alreadyCrawled(String url) {
    if (alreadyCrawledSet.contains(url)) {
        return true;
    } else {
        return false;
    }
}

我想使用多線程,以利用單線程實現必須等待Jsoup.connect(url).get()調用中的HTTP請求返回然后繼續處理的Jsoup.connect(url).get() 我希望通過允許多個線程同時作用,可以在此I / O約束延遲期間完成一些工作,從而加快程序的速度。

我對並發不是很有經驗-我的第一個想法是簡單地創建一個Executor然后將每個對crawlURL調用提交給它。 但是我很困惑-我不知道如何確保以線程安全的方式訪問我的HashSetQueue ,特別是考慮到每個線程不僅消耗 Queue URL,還將新URL推送到Queue

我了解原子性概念的基礎,以及線程可以“鎖定”共享資源的想法,但是我不知道如何在這種情況下將它們付諸實踐。

有沒有人建議使這種多線程?

我的解決方案是一次處理一張圖表。 因此,對於每個級別,將每個鏈接提交到要爬網(多線程)的ExecutorService ,然后等待該級別完成(使用CountDownLatch ),然后再進入下一個級別。

我使用了FixedThreadPool作為速率限制的一種形式。

(最初,我試圖異步地分派每個URL,這必須更加有效,但我無法弄清楚如何終止整個過程。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM