2012-08-05 125 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.. 
    } 
}