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:

AFAIK, това трябва да докаже, че няма проблеми с релацията 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 :/ моля, публикувайте код на нишка

РЕДАКТИРАНЕ:

Трябва да се махна за няколко часа. Тук всичките ми три класа пренаписани

все още работят, по-бавно, но работят. Определено бих препоръчал използването на фиксиран набор от нишки за подобряване на производителността.

Но мисля, че трябва да е проблем с мрежата. Късмет :)

РЕДАКТИРАНЕ:

Времето за изчакване на връзката означава, че целевият сървър изобщо не може да бъде достигнат. AFAIK, това означава, че (сървърът никога не е изпращан / клиентът никога не е получавал) TCP SYN+ACK съобщение.

Първото нещо, което може да се заключи е, че целевият сървър не е онлайн, но има още възможни причини за този проблем, една може да е, че целевият сървър е претоварен със заявки (в краен случай това е (D)DoS атака).

В момента сте опитали паралелен подход - всяка заявка е в отделна нишка:

1) Извършване на седемстотин заявки в 700 нишки (добре не седемстотин точно, но толкова, колкото може да поеме вашата операционна система)

2) Извършване на седемстотин заявки чрез набор от нишки от n‹‹700 нишки

Първо можете да опитате да поставите случайна форма за заспиване 0 - 10 s във всяка заявка

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
като вашата публикация, може би когато се опитам да се свържа със стотици теми, тогава той мисли, че im ddosing сайт. - 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
Е, бих могъл да си представя много умен google да не акира, докато не види дали syn е част от стадо, и да ги откаже на всички. - person bmargulies; 06.10.2012
comment
да, осъзнавам това, но кажете ми правилно ли е това: когато първият SYN бъде отказан, няма ли хвърленото изключение да бъде Connection Refused? SYN+ACK никога не се получава, тогава хвърлената връзка трябва да бъде връзката Timeout? - person linski; 06.10.2012
comment
Най-вече прочетох източника на jsoup и няма евентуално телепатично влияние, което да доведе до тези изключения. - person bmargulies; 06.10.2012