Java jsoup с использованием потоков не работает

У меня есть похожие страницы примерно так:

www.foo1.bar
www.foo2.bar
www.foo3.bar
.
.
www.foo100.bar

Я использую библиотеку jsoup и подключаюсь к каждой странице одновременно с Thread :

Thread matchThread = new Thread(task);
matchThread.start();

Каждая задача подключается к странице следующим образом и анализирует HTML:

Jsoup.connect("www.fooX.bar").timeout(0).get();

Получение тонн этих исключений:

java.net.ConnectException: Connection timed out: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:529)
at sun.net.NetworkClient.doConnect(NetworkClient.java:158)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:388)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:523)
at sun.net.www.http.HttpClient.<init>(HttpClient.java:227)
at sun.net.www.http.HttpClient.New(HttpClient.java:300)
at sun.net.www.http.HttpClient.New(HttpClient.java:317)
at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:970)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:911)
at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:836)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:404)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:391)
at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:157)
at org.jsoup.helper.HttpConnection.get(HttpConnection.java:146)

Разрешает ли jsoup только 1 поток одновременно? Или что я делаю не так? Любые предложения о том, как быстрее подключаться к моим страницам, поскольку переход по одной занимает целую вечность.

РЕДАКТИРОВАТЬ:

Все 700 потоков, использующих этот метод, может быть, это проблема или что-то в этом роде. Может ли этот метод обрабатывать такое количество потоков или он одноэлементный?

private static Document connect(String url) {
    Document doc = null;
    try {
        doc = Jsoup.connect(url).timeout(0).get();
    } catch (IOException e) {
        System.out.println(url);
    }
    return doc; 
}

РЕДАКТИРОВАТЬ: весь код потока

public class MatchWorker implements Callable<Match>{

private Element element;

public MatchWorker(Element element) {
    this.element = element;
}

@Override
public Match call() throws Exception {
    Match match = null;
            Util.connectAndDoStuff();
    return match;
}

}

МОИ ВСЕ 700 ЭЛЕМЕНТОВ:

    Collection<Match> matches = new ArrayList<Match>();
    Collection<Future<Match>> results = new ArrayList<Future<Match>>();

 for (Element element : elements) {
        MatchWorker matchWorker = new MatchWorker(element);
        FutureTask<Match> task = new FutureTask<Match>(matchWorker);
        results.add(task);

        Thread matchThread = new Thread(task);
        matchThread.start();
    }
    for(Future<Match> match : results) {
        try {
            matches.add(match.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

person Jaanus    schedule 06.10.2012    source источник
comment
Вы дважды проверили, что www.fooX.bar находится в сети - например. браузер может получить к нему доступ, или вы можете подключиться к нему по телнету на порту 80?   -  person linski    schedule 06.10.2012
comment
Да, я могу получить к нему доступ, это просто веб-сайт, как и любой другой.   -  person Jaanus    schedule 06.10.2012
comment
@Jaanus: я тоже часто сталкиваюсь с этой проблемой. Удалось ли вам найти решение для этого?   -  person Richa    schedule 02.08.2018


Ответы (2)


Я пробовал это:

    ExecutorService executorService = Executors.newFixedThreadPool(5);
    List<Future<Void>> handles = new ArrayList<Future<Void>>();
    Future<Void> handle;
    for (int i=0;i < 12; i++) {
        handle = executorService.submit(new Callable<Void>() {

            public Void call() throws Exception {
                Document d = Jsoup.connect("http://www.google.hr").timeout(0).get();
                System.out.println(d.title());
                return null;
            }
        });
        handles.add(handle);
    }

    for (Future<Void> h : handles) {
        try {
            h.get();
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    executorService.shutdownNow();

Он заканчивается почти сразу и печатает правильный заголовок. Возможно, у вас проблема с брандмауэром? («Время ожидания соединения истекло» означает, что сервер вообще не был доступен)

РЕДАКТИРОВАТЬ:

я использовал JSoup 1.7.1

РЕДАКТИРОВАТЬ^2:

Насколько я знаю, это должно доказать, что в отношении JSoup - Thread нет проблем, потому что в конце концов он использует потоки.

РЕДАКТИРОВАТЬ^3:

Кроме того, если вы находитесь за прокси-сервером, здесь как вы можете установить настройки прокси.

РЕДАКТИРОВАТЬ^4:

public static Document connect(String url) {
    Document doc = null;
    try {
        doc = Jsoup.connect(url).timeout(0).get();
    } catch (IOException ex) {
        ex.printStackTrace();
    }
    return doc;
}

и функция вызова переписана:

public Void call() throws Exception {                    
    System.out.println(App.connect("http://www.google.hr").title());
    return null;
}

дает тот же результат. Единственное, о чем я могу думать, это какая-то неявная статическая синхронизация, но это не имеет особого смысла, так как есть исключение TimeOut: / пожалуйста, опубликуйте код потока

РЕДАКТИРОВАТЬ:

Придется уйти на пару часов. Здесь все три моих класса переписаны

все еще работают, медленнее, но работают. Я определенно рекомендую использовать фиксированный пул потоков для повышения производительности.

Но я думаю, что это должна быть проблема с сетью. Удачи :)

РЕДАКТИРОВАТЬ:

Превышение времени ожидания подключения означает, что конечный сервер вообще недоступен. Насколько я знаю, это означает, что (сервер никогда не отправлял / клиент никогда не получал) TCP Сообщение SYN+ACK.

Первое, что можно сделать, это то, что сервер назначения не подключен к сети, но есть больше возможных причин этой проблемы, одна из них может состоять в том, что сервер назначения перегружен запросами (в крайнем случае это (D)DoS-атака).

В настоящее время вы пробовали параллельный подход - каждый запрос находится в своем потоке:

1) Делаем семьсот запросов в 700 потоков (ну не семьсот на самом деле, а столько, сколько может выдержать ваша ОС)

2) Выполнение семисот запросов через пул из n‹‹700 потоков.

Сначала вы можете попробовать поместить случайную форму сна 0–10 с в каждый запрос.

Thread.currentThread.sleep(new Random().nextInt(10000)) 

Но, учитывая результаты на данный момент, это, вероятно, не сработает. Следующим шагом является замена параллельного последовательного подхода, как вы упомянули в комментарии, - каждый запрос выполняется один за другим из цикла for одного основного потока. Еще можно попробовать поставить случайный сон.

Это самый мягкий (самый медленный) способ, которым вы можете воспользоваться, и если это не сработает, я не знаю, как это решить :(

РЕДАКТИРОВАТЬ:

Используя пул из 5 потоков, я успешно загрузил названия 1141 футбольного матча.

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

Если это правильно, вы сможете получить данные через прокси, но будьте вежливы и используйте пул потоков из ‹ 10 потоков :)

person linski    schedule 06.10.2012
comment
Нет, у меня последний jsoup, а не прокси, мне нужно пройти ровно 765 сайтов: каждый отличается. Мои потоки используют один и тот же статический метод для подключения, возможно, это вызывает проблемы, смотрите обновления на первой странице. - person Jaanus; 06.10.2012
comment
можете выложить весь код рабочего потока? я попробовал статический метод, скоро см. редактирование - person linski; 06.10.2012
comment
Я поместил весь код темы в первый пост... - person Jaanus; 06.10.2012
comment
Хорошо, лучше, когда потоки замедляются, а не создаются 700 потоков, но в некоторых случаях все равно получается java.net.ConnectException: Connection timed out: connect. - person Jaanus; 06.10.2012
comment
Я бы попробовал понюхать трафик чем-нибудь вроде wireshark :/ - person linski; 06.10.2012
comment
linksi, когда я помещаю метод connect в цикл, например... пройти 10 раз, пока не будет исключения, тогда он, наконец, подключается к нему, но иногда должен повторить попытку 5 раз. - person Jaanus; 07.10.2012
comment
смотрите обновление. Уместно ли попросить вас дать мне эти URL-адреса, чтобы я мог попробовать со своей части сети? Если мне это удастся, это означает, что проблема не в целевом сервере, а где-то в вашем пути к серверу. Если я потерплю неудачу, то это вероятно конечный сервер (брандмауэр, IDS?).. - person linski; 07.10.2012
comment
betexplorer.com/results , там сотни игр, я просматриваю все ссылки. и они прекрасно работают ... но когда я пытаюсь одновременно подключиться к 150 потокам. тогда возникает проблема. - person Jaanus; 07.10.2012
comment
как ваш пост, может быть, когда я пытаюсь подключиться к сотням потоков, он думает, что я делаю сайт. - person Jaanus; 07.10.2012
comment
смотрите обновление. пожалуйста, подумайте о том, чтобы проголосовать и принять, если это возможно, поскольку он закрыт. Спасибо. - person linski; 07.10.2012

Jsoup просто вызывает HTTPUrlConnection для подключения. Это не влияет на то, произойдет ли сбой этого соединения. На это могут повлиять брандмауэры и устройства предотвращения DDOS. Неудивительно, что веб-сайт отвергает поток одновременных подключений.

person bmargulies    schedule 06.10.2012
comment
но разве он не должен сначала получить несколько одобрений, а затем соединение было отклонено, а время ожидания соединения не истекло? - person linski; 06.10.2012
comment
Ну, я могу представить себе очень умного гугла, который не подтвердит, пока не увидит, является ли син частью стаи, и отклонит их все. - person bmargulies; 06.10.2012
comment
да, я понимаю это, но скажите мне, правильно ли это: когда первый SYN получает отказ, не будет ли выброшено исключение Connection Refused? если SYN+ACK никогда не получен, то установленное соединение должно быть Timeout? - person linski; 06.10.2012
comment
В основном я читал источник jsoup, и он, возможно, не имеет телепатического влияния, которое могло бы вызвать эти исключения. - person bmargulies; 06.10.2012