jsoup は Java で HTML の解析・編集を行うためのライブラリ。
URL を指定すれば実際の Web ページを解析のインプットに指定でき、タグの検索には CSS セレクタが使えるので、 Web スクレイピングをしたい時にとても便利。
#導入
Maven のセントラルリポジトリに jar がある。
dependencies {
compile 'org.jsoup:jsoup:1.7.3'
}
#解析する HTML の指定
##URL を指定して実際の Web ページをインプットにする
package sample.jsoup;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class Main {
public static void main(String[] args) throws IOException {
Document document = Jsoup.connect("http://www.google.co.jp").get();
System.out.println(document.html());
}
}
<!DOCTYPE html>
<html itemscope="" itemtype="http://schema.org/WebPage">
<head>
<meta content="世界中のあらゆる情報を検索するためのツールを提供しています。さまざまな検索機能を活用して、お探しの情報を見つけてください。" name="description" />
<meta content="noodp" name="robots" />
<meta itemprop="image" content="/images/google_favicon_128.png" />
<title>Google</title>
(以下略)
Jsoup.connect("<URL>").get()
で、指定した URL に GET メソッドでアクセスし、結果をパースした Document
オブジェクトを取得できる。
あとは、この Document
オブジェクトから必要なタグを検索する。
※HTTP のメソッドは GET と POST しか無いようなので、 RESTful API のクライアントとしては利用できないっぽい。(Connection.Method (jsoup 1.7.4-SNAPSHOT API))
###リクエストパラメータを設定する
package sample.jsoup;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class Main {
public static void main(String[] args) throws IOException {
Document document = Jsoup.connect("http://qiita.com/search")
.data("q", "java")
.get();
Elements elements = document.select(".brand, .page-title, .stats");
for (Element element : elements) {
System.out.println(element.text());
}
}
}
Qiita - プログラマの技術情報共有サービス
javaの検索結果
856投稿 • 7163フォロワー
data(String, String)
メソッドでリクエストパラメータを設定できる。
URL エンコードは内部でしてくれるので、全角文字もそのまま指定できる。
##HTML 形式の文字列をインプットにする
package sample.jsoup;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class Main {
public static void main(String[] args) {
String html = "<div><span>hoge</span><p>fuga</p></div>";
Document document = Jsoup.parse(html);
System.out.println(document.html());
}
}
<html>
<head></head>
<body>
<div>
<span>hoge</span>
<p>fuga</p>
</div>
</body>
</html>
##ローカルのファイルをインプットにする
<html>
<head>
<title>test page</title>
</head>
<body>
<h1>テストページです。</h1>
</body>
</html>
package sample.jsoup;
import java.io.File;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class Main {
public static void main(String[] args) throws IOException {
Document document = Jsoup.parse(new File("input.html"), "UTF-8");
System.out.println(document.html());
}
}
<html>
<head>
<title>test page</title>
</head>
<body>
<h1>テストページです。</h1>
</body>
</html>
#テキスト・ HTML を取得する
<div id="hoge">
<h1>Hoge</h1>
<ul id="fuga">
<li>Fuga</li>
<li id="piyo">Piyo</li>
</ul>
</div>
package sample.jsoup;
import java.io.File;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
public class Main {
public static void main(String[] args) throws IOException {
Document document = Jsoup.parse(new File("input.html"), "UTF-8");
Element hoge = document.getElementById("hoge");
System.out.println("[hoge.html()]\r\n" + hoge.html() + "\r\n");
Element fuga = document.getElementById("fuga");
System.out.println("[fuga.text()]\r\n" + fuga.text() + "\r\n");
Element piyo = document.getElementById("piyo");
System.out.println("[piyo.outerHtml()]\r\n" + piyo.outerHtml() + "\r\n");
}
}
[hoge.html()]
<h1>Hoge</h1>
<ul id="fuga">
<li>Fuga</li>
<li id="piyo">Piyo</li>
</ul>
[fuga.text()]
Fuga Piyo
[piyo.outerHtml()]
<li id="piyo">Piyo</li>
-
html()
メソッドで、そのタグの中身を HTML 形式の文字列で取得できる。 -
text()
メソッドで、そのタグの中身のうち、テキスト部分だけを抽出した文字列を取得できる。 -
outerHtml()
メソッドで、そのタグ自身を HTML 形式の文字列で取得できる。
#タグの検索
##ID 指定で検索する
<h1 id="hoge">Hoge</h1>
<h1 id="fuga">Fuga</h1>
<h1 id="piyo">Piyo</h1>
package sample.jsoup;
import java.io.File;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
public class Main {
public static void main(String[] args) throws IOException {
Document document = Jsoup.parse(new File("input.html"), "UTF-8");
Element element = document.getElementById("hoge");
System.out.println(element.outerHtml());
}
}
<h1 id="hoge">Hoge</h1>
###その他検索用メソッド
ID 以外にも、 class や属性指定、兄弟タグ、親タグ、タグ内のテキスト、など様々な検索用メソッドが用意されている。
とりあえず、 Element クラスの API はざっと目を通しておいた方がよさげ。
Element (jsoup 1.7.4-SNAPSHOT API)
##CSS セレクタを使って検索する
<div id="hoge">
<ul>
<li class="error">hoge</li>
<li class="success">fuga</li>
<li class="error">piyo</li>
</ul>
<span class="error">ERROR</span>
</div>
<span id="fuga">Fuga</span>
package sample.jsoup;
import java.io.File;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class Main {
public static void main(String[] args) throws IOException {
Document document = Jsoup.parse(new File("input.html"), "UTF-8");
Elements elements = document.select("#hoge ul .error");
for (Element element : elements) {
System.out.println(element.outerHtml());
}
}
}
<li class="error">hoge</li>
<li class="error">piyo</li>
select(String cssQuery)
メソッドで、 CSS セレクタを使用した検索が可能。
使用できる CSS セレクタについては、以下の Selector クラスの API ドキュメントで説明されている。
Selector (jsoup 1.7.4-SNAPSHOT API)
ほとんどの場合普通の CSS セレクタと同じように使えるが、 E[foo="bar"]
タイプのセレクタを使用するときだけ、以下のような違いがある。
<input id="hoge" name="HOGE" />
<input id="fuga" name="FUGA" />
package sample.jsoup;
import java.io.File;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
public class Main {
public static void main(String[] args) throws IOException {
Document document = Jsoup.parse(new File("input.html"), "UTF-8");
Elements elements = document.select("[name=HOGE]");
System.out.println(elements.outerHtml());
}
}
<input id="hoge" name="HOGE" />
属性の値は ダブルクォーテーション "
で括ってはいけない 。
( "[name=\\"HOGE\\"]"
ではなく、 "[name=HOGE]"
が正)
おそらく、 Java のコード上ではダブルクォーテーションにエスケープが必要になるので、より簡潔に書けるようにこのような違いがあると思われる。
#プロキシ環境下で使う
##認証が不要な場合
package jsoup;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class Main {
public static void main(String[] args) throws IOException {
System.setProperty("http.proxyHost", "プロキシホスト名");
System.setProperty("http.proxyPort", "プロキシポート");
Document doc = Jsoup.connect("http://www.google.co.jp").get();
}
}
認証が不要な場合は簡単で、システムプロパティにプロキシのホストとポートを設定してあげればいい。
##認証が必要な場合
package jsoup;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
public class Main {
public static void main(String[] args) throws IOException {
// プロキシの設定(ホストとポート)
System.setProperty("http.proxyHost", "プロキシホスト名");
System.setProperty("http.proxyPort", "プロキシポート");
// 認証情報の設定
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("ユーザー名", "パスワード".toCharArray());
}
});
// Jsoup 取得し
Document doc = Jsoup.connect("http://www.google.co.jp").get();
}
}
#参考
- jsoup Java HTML Parser, with best of DOM, CSS, and jquery
- Java内でjQueryを使う!jsoup ::: Serendipity 2 future lies'n sundome. (´・ω・)
- jsoupでHTMLをパースする - するめとめがね
- ウェブスクレイピング - Wikipedia
- Selectors Level 3 | W3C
- java - How can I configure HTTPClient to authenticate against a SOCKS proxy? - Stack Overflow
- Jakarta Commons によるHTTP処理(HttpClient) - Java入門
- java - How to add proxy support to Jsoup (HTML parser)? - Stack Overflow
- Java Proxy Authentication - Stack Overflow