Параллелизм рекурсивного Webcrawler-алгоритма в Java

голоса
-1

Я написал программу на Java, чтобы найти все страницы веб-сайта, начиная с URL на начальную страницу (с помощью Jsoup в WebCrawler). Это нормально для небольших сайтов, но слишком медленно для сайтов с 200 или более страниц:

public class SiteInspector {

private ObservableSet<String> allUrlsOfDomain; // all URLS found for site
private Set<String> toVisit; // pages that were found but not visited yet
private Set<String> visited; // URLS that were visited
private List<String> invalid; // broken URLs

public SiteInspector() {...}

public void getAllWebPagesOfSite(String entry) //entry must be startpage of a site
{
    toVisit.add(entry);
    allUrlsOfDomain.add(entry);
    while(!toVisit.isEmpty())
    {
        String next = popElement(toVisit);
        getAllLinksOfPage(next);  //expensive
        toVisit.remove(next);
    }
}


public void getAllLinksOfPage(String pageURL) {
    try {

        if (urlIsValid(pageURL)) {
            visited.add(pageURL);
            Document document = Jsoup.connect(pageURL).get();  //connect to pageURL (expensive network operation)
            Elements links = document.select(a);             //get all links from page 
            for(Element link : links)
            {
                String nextUrl = link.attr(abs:href);            // http://...
                if(nextUrl.contains(new URL(pageURL).getHost()))  //ignore URLs to external hosts
                {
                    if(!isForbiddenForCrawlers(nextUrl))           // URLS forbidden by robots.txt
                    {
                        if(!visited.contains(nextUrl))
                        {
                            toVisit.add(nextUrl);
                        }
                    }
                    allUrlsOfDomain.add(nextUrl);
                }
            }
        } 
        else
        {
            invalid.add(pageURL); //URL-validation fails
        }
    } 
    catch (IOException e) {
        e.printStackTrace();
    }
}

private boolean isForbiddenForCrawlers(String url){...}
private boolean urlIsValid(String url) {...}
public String popElement(Set<String> set) {...}

Я знаю, что я должен запустить дорогой сети-операции в дополнительных потоках.

Document document = Jsoup.connect(pageURL).get();  //connect to pageURL

Моя проблема заключается в том , что я понятия не имею , как правильно передать эту работу, сохраняя при этом множества последовательных (как синхронизировать?). Если это возможно , я хочу использовать ThreadPoolExecutor контролировать количество потоков , которые знакомятся в процессе. Как вы , ребята , есть идея , как решить эту проблему? Заранее спасибо.

Задан 07/11/2018 в 19:57
источник пользователем
На других языках...                            


1 ответов

голоса
2

Для того, чтобы использовать потоки, а также сохранять наборы последовательны, вам просто нужно создать поток, который принимает переменную, которую вы хотите добавить в набор, но созданный пустой, так что поток заполняет его, когда сделано, а затем добавляет его в набор.

Простой пример, который может быть:

  • Main.class

    for (String link : links) {
        String validUrl = null;
        taskThread = new Thread( new WebDownloadThreadHanlder(link, validUrl, barrier));
        taskThread.start();
    
        if (validUrl != null) {
            allUrlsOfDomain.add(validUrl);
        }
    }
    
    barrier.acquireUninterruptibly(links.size());
    
  • WebDownloadThreadHandler.class

    public class WebDownloadThreadHandler implements Runnable {
            private String link;
            private String validUrl;
            private Semaphore barrier;
    
            public ScopusThreadHandler(String link, String validUrl, Semaphore barrier) {
                this.link = link;
                this.validUrl = null;
                this.barrier = barrier;
            }
    
            public void run () {
                try {
                    Document document = Jsoup.connect(this.link).userAgent("Mozilla/5.0");
                    Elements elements = document.select(YOUR CSS QUERY);
    
                    /*
                    YOUR JSOUP CODE GOES HERE, AND STORE THE VALID URL IN: this.validUrl = THE VALUE YOU GET;
                    */
    
                } catch (IOException) {
                    e.printStackTrace();
                }
    
                this.barrier.release();
          }
    }
    

То , что вы здесь делаете, создает поток для каждой сети вы хотите , чтобы получить все ссылки с, и хранить их в переменные, если вы хотите получить больше , чем один lvalid ссылку с каждой страницы, вы можете сделать это с помощью набора и добавления это для глобального набора (добавление его). Дело в том , что , чтобы сохранить ваш код соответствует вам необходимо хранить восстановленные значения в переменных вы передаете нить в качестве аргумента , используя ЭТО ключевое слово.

Надеюсь, поможет! Если вам нужно что-нибудь еще, не стесняйтесь спросить меня!

Ответил 08/11/2018 в 16:30
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more