[英]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
調用提交給它。 但是我很困惑-我不知道如何確保以線程安全的方式訪問我的HashSet
和Queue
,特別是考慮到每個線程不僅消耗 Queue
URL,還將新URL推送到Queue
。
我了解原子性概念的基礎,以及線程可以“鎖定”共享資源的想法,但是我不知道如何在這種情況下將它們付諸實踐。
有沒有人建議使這種多線程?
我的解決方案是一次處理一張圖表。 因此,對於每個級別,將每個鏈接提交到要爬網(多線程)的ExecutorService
,然后等待該級別完成(使用CountDownLatch
),然后再進入下一個級別。
我使用了FixedThreadPool
作為速率限制的一種形式。
(最初,我試圖異步地分派每個URL,這必須更加有效,但我無法弄清楚如何終止整個過程。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.