Jsoup 选择器:h2 之后的第 2 个 div
Jsoup selectors: 2nd div after h2
我有以下 HTML:
<html>
<body>
...
<h2> Blah Blah 1</h2>
<p>blah blah</p>
<div>
<div>
<table>
<tbody>
<tr><th>Col 1 Header</th><th>Col 2 Header</th></tr>
<tr><td>Line 1.1 Value</td><td>Line 2.1 Header</td></tr>
<tr><td>Line 2.1 Value</td><td>Line 2.2 Value</td></tr>
</tbody>
</table>
</div>
</div>
<div>
<div>
<table>
<tbody>
<tr><th>Col 1 Header T2</th><th>Col 2 Header T2</th></tr>
<tr><td>Line 1.1 Value T2</td><td>Line 2.1 Header T2</td></tr>
<tr><td>Line 2.1 Value T2</td><td>Line 2.2 Value T2</td></tr>
</tbody>
</table>
</div>
</div>
<h2> Blah Blah 2</h2>
<div>
<div>
<table>
<tbody>
<tr><th>XCol 1 Header</th><th>XCol 2 Header</th></tr>
<tr><td>XLine 1.1 Value</td><td>XLine 2.1 Header</td></tr>
<tr><td>XLine 2.1 Value</td><td>XLine 2.2 Value</td></tr>
</tbody>
</table>
</div>
</div>
<p>blah blah</p>
<div>
<div>
<table>
<tbody>
<tr><th>XCol 1 Header T2</th><th>XCol 2 Header T2</th></tr>
<tr><td>XLine 1.1 Value T2</td><td>XLine 2.1 Header T2</td></tr>
<tr><td>XLine 2.1 Value T2</td><td>XLine 2.2 Value T2</td></tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
我想提取包含给定文本的 h2 标签后的第二个 DIV。
您可能会注意到,在第一个和第二个 div 中,p 标签不在同一位置。
要提取第一个 h2 之后的 DIV,可以使用以下公式:
h2:contains(Blah 1) + p + div +div
但是要提取第二个,将 "Blah 1" 替换为 "Blah 2" 将不起作用,因为“"p"”标记位于其他位置,因此静态选择器将是:
h2:contains(Blah 2) + div + p +div
我需要的是一个单一的选择器公式,无论 p 块在哪里,只要更改文本就可以使它起作用
我尝试了几种方法:
就像...选择器 nth-of-type 也不起作用,因为我只知道 DIV 的位置 wrt h2 不是 DIV 的父亲,而是前一个兄弟姐妹 ...
请帮忙
我有两个实现方法。
第一个是删除每个 <p>
然后你只需要 select "h2:contains(" + text + ")+div+div"
。请小心,仅当您确定 <div>
不包含任何 <p>
时才使用它。否则会缺少一些内容。
public void execute1(String html) {
Document doc = Jsoup.parse(html);
// first approach: remove every <p> to simplify document
Elements paragraphs = doc.select("p");
for (Element paragraph : paragraphs) {
paragraph.remove();
}
// then one selector will return what you want in both cases
System.out.println(selectSecondDivAfterH2WithText(doc, "Blah 1"));
System.out.println(selectSecondDivAfterH2WithText(doc, "Blah 2"));
}
private Element selectSecondDivAfterH2WithText(Document doc, String text) {
return doc.select("h2:contains(" + text + ")+div+div").first();
}
第二种方法是遍历 "h2:contains(" + text+ ")"
和 "manually" 的兄弟姐妹,找到第二个 <div>
,忽略其他任何东西。它更好,因为它不会破坏原始文档,并且会跳过任意数量的 <p>
个元素。
public void execute2(String html) {
Document doc = Jsoup.parse(html);
System.out.println(selectSecondDivAfterH2WithText2(doc, "Blah 1"));
System.out.println(selectSecondDivAfterH2WithText2(doc, "Blah 2"));
}
private Element selectSecondDivAfterH2WithText2(Document doc, String text) {
int counter = 2;
// find h2 with given text
Element h2 = doc.select("h2:contains(" + text + ")").first();
// select every sibling after this h2 element
Elements siblings = h2.nextElementSiblings();
// loop over them
for (Element sibling : siblings) {
// skip everything that's not a div
if (sibling.tagName().equals("div")) {
// count how many divs left to skip
counter--;
if (counter == 0) {
// return when found nth div
return sibling;
}
}
}
return null;
}
我还有第三个使用 "h2:contains(" + text + ")~div:nth-of-type(2)"
的想法。它适用于第一种情况,但对于第二种情况可能会失败,因为 div 之间有一个 <p>
。
一种简单的方法是使用逗号 (,
) 查询运算符,它在选择器之间执行 OR。因此,您可以结合 P
标签所在位置的两种变体。
h2:contains(Blah 2) + div ~ div, h2:contains(Blah 2) ~ div + div
这是 try.jsoup 操场上的示例。
我有以下 HTML:
<html>
<body>
...
<h2> Blah Blah 1</h2>
<p>blah blah</p>
<div>
<div>
<table>
<tbody>
<tr><th>Col 1 Header</th><th>Col 2 Header</th></tr>
<tr><td>Line 1.1 Value</td><td>Line 2.1 Header</td></tr>
<tr><td>Line 2.1 Value</td><td>Line 2.2 Value</td></tr>
</tbody>
</table>
</div>
</div>
<div>
<div>
<table>
<tbody>
<tr><th>Col 1 Header T2</th><th>Col 2 Header T2</th></tr>
<tr><td>Line 1.1 Value T2</td><td>Line 2.1 Header T2</td></tr>
<tr><td>Line 2.1 Value T2</td><td>Line 2.2 Value T2</td></tr>
</tbody>
</table>
</div>
</div>
<h2> Blah Blah 2</h2>
<div>
<div>
<table>
<tbody>
<tr><th>XCol 1 Header</th><th>XCol 2 Header</th></tr>
<tr><td>XLine 1.1 Value</td><td>XLine 2.1 Header</td></tr>
<tr><td>XLine 2.1 Value</td><td>XLine 2.2 Value</td></tr>
</tbody>
</table>
</div>
</div>
<p>blah blah</p>
<div>
<div>
<table>
<tbody>
<tr><th>XCol 1 Header T2</th><th>XCol 2 Header T2</th></tr>
<tr><td>XLine 1.1 Value T2</td><td>XLine 2.1 Header T2</td></tr>
<tr><td>XLine 2.1 Value T2</td><td>XLine 2.2 Value T2</td></tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
我想提取包含给定文本的 h2 标签后的第二个 DIV。
您可能会注意到,在第一个和第二个 div 中,p 标签不在同一位置。
要提取第一个 h2 之后的 DIV,可以使用以下公式:
h2:contains(Blah 1) + p + div +div
但是要提取第二个,将 "Blah 1" 替换为 "Blah 2" 将不起作用,因为“"p"”标记位于其他位置,因此静态选择器将是:
h2:contains(Blah 2) + div + p +div
我需要的是一个单一的选择器公式,无论 p 块在哪里,只要更改文本就可以使它起作用
我尝试了几种方法: 就像...选择器 nth-of-type 也不起作用,因为我只知道 DIV 的位置 wrt h2 不是 DIV 的父亲,而是前一个兄弟姐妹 ...
请帮忙
我有两个实现方法。
第一个是删除每个 <p>
然后你只需要 select "h2:contains(" + text + ")+div+div"
。请小心,仅当您确定 <div>
不包含任何 <p>
时才使用它。否则会缺少一些内容。
public void execute1(String html) {
Document doc = Jsoup.parse(html);
// first approach: remove every <p> to simplify document
Elements paragraphs = doc.select("p");
for (Element paragraph : paragraphs) {
paragraph.remove();
}
// then one selector will return what you want in both cases
System.out.println(selectSecondDivAfterH2WithText(doc, "Blah 1"));
System.out.println(selectSecondDivAfterH2WithText(doc, "Blah 2"));
}
private Element selectSecondDivAfterH2WithText(Document doc, String text) {
return doc.select("h2:contains(" + text + ")+div+div").first();
}
第二种方法是遍历 "h2:contains(" + text+ ")"
和 "manually" 的兄弟姐妹,找到第二个 <div>
,忽略其他任何东西。它更好,因为它不会破坏原始文档,并且会跳过任意数量的 <p>
个元素。
public void execute2(String html) {
Document doc = Jsoup.parse(html);
System.out.println(selectSecondDivAfterH2WithText2(doc, "Blah 1"));
System.out.println(selectSecondDivAfterH2WithText2(doc, "Blah 2"));
}
private Element selectSecondDivAfterH2WithText2(Document doc, String text) {
int counter = 2;
// find h2 with given text
Element h2 = doc.select("h2:contains(" + text + ")").first();
// select every sibling after this h2 element
Elements siblings = h2.nextElementSiblings();
// loop over them
for (Element sibling : siblings) {
// skip everything that's not a div
if (sibling.tagName().equals("div")) {
// count how many divs left to skip
counter--;
if (counter == 0) {
// return when found nth div
return sibling;
}
}
}
return null;
}
我还有第三个使用 "h2:contains(" + text + ")~div:nth-of-type(2)"
的想法。它适用于第一种情况,但对于第二种情况可能会失败,因为 div 之间有一个 <p>
。
一种简单的方法是使用逗号 (,
) 查询运算符,它在选择器之间执行 OR。因此,您可以结合 P
标签所在位置的两种变体。
h2:contains(Blah 2) + div ~ div, h2:contains(Blah 2) ~ div + div
这是 try.jsoup 操场上的示例。