2012-08-05 126 views
4

我想解析下面的HTML使用jsoup但無法得到正確的語法。Jsoup的CSS選擇器代碼(包括xpath代碼)

<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。

我有第一行的xpath(應該類似於第3行),但無法計算出等效的css選擇器。

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

請幫忙。

在單獨的我有幾百個HTML文件,需要解析並從中提取數據以存儲在數據庫中。 Jsoup是這個的最佳選擇嗎?

我想重新打開這個問題,因爲我還沒有找到解決方案。請幫忙。

回答

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 

不知道你正在嘗試做雖然什麼更多的細節,我不知道這是否正是你想要的。

+0

我改變了我的答案通過使用TagSoup XOM您的XPath來試試。 – laz 2012-08-06 01:07:43

+0

感謝您的代碼,我會給tagoup一個鏡頭。 Tagsoup比Jsoup更好嗎? 我是相當新的解析,並在7年後再次開始在java中編碼,所以認爲我是一個新手:)。 我只是試圖解析存儲在我的機器上的一組html文件,以提取有用的數據並存儲在數據庫中。唯一的限制是我不想在html中進行js或image調用,因爲這些鏈接不存在,並且可能會使進程變慢。 – 2012-08-06 10:32:39

+0

我只是試着運行代碼,輸出是空的。當我打印textElements.size()時,它是0.任何想法? – 2012-08-06 11:00:23

1

你的問題我覺得是文本的你感興趣的,只有一個短語任何定義標記中包含「一些文本2」,這是由<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 

這就是我可以做的最好的,我希望有人能找到更好的答案,並會繼續關注這個問題。

+0

謝謝doc.select(「div.info b」)。text();正在工作,其他2個是主要的謎題:)。 – 2012-08-05 22:45:33

1

可以獲取對單個文本節點的對象引用。我想也許你在看着Jsoup的TextNode對象。

Element的頂級文本是TextNode Object的一個實例。例如,「一些文本1」和「一些文本3」都是「< div class ='info'>」下的TextNode對象,並且「Line 1:」是「< strong>」下的TextNode Object。

Element對象有一個textNodes()方法,它可以用來保存這些TextNode對象。

檢查下面的代碼:

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

此代碼找到的第一個< 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文檔確實有一些性能點擊。但是如果你的文件長度合理,你應該獲得足夠的性能。

以下是獲取文檔的每個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.. 
    } 
}