Java jsoup使用线程无法正常工作

Jaa*_*nus 0 java multithreading callable runnable jsoup

我喜欢这样的页面:

www.foo1.bar
www.foo2.bar
www.foo3.bar
.
.
www.foo100.bar
Run Code Online (Sandbox Code Playgroud)

我正在使用库jsoup并使用Thread同时连接到每个页面:

Thread matchThread = new Thread(task);
matchThread.start();
Run Code Online (Sandbox Code Playgroud)

每个任务,连接到这样的页面,并解析HTML:

Jsoup.connect("www.fooX.bar").timeout(0).get();
Run Code Online (Sandbox Code Playgroud)

获得大量的这些例外:

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)
Run Code Online (Sandbox Code Playgroud)

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; 
}
Run Code Online (Sandbox Code Playgroud)

编辑:整个线程代码

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;
}
Run Code Online (Sandbox Code Playgroud)

}

我的所有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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

lin*_*ski 7

我试过这个:

    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();
Run Code Online (Sandbox Code Playgroud)

它完成了几乎immediatley并打印正确的标题.也许你有防火墙问题?("连接超时"表示根本无法访问服务器)

编辑:

我使用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;
}
Run Code Online (Sandbox Code Playgroud)

并重写了调用函数:

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

给出相同的结果.我唯一能想到的是一些隐式静态同步,但由于存在TimeOut异常,因此没有多大意义:/ pls post thread code

编辑:

必须离开几个小时.这里我所有的三个班都重写了

仍然工作,慢,但工作.我绝对会建议使用固定线程池来提高性能.

但是,我认为这必定是一个网络问题.祝好运 :)

编辑:

连接超时意味着根本无法访问目标服务器.AFAIK,这意味着(服务器永远不会发送/客户端永远不会收到)TCP SYN + ACK消息.

可以得出结论的第一件事是目标服务器不在线,但是有更多可能的原因导致此问题,可能是目标服务器因请求而过载(在极端情况下这是(D)DoS攻击).

目前,您尝试了并行方法 - 每个请求都在自己的线程中:

1)在700个线程中发出七百个请求(实际上不是七百个请求,但与您的操作系统一样多)

2)通过n << 700个线程的线程池发出七百个请求

首先,您可以尝试在每个请求中添加0到10秒的随机睡眠形式

Thread.currentThread.sleep(new Random().nextInt(10000)) 
Run Code Online (Sandbox Code Playgroud)

但鉴于目前的结果,这可能不会奏效.接下来就是用注释中提到的顺序方法替换并行方法 - 每个请求都是从一个主线程的for循环内一个接一个地运行.你也可以试着把随机睡眠.

这是你可以去的最温和(最慢)的方式,如果这不起作用,我不知道如何解决这个问题:(

编辑:

通过使用5个线程线程池,我成功下载了1141个足球比赛的标题.

对于这种类型的站点来说保护他们的数据是合乎逻辑的,所以当你在开发和测试(运行尽可能多的线程,你可以反复召唤)时,大多数人认为你(r IP)是一个想要他们所有人的爬虫数据和他们显然不喜欢也不想要那样,所以他们禁止你.他们只是决定甚至不拒绝你的请求而是玩死 - 因此连接超时.这是有道理的.Phew :)

如果这是正确的,你应该能够通过代理获取数据,但要礼貌并使用<10个线程的线程池:)