Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/84.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Jsoup:has()选择器未按预期工作_Java_Html_Web Scraping_Css Selectors_Jsoup - Fatal编程技术网

Java Jsoup:has()选择器未按预期工作

Java Jsoup:has()选择器未按预期工作,java,html,web-scraping,css-selectors,jsoup,Java,Html,Web Scraping,Css Selectors,Jsoup,我正在尝试解析一个包含多个单元格的HTML表,其结构如下: 细节 细节 ... “id”属性、“a”元素和“href”属性以及“span”元素是重要的细节,这两个元素直接嵌套。 我试着用 select("[id^=topic]" + ":has(> b > a[href])" + ":has(> span.s)") 但是结果列表是空的。当我将其更改为: select("td[id^=topic]" + ":has

我正在尝试解析一个包含多个单元格的HTML表,其结构如下:


细节
细节
...
“id”属性、“a”元素和“href”属性以及“span”元素是重要的细节,这两个元素直接嵌套。 我试着用

select("[id^=topic]"
          + ":has(> b > a[href])"
          + ":has(> span.s)")
但是结果列表是空的。当我将其更改为:

select("td[id^=topic]"
          + ":has(td > b > a[href])"
          + ":has(td > span.s)")
但我不希望选择器依赖于根元素是“td”这一事实,从文档判断,前者也应该工作。以下操作也不起作用:

select("[id^=topic]"
          + ":has(:root > b > a[href])"
          + ":has(:root > span.s)")
我做错什么了吗?顺便说一下,使用Jsoup 1.8.3。

中的选择器:has(selector)包括父元素。我认为
>b
在JSoup中不是一个有效的选择器,但是
*>b
应该可以,它允许任何父元素。因此,这应该是可行的:

select("[id^=topic]"
      + ":has(* > b > a[href])"
      + ":has(* > span.s)")
Edit1回应评论:

要使
:has(selector)
的选择器更有可能是
[id^=topic]
的直接子级,您还可以执行以下操作:

select("[id^=topic]"
      + ":has([id^=topic] > b > a[href])"
      + ":has([id^=topic] > span.s)")
当然,这还不能保证,因为父对象的内部子对象也可能携带以
主题
开头的id

Edit2

类似于,您可以通过将选择器分为两部分来确保。首先,我们匹配ID以topic开头的所有元素。然后我们循环这些元素并构造一个包含特定id的新选择器。只要所有元素的id都是独立的,这就可以工作

String html = "<table><tr><td id=\"topic1234\">" +
        "<a name='1234'></a>" +
        "<div><b><a href='/url'>Title</a></b></div>" +
        "<span class='s'>Details</span></td>\n" +
        "<td id=\"topic2345\">\n" +
        "    <a name='2345'></a>\n" +
        "    <b><a href='/url'>Title</a></b>\n" +
        "    <span class='s'>Details</span>\n" +
        "</td>"+
        "<td id=\"topic3456\">\n" +
        "    <div id=\"topic4567\"><a name='3456'></a>\n" +
        "    <b><a href='/url'>Title</a></b>\n" +
        "    <span class='s'>Details</span>\n" +
        "    </div>" +
        "</td></tr></table>";

Document doc = Jsoup.parse(html);
Elements selected = doc.select("[id^=topic]");
for (Element elem : selected) {
  String idStr = elem.attr("id");
  Element el = elem.select(":has(#"+idStr+" > b > a[href]):has(#"+idStr+" > span.s)").first();
  if (el != null){
      System.out.println("found matching element: "+el);
  }
  if (el != null){
      System.out.println("does not really match: "+el);
  }
}
String html=“”+
"" +
“详细信息\n”+
“\n”+
“\n”+
“详细信息\n”+
""+
“\n”+
“\n”+
“详细信息\n”+
"    " +
"";
Document doc=Jsoup.parse(html);
所选元素=文档选择(“[id^=主题]”);
对于(元素元素:选定){
字符串idStr=elem.attr(“id”);
Element el=elem.select(“:has(#“+idStr+”>b>a[href]):has(#“+idStr+”>span.s)”).first();
如果(el!=null){
System.out.println(“找到匹配元素:“+el”);
}
如果(el!=null){
System.out.println(“不匹配:+el”);
}
}

我认为不可能为您需要的内容编写一个选择器,因为JSoup不支持像
:has(>tag)
这样的语法

但是,我认为您可以将选择器拆分为多个部分:

String html = "<table><td id=\"topic1234\">" +
                  "<a name='1234'></a>" +
                  "<div><b><a href='/url'>Title</a></b></div>" +
                  "<span class='s'>Details</span></td>\n" +
                  "<td id=\"topic2345\">\n" +
                  "    <a name='2345'></a>\n" +
                  "    <b><a href='/url'>Title</a></b>\n" +
                  "    <span class='s'>Details</span>\n" +
                  "</td></table>"

Document doc = Jsoup.parse(html);
Elements selected = doc.select("[id^=topic]");
for (Element elem : selected) {
    // Check if "b > a[href]" is a direct child of "td"
    if (elem.select(":root > b > a[href]").size() > 0) {
        System.out.println("Found: "+elem);
    } else {
        System.out.println("Not found:"+elem);
    }
}
String html=“”+
"" +
“详细信息\n”+
“\n”+
“\n”+
“详细信息\n”+
""
Document doc=Jsoup.parse(html);
所选元素=文档选择(“[id^=主题]”);
对于(元素元素:选定){
//检查“b>a[href]”是否是“td”的直接子级
如果(元素选择(“:root>b>a[href]”)。大小()>0){
System.out.println(“发现:+elem”);
}否则{
System.out.println(“未找到:+elem”);
}
}
i、 e.html代码如下所示:


细节
细节
返回:

未找到
:
细节
发现:详细信息
显然,第二种情况(即
span.s
)也可以采用同样的方法


请注意,在这种情况下,
:root
选择器起作用,因为
elem
的根元素是
td
,而不是
:root
不起作用,因为它总是引用文档根,而与选择器的范围无关-在HTML中,这通常是无效的。在selectors-4中,这通常由
:scope
-我怀疑它在jsoup中是否起作用,但是…可能
:has(>b>)
不起作用,因为jsoup也不支持相对选择器,在这种情况下,您可能不得不选择
[id^=…]
元素并单独检查其子元素。在这种情况下,使用选择器可以得到的最接近的结果是
:has(b>…)
,但我相信您知道这并不意味着完全相同的事情。您的完整HTML是如何构造的?我的意思是,
元素是否存在于
标记中?我之所以问你这个问题,是因为根据,JSoup无法检测到“lone”
td
s.@user2340612:好吧,考虑到问题的第一句话,我假设这些单元格确实存在于一个表中。@user2340612:无论哪种方式,都不需要显式:)注意
:has(*>b)
等同于
:has(b)
,即使
b
不是id为的元素的子元素,而是其中某个其他元素的子元素,它也会匹配。感谢您的回复。您的第二个选项对我来说很好,因为
主题
ID没有嵌套。