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の解析を保証します。 これは、String、InputStream、File、または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");
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にあります。