Jsoupを使ってJavaでHTMLを解析する

Jsoupを使用したJavaでのHTMLの解析

1. 概要

Jsoupは、主にHTMLからデータを抽出するために使用されるオープンソースのJavaライブラリです。 また、HTMLを操作および出力することもできます。 安定した開発ライン、優れたドキュメント、流かつ柔軟なAPIを備えています。 Jsoupは、XMLの解析および構築にも使用できます。

このチュートリアルでは、Spring Blogを使用して、jsoupのいくつかの機能を示すスクレイピング演習を説明します。

  • 読み込み:HTMLをDocumentにフェッチして解析します

  • フィルタリング:目的のデータをElementsに選択し、トラバースします

  • 抽出:ノードの属性、テキスト、およびHTMLの取得

  • 変更:ノードの追加/編集/削除およびそれらの属性の編集

2. メーベン依存

プロジェクトでjsoupライブラリを利用するには、依存関係をpom.xmlに追加します。


    org.jsoup
    jsoup
    1.10.2

jsoupの最新バージョンは、MavenCentralリポジトリーにあります。

3. Jsoupの概要

JsoupはページHTMLをロードし、対応するDOMツリーを構築します。 このツリーはブラウザーのDOMと同じように機能し、jQueryやバニラJavaScriptに類似したメソッドを提供して、テキスト/ HTML /属性を選択、トラバース、操作し、要素を追加/削除します。

クライアント側のセレクターとDOMのトラバース/操作に慣れている場合は、jsoupに非常に慣れているはずです。 ページの段落を簡単に印刷できることを確認します。

Document doc = Jsoup.connect("http://example.com").get();
doc.select("p").forEach(System.out::println);

jsoupはHTMLのみを解釈し、JavaScriptを解釈しないことに注意してください。 したがって、JavaScript対応ブラウザでページが読み込まれた後に通常行われるDOMの変更は、jsoupには表示されません。

4. ロード中

ロードフェーズは、HTMLをDocumentにフェッチして解析することで構成されます。 Jsoupは、最新のブラウザーが行うように、最も無効なHTMLから完全に検証されたHTMLまで、あらゆるHTMLの解析を保証します。 これは、StringInputStreamFile、またはURLをロードすることで実現できます。

SpringブログのURLからDocumentをロードしましょう。

String blogUrl = "https://spring.io/blog";
Document doc = Jsoup.connect(blogUrl).get();

getメソッドに注意してください。これはHTTPGET呼び出しを表します。 postメソッドを使用してHTTP POSTを実行することもできます(または、HTTPメソッドタイプをパラメーターとして受け取るmethodを使用することもできます)。

異常なステータスコードを検出する必要がある場合(例: 404)、HttpStatusException例外をキャッチする必要があります:

try {
   Document doc404 = Jsoup.connect("https://spring.io/will-not-be-found").get();
} catch (HttpStatusException ex) {
   //...
}

接続をもう少しカスタマイズする必要がある場合があります。 Jsoup.connect(…)Connectionを返します。これにより、特に、ユーザーエージェント、リファラー、接続タイムアウト、Cookie、投稿データ、およびヘッダーを設定できます。

Connection connection = Jsoup.connect(blogUrl);
connection.userAgent("Mozilla");
connection.timeout(5000);
connection.cookie("cookiename", "val234");
connection.cookie("cookiename", "val234");
connection.referrer("http://google.com");
connection.header("headersecurity", "xyz123");
Document docCustomConn = connection.get();

接続は流れるようなインターフェイスに従うため、目的のHTTPメソッドを呼び出す前にこれらのメソッドをチェーンできます。

Document docCustomConn = Jsoup.connect(blogUrl)
  .userAgent("Mozilla")
  .timeout(5000)
  .cookie("cookiename", "val234")
  .cookie("anothercookie", "ilovejsoup")
  .referrer("http://google.com")
  .header("headersecurity", "xyz123")
  .get();

browsing the corresponding Javadocによって、Connectionの設定について詳しく知ることができます。

5. フィルタリング

HTMLがDocumentに変換されたので、次はHTMLをナビゲートして、探しているものを見つけます。 jQuery / JavaScriptとの類似性は、セレクターとトラバースメソッドが似ているため、ここで明らかになります。

5.1. 選ぶ

Documentselectメソッドは、同じセレクター構文as in a CSS or JavaScriptを使用して、セレクターを表すStringを受け取り、Elementsの一致リストを取得します。 このリストは空にすることができますが、nullにすることはできません。

selectメソッドを使用していくつかの選択を見てみましょう。

Elements links = doc.select("a");
Elements sections = doc.select("section");
Elements logo = doc.select(".spring-logo--container");
Elements pagination = doc.select("#pagination_control");
Elements divsDescendant = doc.select("header div");
Elements divsDirect = doc.select("header > div");

一般的なselectの代わりに、ブラウザーのDOMに触発されたより明示的なメソッドを使用することもできます。

Element pag = doc.getElementById("pagination_control");
Elements desktopOnly = doc.getElementsByClass("desktopOnly");

ElementDocumentのスーパークラスであるため、DocumentおよびElementJavadocの選択メソッドの操作について詳しく知ることができます。

5.2. 横断

Traversing means navigating across the DOM tree. Jsoupは、Document、一連のElements,、または特定のElementを操作するメソッドを提供し、ノードの親、兄弟、または子に移動できるようにします。 。

また、Elementsのセットの最初、最後、およびn番目(0ベースのインデックスを使用)のElementにジャンプできます。

Element firstSection = sections.first();
Element lastSection = sections.last();
Element secondSection = sections.get(2);
Elements allParents = firstSection.parents();
Element parent = firstSection.parent();
Elements children = firstSection.children();
Elements siblings = firstSection.siblingElements();

選択を繰り返すこともできます。 実際、タイプElementsのすべてを繰り返すことができます。

sections.forEach(el -> System.out.println("section: " + el));

前の選択(サブ選択)に制限された選択を行うことができます:

Elements sectionParagraphs = firstSection.select(".paragraph");

6. 抽出

特定の要素に到達する方法がわかったので、それらのコンテンツ、つまり属性、HTML、または子テキストを取得するときが来ました。

ブログから最初の記事を選択し、日付、最初のセクションテキスト、最後に内部および外部HTMLを取得するこの例を見てください。

Element firstArticle = doc.select("article").first();
Element timeElement = firstArticle.select("time").first();
String dateTimeOfFirstArticle = timeElement.attr("datetime");
Element sectionDiv = firstArticle.select("section div").first();
String sectionDivText = sectionDiv.text();
String articleHtml = firstArticle.html();
String outerHtml = firstArticle.outerHtml();

セレクターを選択して使用する際に留意すべきヒントを次に示します。

  • 変更された可能性があるページDOMだけでなく、ブラウザーの「ソースの表示」機能に依存します(ブラウザーコンソールで選択すると、jsoupとは異なる結果が得られる場合があります)

  • Know your selectorsはたくさんあるので、少なくとも以前に見たことがあるのは常に良いことです。セレクターの習得には時間がかかります

  • それらを試すためのUse a playground for selectors(サンプルHTMLをそこに貼り付けます)

  • ページの変更への依存度を低くする:最小で妥協のないセレクターを目指します(例: IDを好みます。 ベース)

7. 変更中

変更には、要素の属性、テキスト、HTMLの設定、および要素の追加と削除が含まれます。 これは、以前にjsoupによって生成されたDOMツリー(Document)に対して行われます。

7.1. 属性と内部テキスト/ HTMLの設定

jQueryの場合と同様に、属性、テキスト、およびHTMLを設定するメソッドは同じ名前を持ちますが、設定する値も受け取ります。

  • attr() –属性の値を設定します(属性が存在しない場合は属性を作成します)

  • text() –要素の内部テキストを設定し、コンテンツを置き換えます

  • html() –要素の内部HTMLを設定し、コンテンツを置き換えます

これらの方法の簡単な例を見てみましょう。

timeElement.attr("datetime", "2016-12-16 15:19:54.3");
sectionDiv.text("foo bar");
firstArticle.select("h2").html("
");

7.2. 要素の作成と追加

新しい要素を追加するには、最初にElementをインスタンス化して要素を作成する必要があります。 Elementが作成されたら、appendChildメソッドを使用して別のElementに追加できます。 新しく作成および追加されたElementは、appendChildが呼び出される要素の最後に挿入されます。

Element link = new Element(Tag.valueOf("a"), "")
  .text("Checkout this amazing website!")
  .attr("href", "http://example.com")
  .attr("target", "_blank");
firstArticle.appendChild(link);

7.3. 要素を削除する

要素を削除するには、最初に要素を選択して、removeメソッドを実行する必要があります。

たとえば、「navbar-link”クラスを含むすべての<li>タグをDocument,から削除し、最初の記事からすべての画像を削除しましょう。

doc.select("li.navbar-link").remove();
firstArticle.select("img").remove();

7.4. 変更されたドキュメントをHTMLに変換する

最後に、Documentを変更していたので、作業を確認することをお勧めします。

これを行うには、提示されたメソッドを使用して選択、トラバース、および抽出することでDocument DOMツリーを探索できます。または、html()メソッドを使用してそのHTMLをStringとして単純に抽出できます。

String docHtml = doc.html();

Stringの出力はきちんとしたHTMLです。

8. 結論

Jsoupは、あらゆるページをスクレイピングするための優れたライブラリです。 Javaを使用していて、ブラウザベースのスクレイピングを必要としない場合は、それを考慮に入れるライブラリです。 フロントエンド開発で得た知識を活用し、優れたプラクティスとデザインパターンに従うため、使い慣れた使いやすいです。

jsoup APIを調べ、jsoup cookbookを読むことで、jsoupを使用してWebページをスクレイピングする方法について詳しく知ることができます。

このチュートリアルで使用されるソースコードは、GitHub projectにあります。