web-dev-qa-db-ja.com

ページコンテンツはJavaScriptで読み込まれ、Jsoupには表示されません

ページ上の1つのブロックはJavaScriptによってコンテンツで満たされ、Jsoupでページをロードした後、その情報はありません。 Jsoupでページを解析するときにJavaScriptで生成されたコンテンツを取得する方法はありますか?

長すぎるため、ここにページコードを貼り付けることはできません: http://Pastebin.com/qw4Rfqgw

必要なコンテンツの要素は次のとおりです。<div id='tags_list'></div>

この情報をJavaで取得する必要があります。できればJsoupを使用してください。要素はJavaScriptの助けを借りてフィールドです:

<div id="tags_list">
    <a href="/tagsc0t20099.html" style="font-size:14;">разведчик</a>
    <a href="/tagsc0t1879.html" style="font-size:14;">Sr</a>
    <a href="/tagsc0t3140.html" style="font-size:14;">стратегический</a>
</div>

Javaコード:

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

import Java.io.IOException;

public class Test
{
    public static void main( String[] args )
    {
        try
        {
            Document Doc = Jsoup.connect( "http://www.bestreferat.ru/referat-32558.html" ).get();
            Elements Tags = Doc.select( "#tags_list a" );

            for ( Element Tag : Tags )
            {
                System.out.println( Tag.text() );
            }
        }
        catch ( IOException e )
        {
            e.printStackTrace();
        }
    }
}
26
Eugene

JSoupは[〜#〜] html [〜#〜]パーサーであり、何らかの組み込みブラウザエンジンではありません。つまり、最初のページの読み込み後にJavascriptによってDOMに追加されたコンテンツはまったく認識されません。

その種類のコンテンツにアクセスするには、埋め込みブラウザコンポーネントが必要になります。SOなど、その種類のコンポーネントに関して多くの議論があります。たとえば、 埋め込み方法はありますかJavaのブラウザ?

22
fvu

私の場合、com.codeborne.phantomjsdriverで解決しました注:グルーヴィーなコードです。

pom.xml

        <dependency>
          <groupId>com.codeborne</groupId>
          <artifactId>phantomjsdriver</artifactId>
          <version> <here goes last version> </version>
        </dependency>

PhantomJsUtils.groovy

import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.openqa.Selenium.WebDriver
import org.openqa.Selenium.phantomjs.PhantomJSDriver

class PhantomJsUtils {
    private static String filePath = 'data/temp/';

    public static Document renderPage(String filePath) {
        System.setProperty("phantomjs.binary.path", 'libs/phantomjs') // path to bin file. NOTE: platform dependent
        WebDriver ghostDriver = new PhantomJSDriver();
        try {
            ghostDriver.get(filePath);
            return Jsoup.parse(ghostDriver.getPageSource());
        } finally {
            ghostDriver.quit();
        }
    }

    public static Document renderPage(Document doc) {
        String tmpFileName = "$filePath${Calendar.getInstance().timeInMillis}.html";
        FileUtils.writeToFile(tmpFileName, doc.toString());
        return renderPage(tmpFileName);
    }
}

ClassInProject.groovy

Document doc = PhantomJsUtils.renderPage(Jsoup.parse(yourSource))
14
iluhin

何が起こっているのかを理解する必要があります:

  • Jsoupを使用している場合もブラウザを使用している場合も、Webサイトからページをクエリすると、HTMLが返されます。 Jsoupはそれを解析できます。
  • ただし、ほとんどのWebサイトには、そのHTMLにJavascriptが含まれているか、そのHTMLからリンクされているため、ページにコンテンツが表示されます。ブラウザはJavascriptを実行できるため、ページにデータを入力できます。 Jsoupはそうではありません。

これを理解する方法は次のとおりです。HTMLコードの解析は簡単です。 Javascriptコードの実行と対応するHTMLコードの更新ははるかに複雑であり、ブラウザーの仕事です。

この種の問題の解決策は次のとおりです。

  1. JavaScriptコードが行っているAjax呼び出し、つまりコンテンツの読み込みを見つけることができる場合、Jsoupでこれらの呼び出しのURLを使用できる可能性があります。そのためには、ブラウザから開発者ツールを使用します。しかし、これは動作することが保証されていません:

    • uRLは動的である可能性があり、その時点でページにあるものに依存する可能性があります
    • コンテンツが公開されていない場合、Cookieが関係し、リソースURLを照会するだけでは不十分です。
  2. これらの場合、ブラウザの動作を「シミュレート」する必要があります。幸いなことに、そのようなツールが存在します。私が知っている、そしてお勧めするのは PhantomJS です。 Javascriptで動作し、新しいプロセスを開始してJavaから起動する必要があります。 Javaに固執したい場合は、 この投稿 にJavaの選択肢がいくつかリストされています。

6

実は「道」があるのです!多分それは「方法」よりも「回避策」です。以下のコードは、メタ属性「REFRESH」とjavascriptリダイレクトの両方をチェックします...どちらかが存在する場合、RedirectedUrl変数が設定されます。ターゲット...その後、ターゲットページを取得して続行できます...

    String RedirectedUrl=null;
    Elements meta = page.select("html head meta");
    if (meta.attr("http-equiv").contains("REFRESH")) {
        RedirectedUrl = meta.attr("content").split("=")[1];
    } else {
        if (page.toString().contains("window.location.href")) {
            meta = page.select("script");
            for (Element script:meta) {
                String s = script.data();
                if (!s.isEmpty() && s.startsWith("window.location.href")) {
                    int start = s.indexOf("=");
                    int end = s.indexOf(";");
                    if (start>0 && end >start) {
                        s = s.substring(start+1,end);
                        s =s.replace("'", "").replace("\"", "");        
                        RedirectedUrl = s.trim();
                        break;
                    }
                }
            }
        }
    }

... now retrieve the redirected page again...
1
salihcenap

ユーザーエージェントを指定した後、私の問題は解決しました。

https://github.com/jhy/jsoup/issues/287#issuecomment-12769155

0
emon

Jsoupでページを解析するときにjavascriptで生成されたコンテンツを取得する方法はありますか?

Javaでjavascriptインタープリター全体を構築せずに、これがどれほど難しいかを考えながら、NOと推測します。

0
James