jsoupでURLのタイトルとコンテンツ文字列のみ取得

2019年8月23日

タイトル通りだ。URLを指定してそのタイトルとコンテンツをHTMLタグ無しで文字列として取得する。タイトルが見つからないときはnullになる。

build.gradle

dependencies {
  compile group: 'org.jsoup', name: 'jsoup', version: '1.12.1'
}

コード

    Document doc = Jsoup.connect(url).get();    

    // 文書全体をテキストで取得
    String content = doc.text();    

    // titleタグを探し、その中の文字列を取得
    // これは冗長かもしれない。他にやり方があるかも
    String title = doc.getAllElements().stream()
      .filter(e->e.tag().getName().equals("title"))
      .map(e->e.text())
      .findAny()
      .orElse(null);

JSoupでタグの取りこぼしがある

理由がわからないのだが、JSoupでテキストのみを取得しているのに、なぜかタグが紛れ込んでいることがある。もしかしたらJSoupのせいではないのかもしれないが、ともあれタグがあっては困るので、エスケープするプログラムを書いた。元からあるエスケープはそのままにしておき、取りこぼしたタグ等をエスケープする。


/** 既にエスケープされた文字列を特定するためのパターン */ static Pattern PATTERN = Pattern.compile( //以下は掲載するときに色々考えるのが面倒なのですべて全角になっている "&amp;|&quot;|&lt;|&gt;|&nbsp;|&ensp;|&emsp;|&ndash;|&mdash;|&mdash;|&#\\d+;)"); /** * 既にエスケープ文字列になっている箇所を避け、それ以外をエスケープする。 * <p> * JSoupがHTMLタグを残してしまうことがある。これを除去するのが面倒なので、 * エスケープしてしまうことにするが、しかし、既にエスケープされている文字列までさらに * エスケープしてはいけない。そのため、既にエスケープされている部分はそのままにして、 * それ以外の箇所をエスケープする。 * </p> * @param source 対象文字列 * @return エスケープされた文字列 */ static String sanitize(String source) { Matcher m = PATTERN.matcher(source); StringBuilder s = new StringBuilder(); int end = 0; while (m.find()) { s.append(escape(source.substring(end, m.start()))); s.append(source.substring(m.start(), m.end())); end = m.end(); } s.append(escape(source.substring(end, source.length()))); return s.toString(); } /** * 一律にエスケープする * @param source 対象文字列 * @return エスケープされた文字列 */ static String escape(String source) { return source // いかもすべて全角になっている       .replace("&", "&amp;")       .replace("\"", "&quot;")       .replace("<", "&lt;")       .replace(">", "&gt;")       .replace("'", "&#39;"); }