Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中web爬虫的多线程DFS_Java_Multithreading_Web Crawler_Executorservice_Depth First Search - Fatal编程技术网

Java中web爬虫的多线程DFS

Java中web爬虫的多线程DFS,java,multithreading,web-crawler,executorservice,depth-first-search,Java,Multithreading,Web Crawler,Executorservice,Depth First Search,我正在使用Jsoup用Java编写一个web爬虫程序 目前,我有一个使用深度优先搜索的单线程实现(它只需抓取一个域,这样我就可以选择DFS或BFS,并选择DFS,因为这意味着我可以使用队列而不是堆栈,因此在执行多线程版本时使用LinkedBlockingQueue) 我有一个队列的链接要访问,还有一个哈希集的已访问链接,我的主循环从队列中弹出一个链接,访问页面,并将页面中任何未访问的链接添加到队列中 这是我实现单线程实现的类的内容(如果任何抛出的声明都是虚假的,请告诉我原因,因为我需要解决这个问

我正在使用Jsoup用Java编写一个web爬虫程序

目前,我有一个使用深度优先搜索的单线程实现(它只需抓取一个域,这样我就可以选择DFS或BFS,并选择DFS,因为这意味着我可以使用队列而不是堆栈,因此在执行多线程版本时使用
LinkedBlockingQueue

我有一个
队列
的链接要访问,还有一个
哈希集
的已访问链接,我的主循环从队列中弹出一个链接,访问页面,并将页面中任何未访问的链接添加到队列中

这是我实现单线程实现的类的内容(如果任何
抛出的
声明都是虚假的,请告诉我原因,因为我需要解决这个问题)

private static LinkedBlockingQueue URLSToCrawl=new LinkedBlockingQueue();
私有静态字符串baseURL;
私有静态字符串HTTPSBaseURL;
私有静态HashSet alreadyCrawledSet=新HashSet();
private static List deadLinks=new LinkedList();
公共静态void main(字符串[]args)引发IOException、InterruptedException{
//应该输出一个站点地图,显示每个页面的静态资产。
isTrue(args.length==1,“用法:提供获取url”);
baseURL=args[0];
HTTPSBaseURL=baseURL.replace(“http://”、“https://”);
添加(baseURL);
URLSToCrawl.add(baseURL);
而(!URLSToCrawl.isEmpty()){
字符串url=URLSToCrawl.take();
爬网url(url);
}
}
私有静态void crawlURL(字符串url)引发IOException、InterruptedException{
打印(“%s”,url);
试一试{
Document doc=Jsoup.connect(url.get();
Elements links=doc.select(“a[href]”);
用于(元素链接:链接){
字符串linkURL=link.attr(“abs:href”);
if(sameDomain(linkURL)&&!alreadyCrawled(linkURL)){
添加(链接URL);
URLSToCrawl.put(linkURL);
}
}
}捕获(HttpStatus异常){
添加(url);
}
}   
私有静态布尔值alreadyCrawled(字符串url){
if(alreadyCrawledSet.contains(url)){
返回true;
}否则{
返回false;
}
}
我希望将此多线程化,以利用以下事实:单线程实现必须等待
Jsoup.connect(url).get()
调用中的HTTP请求返回,然后才能继续处理。我希望通过允许多个线程同时运行,可以在I/O限制延迟期间完成一些工作,从而加快程序的运行速度

我对并发性不是很有经验——我的第一个想法是简单地创建一个
Executor
,然后将每个调用提交给
crawurl
。但我感到困惑——我不知道如何确保以线程安全的方式访问我的
哈希集
队列
,特别是考虑到每个线程不仅使用
队列
中的URL,而且还将新URL推送到
队列

我了解原子性概念的基本知识,以及线程可以“锁定”共享资源的想法,但我不知道如何在这种情况下将它们付诸实践


有人对如何使这个多线程化有什么建议吗?

我的解决方案是一次处理一层图形。因此,对于每个级别,将每个链接提交到要爬网(多线程)的
ExecutorService
,然后等待该级别完成(使用
CountDownLatch
),然后再移动到下一级别

我使用
FixedThreadPool
作为速率限制的一种形式

(最初我尝试异步发送每个url,这必须更高效,但我不知道如何终止整个过程。)

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;
    }
}