0

Amazonで商品レビューを解析していますが、リンク内のテキストを含むレビューの完全なテキストを取得したいと思います。

私は現在jSoupを使用していますが、アンカーを無視するだけです。もちろん、セレクターを使用するだけでアンカーからすべてのテキストを取得できますが、そのテキストが含まれていたコンテキストに関する情報は失われます。

例が自分自身を説明する最良の方法だと思います。

構造のサンプル:

<div class="container">
  <div style="a">Something...</div>
  <div style="b">...Nested spans and divs... </div>
  <div class="tiny">_____ </div>
  " From the makers of the incredible <a href="SOMELINK">SOMEPRODUCT</a> we have this other product that blablabla.... Amazing specs, but <a href="SOME_OTHER_LINK">this other product</a> is somehow better".

私が得たもの:「信じられないほどのメーカーから、私たちはこの他の製品を持っています。それは素晴らしいスペックですが、どういうわけか優れています」。

私が欲しいもの:「信じられないほどのSOMEPRODUCTのメーカーから、私たちはblablabla ...素晴らしいスペックのこの他の製品を持っていますが、この他の製品はどういうわけか優れています」。

jSoupを使用した私のコード:

Elements allContainers = doc.select(".container");
for (Element container : allContainers) {
  String reviewText = container.ownText(); // THIS EXCLUDES TEXT FROM LINKS
StdOut.println(reviewText);

jSoupがテキストノードを実際のノードとして扱っているようには見えないため、その方法を見つけることができません。したがって、これらのアンカーは次のノードの子の間では考慮されていないようです。

:notセレクターを使用して取得しようとするなど、他のアイデアも受け入れますが、jSoupがリンクからのテキストを保持できないとは信じられません。これは、彼らがこれを無視したとは信じられないほど一般的です。特徴。

4

3 に答える 3

1

jSoupがテキストノードを実際のノードとして扱うようには見えませんが、

いいえ-JSoupテキストノードは、要素と同様に実際のノードです。

あなたが問題を説明したように、あなたには非常に特定の要件があり、私はあなたが単一の呼び出しであなたが望むことを正確に行うための組み込みがないことに同意します。ただし、単純なヘルパーメソッドを使用すると、問題は解決できます。

まず、問題を確認しましょう。親divには次の子があります。

div div div #text a #text a # text

そしてもちろん、各要素diva要素には、テキストノードを含む他の子があります。あなたの例に基づくと、テキストノードではないものを無視して、すべての子を反復処理したいようです。最初のテキストノードを見つけたら、そのテキストと後続のノードのテキストを収集します。

確かに実行可能ですが、これを実行する組み込みのメソッドがないことは驚きではありません。

問題を解決するための1つの実装を次に示します。

   public static String textPlus(Element elem)
   {
      List<TextNode> textNodes = elem.textNodes();
      if (textNodes.isEmpty())
         return "";

      StringBuilder result = new StringBuilder();
      // start at the first text node
      Node currentNode = textNodes.get(0);
      while (currentNode != null)
      {
         // append deep text of all subsequent nodes
         if (currentNode instanceof TextNode)
         {
            TextNode currentText = (TextNode) currentNode;
            result.append(currentText.text());
         }
         else if (currentNode instanceof Element)
         {
            Element currentElement = (Element) currentNode;
            result.append(currentElement.text());
         }
         currentNode = currentNode.nextSibling();
      }
      return result.toString();
   }

これを使用するには:

Elements allContainers = doc.select(".container");
for (Element container : allContainers) {
  String reviewText = textPlus(container);
  StdOut.println(reviewText);
}

サンプルのhtmlテキストを指定すると、このコードは次のようになります。

「信じられないほどのSOMEPRODUCTのメーカーから、私たちはblablablaというこの他の製品を持っています。....素晴らしいスペックですが、この他の製品はどういうわけか優れています。」

お役に立てれば。

于 2012-10-24T03:27:49.490 に答える
1

私はそれをテストしていませんが、Elementクラスのjsoup APIドキュメントによると、ownTextの代わりにメソッドtextを使用する必要があります

文章

public String text()

Gets the combined text of this element and all its children.

For example, given HTML <p>Hello <b>there</b> now!</p>, p.text() returns "Hello there now!"

Returns:
    unencoded text, or empty string if none. 
See Also:
    ownText(), textNodes() 

ownText

public String ownText()

Gets the text owned by this element only; does not get the combined text of all children.

For example, given HTML <p>Hello <b>there</b> now!</p>, p.ownText() returns "Hello now!", whereas p.text() returns "Hello there now!". Note that the text within the b element is not returned, as it is not a direct child of the p element.

Returns:
    unencoded text, or empty string if none. 
See Also:
    text(), textNodes() 
于 2012-11-05T00:06:56.493 に答える
0

Guidoの答えを受け入れたのは、それがうまくいかなかったとしても、間違いなく正しい軌道に乗ったからです。

Guidoのコードは、最初のノードからテキストを取得してから、兄弟を繰り返し処理します。残念ながら、私の実際の例にはさらに2つの問題がありました。

1-特にアンカーからのテキストには要件はなく、他には何もありませんでした。もっと頑強なものが欲しかったので、Guidoの構造にその選択を追加しました。

2-これでも、各Amazonレビューの最後にある「コメント」リンクや「パーマリンク」リンクなどの不要なリンクからテキストが取得されます。他のセレクターはそれらをクリアするためにあります。

私は将来の参考のために私のために働いたコードを投稿しています。それが役に立てば幸い :-)

public static String textPlus(Element elem)
{
    List<TextNode> textNodes = elem.textNodes();
    if (textNodes.isEmpty())
        return "";

    StringBuilder result = new StringBuilder();

    Node currentNode = textNodes.get(0);

    while (currentNode != null)
    {
        // append deep text of all subsequent nodes
        if (currentNode instanceof TextNode)
        {
            TextNode currentText = (TextNode) currentNode;
            String curtext = currentText.text();
            result.append("\n\n" + currentText.text());
        }
        else if (currentNode instanceof Element)
        {
            Element currentElement = (Element) currentNode;
            Elements anchorElements = currentElement.select("a[href]").select(":not(:contains(Comment))").select(":not(:contains(Permalink))");
            if (!anchorElements.isEmpty()) {
                for (Element anchorElement : anchorElements)
                    result.append("\n\n" + anchorElement.text());
            }
        }
        currentNode = currentNode.nextSibling();
    }
    return result.toString().trim();
于 2012-10-24T22:05:26.173 に答える