为什么JSoup不读取页面的所有元素?

时间:2016-04-19 14:39:17

标签: java jsoup

今天我开始玩#34;与JSoup。我想知道有多强大的JSoup,所以我找了一个包含很多元素的网页,我试图检索所有这些元素。我找到了我要找的东西:http://www.top1000.ie/companies

这是一个列表,其中包含许多相似的元素(1000)(列表中的每个公司)。只需更改它们内部的文本,以便我试图检索它的是该文本,但我只能获得前20个元素,而不是其余元素。

这是我的简单代码:

package retrieveInfo;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Retrieve {

    public static void main(String[] args) throws Exception{
        String url = "http://www.top1000.ie/companies";
        Document document = Jsoup.connect(url)
                 .userAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0")
                 .timeout(1000*5)
                 .get();

        Elements companies = document.body().select(".content .name");
        for (Element company : companies) {
            System.out.println("Company: " + company.text());
        }
    }

}

我认为可能是页面没有时间加载,所以这就是为什么我让.timeout(1000*5)等待5秒但我只能获得列表的前20个元素。< / p>

JSoup是否有可以从网页检索的元素限制?我认为不应该因为它似乎已经为此目的做好准备所以我认为我在代码中遗漏了一些内容。

任何帮助将不胜感激。提前谢谢!

2 个答案:

答案 0 :(得分:4)

新答案:

我查看了您要解析的网站。问题是,只有前20个comanpies加载了网站的第一次调用。其余的是通过AJAX加载的。并且Jsoup不解释或运行JavaScript。您可以使用selenium webdriver,或直接找出AJAX调用。

OLD:

如果没有通过maxBodySize()方法告知,则Jsoup限制为1M。所以你可能想这样做:

Document document = Jsoup.connect(url)
             .userAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0")
             .maxBodySize(0)
             .timeout(1000*5)
             .get();

请注意,以上完全取消了尺寸限制。这可能不是一个好主意,因为Jsoup在内存中构建DOM,因此您可能会遇到大文档的内存堆大小问题。如果您遇到这样的问题,切换到另一个基于SAX的HTML解析器可能会有所帮助。

答案 1 :(得分:2)

网站最初只加载前20个元素。向下滚动时,下一个元素块由脚本加载(POSThttp://www.top1000.ie/companies?page=2)。然后,该脚本将接收到的元素添加到DOM中。

但是,您从POST/companies?page=的回复是JSON。

{
 "worked":true,
 "has_more":true,
 "next_url":"/companies?page=3",
 "html":"..."
 ...
}

这里的“html”字段似乎包含将添加到DOM的元素。

使用Jsoup获取数据将非常繁琐,因为Jsoup将在实际的JSON周围添加所有类型的标记,并且还会转义某些字符。

我认为您最好使用in this post描述的方式之一,连接到http://www.top1000.ie/companies?page=1并逐页阅读数据。

编辑这是一个关于如何使用HttpURLConnectionminimal-json解析器解决此问题的最小示例。

void readPage(int page) throws IOException {
    URL url = new URL("http://www.top1000.ie/companies?page=" + page);

    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setDoOutput(true);
    connection.setRequestMethod("POST");

    try (OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream())) {
        // no need to post any data for this page
        writer.write("");
    }

    if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
        try (Reader reader = new InputStreamReader(connection.getInputStream())) {
            String html = Json
                .parse(reader)
                .asObject()
                .getString("html", "");

            Elements companies = Jsoup
                .parse(html)
                .body().select(".content .name");

            for (Element company : companies) 
                System.out.println("Company: " + company.text());
        }
    } else {
        // handle HTTP error code.
    }
}

这里我们使用HttpURLConnection向URL发送POST请求(没有任何数据),使用JSON解析器从结果中获取"html"字段,然后使用Jsoup。 只需在循环中调用您想要阅读的页面。