【发布时间】:2014-07-14 16:24:31
【问题描述】:
在处理一堆乱七八糟的嵌套表时,我们如何使用jsoup 提取特定的表?
以下面的 HTML 为例,一堆表格。在后半部分向下扫描两个关键表,每个表都有一个th 单元格,显示DOG 或CAT。
有时我想要狗桌,有时我想要猫桌。可能有十几个(“BIRD”、“MOUSE”、“HAMSTER”等)。 cat-table 可能比 dog-table 嵌套得更深。所以我不能使用任何关于“第一”或“最后”的技巧。我必须查看th 单元格的值,然后获取直接包含表。
以下jsoup 代码为我提供了两个元素:
Elements elements = document.select( "table:has(tbody > tr > th > b:containsOwn(CAT))" );
通过该行,我得到两个元素而不是一个:
- 我想要的桌子。
- 包含我想要的表的外部表。
此时我的解决方法是检查长度,然后选择较短的。但一定有更好的办法。
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>title</title>
</head>
<body>
<!-- page content -->
<table> <!--Outer table. Do not want this.-->
<tbody>
<tr>
<td>
<table>
<tbody>
<tr>
<th><b>DOG</b></th> <!-- DOG in header -->
</tr>
<tr>
<td>X</td>
<td>7</td>
</tr>
</tbody>
</table>
</td>
<td>
<table> <!-- I want this table because it contains a header ("th") displaying the value "CAT". -->
<tbody>
<tr>
<th><b>CAT</b></th> <!-- CAT in header -->
</tr>
<tr>
<td>A</td>
<td>1</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</body>
</html>
我还使用 jsoup 1.7.3 版尝试了以下 Java 应用程序。
package com.example.jsoupexperiment;
import java.io.InputStream;
import java.util.Scanner;
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 ParseNestedTables
{
public static void main( String[] args )
{
System.out.println( "Running main method of ParseNestedTables class." );
InputStream stream = ParseNestedTables.class.getResourceAsStream( "/bogus.html" );
Scanner scan = new Scanner( stream );
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))" );
int countElements = elements.size(); // Hoping for 1, but getting 2.
System.out.println( "Found " + countElements + " elements. Dumping… \n\n" );
for ( Element element : elements ) {
System.out.println( "Element…\n" + element.toString() + "\n\n" );
}
}
}
但它返回两个元素而不是一个:
- 包含所需表的外部表。
- 所需的表。
另一个问题是,虽然我不完全理解 eq selector 的行为,但如果它只是在层次结构中同一点上彼此相邻的兄弟元素中进行挑选,那么这将是不正确的回答,即使它在这个例子中有效。在我的问题的实际应用中,表可以任意嵌套在任意数量的其他表中。其他表格与页面布局相关,与我想要的表格没有直接的逻辑联系。
【问题讨论】:
-
document.select("table:eq(0):has(th:contains(CAT))");也许? -
@HovercraftFullOfEels 不,该行给出了相同的结果(两个元素,外部表和所需表)。感谢您的尝试。
-
没问题。请注意,我确实编辑了我的评论。
-
@HovercraftFullOfEels 如此指出。我尝试了
"table:lt(1):has(th:contains(CAT))"和"table:eq(0):has(th:contains(CAT))"。那些应该有正确的含义?无论如何,两者都有相同的结果,外部和内部表都作为一对元素返回。 -
您的要求是必须解决使用选择器吗?如果是,我认为您可能无法得到答案 - 请参阅 stackoverflow.com/questions/1520429/css-3-content-selector 。没有可以根据文本进行选择的 css 选择器。 (基于那个答案)。