“has:()”和“not:()”伪类在 BeautifulSoup 中使用时会有不同的行为

MIT*_*THU 3 python beautifulsoup css-selectors python-3.x

我试图弄清楚在以下情况下css pseudo-classes如何not:()工作。has:()

以下选择器不应打印27A-TAX DISTRICT 27A,但它确实打印了:

from bs4 import BeautifulSoup

htmlelement = """
<tbody>
  <tr style="">
     <td><a>27A-TAX DISTRICT</a> 27A</td>
  </tr>

  <tr style="">
     <td><strong>Parcel Number</strong> 720</td>
  </tr>
</tbody>
"""
soup = BeautifulSoup(htmlelement,"lxml")
item = soup.select_one("tr:not(a)").text
print(item)
Run Code Online (Sandbox Code Playgroud)

另一方面,下面的选择器应该打印I should be printed,但它会抛出AttributeError错误。

from bs4 import BeautifulSoup

htmlelement = """
<p class="vital">I should be printed</p>
<p>I should not be printed</p>
"""
soup = BeautifulSoup(htmlelement,"lxml")
item = soup.select_one("p:has(.vital)").text
print(item)
Run Code Online (Sandbox Code Playgroud)

我哪里出错了,我怎样才能让它们发挥作用?

fac*_*ser 5

不幸的是,您对什么:not():has()做什么的理解很可能不正确。

在第一个示例中,您使用:

soup.select_one("tr:not(a)").text
Run Code Online (Sandbox Code Playgroud)

您使用它的方式将选择每个tr. 这是因为它说“我想要一个tr不是a标签的标签。tr标签永远不是a标签,因此您的代码始终会获取任何标签的文本tr,包括包含27A-TAX DISTRICT.

如果您想要tr没有a标签的标签,那么您可以使用:

soup.select_one("tr:not(:has(a))").text
Run Code Online (Sandbox Code Playgroud)

这表示“我想要一个tr没有后代a标签的标签”。

欲了解更多信息,请阅读:


这引出了你的第二个问题。:has()是一个关系选择器。在第二个示例中,您使用了:

soup.select_one("p:has(.vital)").text
Run Code Online (Sandbox Code Playgroud)

:has()向前查看子级、后代或同级(取决于您使用的语法)以确定该标记是否是您想要的标记。

所以你所说的是“我想要一个p具有该类的后代标签的标签vital”。你的p标签甚至都没有后代,所以不可能有一个vital类。你想要的其实更简单:

soup.select_one("p.vital").text
Run Code Online (Sandbox Code Playgroud)

这句话的意思是“我想要一个p也有类的标签vital”。

欲了解更多信息,请阅读:

  • `:has()` 行为根据主要组合器而变化:`:has(+ tag)` 是下一个兄弟,`:has(&gt; tag)` 是任何后代等。`:contains()` 搜索下面的文本给定标签(包括任何子标签中的文本)。它不考虑属性。为此,您需要使用属性选择器:https://facelessuser.github.io/soupsieve/selectors/#attribute-selectors。 (2认同)