LoginSignup
307
303

More than 5 years have passed since last update.

jsoup使い方メモ

Last updated at Posted at 2014-03-01

jsoup は Java で HTML の解析・編集を行うためのライブラリ。

URL を指定すれば実際の Web ページを解析のインプットに指定でき、タグの検索には CSS セレクタが使えるので、 Web スクレイピングをしたい時にとても便利。

導入

Maven のセントラルリポジトリに jar がある。

build.gradle
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>

ローカルのファイルをインプットにする

input.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 を取得する

input.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 指定で検索する

input.html
<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 セレクタを使って検索する

input.html
<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.html
<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();
    }
}

参考

307
303
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
307
303