2016-04-19 5 views
1

今日私はJSoupで「遊ぶ」を始めました。私はどれくらいの力があるのか​​を知りたかったので、多くの要素を持つWebページを探して、それらのすべてを取得しようとしました。そして、私が探していたものが見つかりました:http://www.top1000.ie/companiesなぜJSoupはページのすべての要素を読み込まないのですか?

これは、類似している(リストの各会社の)要素が多い(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()); 
     } 
    } 

} 

私もそれができるというページをロードする時間がなかったこと、それは私が5秒を待つように.timeout(1000*5)を置くが、私が唯一できる理由ですリストの最初の20要素を取得します。

JSoupには、ウェブページから取得できる要素の上限がありますか?私はそれがその目的のために準備されているように思われるので、私は自分のコードに何かが足りないと思うので、そうしてはいけないと思います。

ご協力いただければ幸いです。前もって感謝します!

+0

Jsoupのどのバージョンですか? – avgvstvs

+0

@avgvstvs最新:1.9.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は実際のJSONの周りにすべての種類のタグを追加し、特定の文字をエスケープするため、データを取得するためにJsoupを使用するのは面倒です。

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. 
    } 
} 

ここでは、その結果から"html"フィールドを取得し、Jsoupを使用して、それを解析するJSONパーサーを使用し、URLに(データなし)POSTリクエストを送信するためにHttpURLConnectionを使用しています。 読みたいページのメソッドをループで呼び出すだけです。

+0

私の修正された答えよりも素敵な分析と少し速いです。 +1 :) – luksch

+0

あなたのアナリシスに感謝しますが、私は疑問があります。1.どうやってJSONを手に入れましたか? 2.他の投稿に記載されている方法のどれがあなたがそれが最高だと思いますか?ありがとうございました! –

+0

@ Error404私はChrome Developer Toolsを使ってネットワークトラフィックを検査していました。 SeleniumやWebdriver(@ lukschが示唆しているように)を経験したことがある人は、試してみることができますが、JSONパーサを使った単純なhttp要求が私の最初の選択です – nyname00

4

新しい回答:

私はあなたが解析しようとしているウェブサイトを見ました。問題は、サイトの最初の呼び出しで、最初の20のcomanpiesだけが読み込まれることです。残りはAJAX経由でロードされます。 JsoupはJavaScriptを解釈したり実行したりしません。そのためにセレンの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パーサーに切り替えることができます。

+0

なぜそれを0に設定しますか?私も 'maxBodySize()'に2MB追加しようとしましたが、私は同じ20の最初の要素しか取得しません。また、あなたのソリューションで。 –

+0

さらに、正直言って、私は20フレーズが1MBの容量を占めるとは思わない。 –

+0

私の改訂版の回答をご覧ください。 – luksch

関連する問題