4

jsoup を使用して以下の HTML を解析しようとしていますが、適切な構文を取得できません。

<div class="info"><strong>Line 1:</strong> some text 1<br>
  <b>some text 2</b><br>
  <strong>Line 3:</strong> some text 3<br>
</div>

テキスト 1、テキスト 2、テキスト 3 を 3 つの異なる変数でキャプチャする必要があります。

最初の行に xpath がありますが (3 行目と似ているはずです)、同等の css セレクターを作成できません。

//div[@class='info']/strong[1]/following::text()

これとは別に、数百の html ファイルがあり、それらからデータを解析して抽出し、データベースに保存する必要があります。これにはJsoupが最適ですか?

4

3 に答える 3

5

Jsoup は、混合コンテンツを含む要素からテキストを取得することを処理できないようです。XOMTagSoupを使用する、作成した XPath を使用するソリューションを次に示します。

import java.io.IOException;

import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Nodes;
import nu.xom.ParsingException;
import nu.xom.ValidityException;
import nu.xom.XPathContext;

import org.ccil.cowan.tagsoup.Parser;
import org.xml.sax.SAXException;

public class HtmlTest {
    public static void main(final String[] args) throws SAXException, ValidityException, ParsingException, IOException {
        final String html = "<div class=\"info\"><strong>Line 1:</strong> some text 1<br><b>some text 2</b><br><strong>Line 3:</strong> some text 3<br></div>";
        final Parser parser = new Parser();
        final Builder builder = new Builder(parser);
        final Document document = builder.build(html, null);
        final nu.xom.Element root = document.getRootElement();
        final Nodes textElements = root.query("//xhtml:div[@class='info']/xhtml:strong[1]/following::text()", new XPathContext("xhtml", root.getNamespaceURI()));
        for (int textNumber = 0; textNumber < textElements.size(); ++textNumber) {
            System.out.println(textElements.get(textNumber).toXML());
        }
    }
}

これは以下を出力します:

 some text 1
some text 2
Line 3:
 some text 3

あなたがやろうとしていることの詳細を知らなくても、これがまさにあなたが望むものかどうかはわかりません.

于 2012-08-05T15:08:04.000 に答える
2

個々の TextNode へのオブジェクト参照を取得することができます。おそらく、Jsoup のTextNodeオブジェクトを見過ごしていると思います。

Elementの最上位のテキストは、TextNode オブジェクトのインスタンスです。たとえば、" some text 1" と " some text 3" はどちらも "< div class='info' >" の下の TextNode オブジェクトであり、"Line 1:" は "< strong >" の下の TextNode オブジェクトです。

Element オブジェクトには、これらの TextNode オブジェクトを取得するために役立つ textNodes()メソッドがあります。

次のコードを確認してください。

String html = "<html>" +
                  "<body>" +
                      "<div class="info">" +
                          "<strong>Line 1:</strong> some text 1<br>" +
                          "<b>some text 2</b><br>" +
                          "<strong>Line 3:</strong> some text 3<br>" +
                      "</div>" +
                  "</body>" +
              "</html>";

Document document = JSoup.parse(html);
Element infoDiv = document.select("div.info").first();
List<TextNode> infoDivTextNodes = infoDiv.textNodes();

このコードは、key="class" および value="info" の属性を持つ最初の < div > 要素を見つけます。次に、「< div class='info' >」直下のすべての TextNode オブジェクトへの参照を取得します。そのリストは次のようになります。

List<TextNode>[" some text 1", " some text 3"]

TextNode オブジェクトには、それらに関連付けられたいくつかの便利なデータとメソッドがあり、それらを利用できます。Node を拡張すると、利用できる機能がさらに増えます。

以下は、class="info" を使用して div 内の各 TextNode のオブジェクト参照を取得する例です。

for(Iterator<Element> elementIt = document.select("div.info").iterator(); elementIt.hasNext();){
    Element element = elementIt.next();

    for (Iterator<TextNode> textIt = element.textNodes().iterator(); textIt.hasNext();) {
        TextNode textNode = textIt.next();
        //Do your magic with textNode now.
        //You can even reference it's parent via the inherited Node Object's 
        //method .parent();
    }
}

このネストされたイテレータ手法を使用すると、オブジェクトのすべてのテキスト ノードにアクセスでき、巧妙なロジックを使用して、Jsoup の構造内で必要なことをほぼ実行できます。

私は過去に作成したスペル チェック メソッドにこのロジックを実装しましたが、多くの要素、おそらく多くのリストなどを含む非常に大きな html ドキュメントでパフォーマンスが低下します。ただし、ファイルの長さが妥当であれば、十分なパフォーマンスが得られるはずです。

以下は、Document の各 TextNode のオブジェクト参照を取得する例です。

Document document = Jsoup.parse(html);

for (Iterator<Element> elementIt = document.body().getAllElements().iterator(); elementIt.hasNext();) {
    Element element = elementIt.next();
    //Maybe some magic for each element..

    for (Iterator<TextNode> textIt = element.textNodes().iterator(); textIt.hasNext();) {
        TextNode textNode = textIt.next();
        //Lots of magic here for each textNode..
    }
}
于 2013-07-02T00:59:14.577 に答える
1

あなたの問題は、あなたが興味を持っているテキストのうち、タグで囲まれた「some text 2」という定義タグ内に1つのフレーズだけが含まれていることだと思い<b> </b>ます。したがって、これは次の方法で簡単に取得できます。

String text2 = doc.select("div.info b").text();

返す

some text 2

関心のある他のテキストは、<div class="info">タグ内に保持されたテキストとしてのみ定義できます。それだけです。したがって、これを取得する唯一の方法は、この大きな要素が保持するすべてのテキストを取得することです

String text1 = doc.select("div.info").text();

残念ながら、これはこの要素が保持するすべてのテキストを取得します。

Line 1: some text 1 some text 2 Line 3: some text 3

それが私にできる最善のことであり、誰かがより良い答えを見つけて、この質問を続けてくれることを願っています.

于 2012-08-05T22:16:46.180 に答える