Java 使用jsoup提取“th”标题显示特定值的表

Java 使用jsoup提取“th”标题显示特定值的表,java,html,parsing,jsoup,Java,Html,Parsing,Jsoup,当处理一堆杂乱无章的嵌套表时,我们如何使用 以下面的HTML为例,它是一堆表格。在下半部分向下扫描两个关键表,每个表都有一个th单元格,显示DOG或CAT 有时我想要狗桌,有时想要猫桌。可能有十几只(鸟、老鼠、仓鼠等等)。cat表可能嵌套得比dog表更深。所以我不能使用任何有关“第一”或“最后”的技巧。我必须查看th单元格的值,然后获取立即包含表 以下代码为我提供了两个元素: Elements elements = document.select( "table:has(tbody >

当处理一堆杂乱无章的嵌套表时,我们如何使用

以下面的HTML为例,它是一堆表格。在下半部分向下扫描两个关键表,每个表都有一个
th
单元格,显示
DOG
CAT

有时我想要狗桌,有时想要猫桌。可能有十几只(鸟、老鼠、仓鼠等等)。cat表可能嵌套得比dog表更深。所以我不能使用任何有关“第一”或“最后”的技巧。我必须查看
th
单元格的值,然后获取立即包含表

以下代码为我提供了两个元素:

 Elements elements = document.select( "table:has(tbody > tr > th  > b:containsOwn(CAT))" );
通过这一行,我得到了两个元素,而不是一个:

  • 我想要的那张桌子
  • 包含我想要的表的外部表
在这一点上,我的解决方法是检查长度,然后选择较短的长度。但一定有更好的办法

HTML:


标题
狗
X
7.
猫
A.
1.

我还使用jsoup版本1.7.3尝试了以下Java应用程序

package com.example.jsupexperiment;
导入java.io.InputStream;
导入java.util.Scanner;
导入org.jsoup.jsoup;
导入org.jsoup.nodes.Document;
导入org.jsoup.nodes.Element;
导入org.jsoup.select.Elements;
/**
*目的使用“jsoup”库测试嵌套表的解析,如
*关于StackOverflow.com问题的讨论:
* http://stackoverflow.com/q/24719049/642706
*标题:使用jsoup提取“th”标题显示特定值的表
*/
公共类ParseNesteTables
{
公共静态void main(字符串[]args)
{
System.out.println(“运行ParseNesteTables类的主方法”);
InputStream=ParseNesteTables.class.getResourceAsStream(“/bogus.html”);
扫描仪扫描=新扫描仪(流);
StringBuilder sb=新的StringBuilder();
while(scan.hasNextLine()){
sb.append(scan.nextLine()+“\n”);
}
//System.out.println(sb.toString());
Document Document=Jsoup.parse(sb.toString());
Elements=document.select(“表:等式(0):has(th:contains(CAT))”;
int countElements=elements.size();//希望为1,但得到2。
System.out.println(“找到”+countElements+“elements.Dumping…\n\n”);
for(元素:元素){
System.out.println(“元素…\n”+元素.toString()+”\n\n”);
}
}
}
但它返回两个元素而不是一个:

  • 包含所需表格的外部表格
  • 所需的表格

  • 另一个问题是,虽然我不完全理解的行为,但如果它只是在层次结构中同一点上相邻的元素之间进行选择,那么即使在本例中有效,这也不是正确的答案。在我的问题的实际应用中,这些表可以任意嵌套在任意数量的其他表中。其他表与页面布局相关,与我想要的表没有直接的逻辑连接。

    我不知道,因为它似乎对我很好:

    import java.util.Scanner;    
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.select.Elements;
    
    public class ThHeaderTest {
       public static void main(String[] args) {
          String resource = "thHeader.txt";
          Scanner scan = new Scanner(ThHeaderTest.class.getResourceAsStream(resource));
          StringBuilder sb = new StringBuilder();
          while (scan.hasNextLine()) {
             sb.append(scan.nextLine() + "\n");
          }
          // System.out.println(sb.toString());
          Document document = Jsoup.parse(sb.toString());
          Elements elements = document.select("table:eq(0):has(th:contains(CAT))");
          System.out.println(elements);
       }
    }
    
    解决方法:使用较短的元素 这不是一个正确的答案,因为它不会改进jsoup选择器。但这是一个实际的解决办法

    由于问题是所需的表也将作为其外部嵌套父表返回,因此从逻辑上讲,我们知道所需表的HTML也将比外部表短

    因此,解决方法是比较每一个发现的问题的长度。使用HTML长度最短的元素。

    解决方法:查找目标值,向上移动层次结构 另一个解决办法。这不是一个正确的答案,因为它不会改进jsoup选择器

    我们通过它的
    th
    头单元格的值知道需要哪个表。所以找到那个元素,然后倒转。沿着元素的层次结构(DOM树),经过
    tr
    tbody
    ,直到到达
    表。我们知道这是拥有目标
    th
    的直接表。我们避免使用外部嵌套表

    关键代码包括查找
    th
    单元格:

    Elements elements = document.select( "th > b:containsOwn(CAT)" ); 
    
    …并循环查找每个父级:

    Element element = elements.first();
    while (  ! ( ( element == null ) || ( element.tagName().equalsIgnoreCase( "table" ) ) ) ) {
        element = element.parent();
    }
    
    完整示例应用程序:
    package com.example.jsupexperiment;
    导入java.io.InputStream;
    导入java.util.Scanner;
    导入org.jsoup.jsoup;
    导入org.jsoup.nodes.Document;
    导入org.jsoup.nodes.Element;
    导入org.jsoup.select.Elements;
    公共类ParseNesteTables
    {
    公共静态void main(字符串[]args)
    {
    System.out.println(“运行ParseNesteTables类的主方法”);
    InputStream=ParseNesteTables.class.getResourceAsStream(“/bogus.html”);
    扫描仪扫描=新扫描仪(流);
    StringBuilder sb=新的StringBuilder();
    while(scan.hasNextLine()){
    sb.append(scan.nextLine()+“\n”);
    }
    Document Document=Jsoup.parse(sb.toString());
    Elements=document.sele
    
    package com.example.jsoupexperiment;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    import org.jsoup.select.Elements;
    
    /**
     * PURPOSE To test parsing of nested tables using the "jsoup" library, as
     * discussed on this StackOverflow.com question:
     * http://stackoverflow.com/q/24719049/642706 Titled: Extract a table whose `th`
     * header displays a certain value, using jsoup
     */
    public class ParseNestedTables2 {
        public static void main(String[] args) throws IOException {
            System.out.println("Running main method of ParseNestedTables class.");
            InputStream stream = ParseNestedTables2.class
                    .getResourceAsStream("/bogus.html");
            Document document = Jsoup.parse(stream, "UTF-8", "http://example.com");
            Elements elements = document.select("table table");
            for (Element element : elements) {
                if (element.select("th b:contains(CAT)").size() > 0) {
                    System.out
                            .println("table that have th contain selected text (CAT)");
                    System.out.println(element);
                }
            }
        }
    
    }