Help us understand the problem. What is going on with this article?

jsoup使い方メモ

More than 5 years have passed since last update.

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

参考

opengl-8080
ただのSE。Java好き。
tis
創業40年超のSIerです。
https://www.tis.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした