Beautifulsoup findAll 如何工作
Beautifulsoup how does findAll work
我注意到 findAll
的方法有一些奇怪的行为:
>>> htmls="<html><body><p class=\"pagination-container\">slytherin</p><p class=\"pagination-container and something\">gryffindor</p></body></html>"
>>> soup=BeautifulSoup(htmls, "html.parser")
>>> for i in soup.findAll("p",{"class":"pagination-container"}):
print(i.text)
slytherin
gryffindor
>>> for i in soup.findAll("p", {"class":"pag"}):
print(i.text)
>>> for i in soup.findAll("p",{"class":"pagination-container"}):
print(i.text)
slytherin
gryffindor
>>> for i in soup.findAll("p",{"class":"pagination"}):
print(i.text)
>>> len(soup.findAll("p",{"class":"pagination-container"}))
2
>>> len(soup.findAll("p",{"class":"pagination-containe"}))
0
>>> len(soup.findAll("p",{"class":"pagination-contai"}))
0
>>> len(soup.findAll("p",{"class":"pagination-container and something"}))
1
>>> len(soup.findAll("p",{"class":"pagination-conta"}))
0
因此,当我们搜索 pagination-container
时,它 returns 第一个和第二个 p
标签。这让我觉得它在寻找部分相等:类似于 if passed_string in class_attribute_value:
。所以我在 findAll
方法中缩短了字符串,但它从来没有找到任何东西!
这怎么可能?
首先,class
is a special multi-valued space-delimited attribute并且有特殊处理。
当您写 soup.findAll("p", {"class":"pag"})
时,BeautifulSoup
将搜索具有 class pag
的元素。它会将元素 class 的值按 space 进行拆分,并检查拆分后的项目中是否存在 pag
。如果您有一个带有 class="test pag"
或 class="pag"
的元素,它将被匹配。
请注意,在 soup.findAll("p", {"class": "pagination-container and something"})
的情况下,BeautifulSoup
将匹配具有确切 class
属性值的元素。在这种情况下不涉及拆分 - 它只是看到有一个元素,其中完整的 class
值等于所需的字符串。
要在 classes 之一上进行 部分匹配,您可以提供 regular expression or a function 作为 class 过滤器值:
import re
soup.find_all("p", {"class": re.compile(r"pag")}) # contains pag
soup.find_all("p", {"class": re.compile(r"^pag")}) # starts with pag
soup.find_all("p", {"class": lambda class_: class_ and "pag" in class_}) # contains pag
soup.find_all("p", {"class": lambda class_: class_ and class_.startswith("pag")}) # starts with pag
还有很多要说的,但您还应该知道 BeautifulSoup
有 CSS selector 支持(有限但涵盖大多数常见用例)。你可以这样写:
soup.select("p.pagination-container") # one of the classes is "pagination-container"
soup.select("p[class='pagination-container']") # match the COMPLETE class attribute value
soup.select("p[class^=pag]") # COMPLETE class attribute value starts with pag
处理 BeautifulSoup
中的 class
属性值是混淆和问题的常见来源,请参阅这些相关主题以获得更多理解:
我注意到 findAll
的方法有一些奇怪的行为:
>>> htmls="<html><body><p class=\"pagination-container\">slytherin</p><p class=\"pagination-container and something\">gryffindor</p></body></html>"
>>> soup=BeautifulSoup(htmls, "html.parser")
>>> for i in soup.findAll("p",{"class":"pagination-container"}):
print(i.text)
slytherin
gryffindor
>>> for i in soup.findAll("p", {"class":"pag"}):
print(i.text)
>>> for i in soup.findAll("p",{"class":"pagination-container"}):
print(i.text)
slytherin
gryffindor
>>> for i in soup.findAll("p",{"class":"pagination"}):
print(i.text)
>>> len(soup.findAll("p",{"class":"pagination-container"}))
2
>>> len(soup.findAll("p",{"class":"pagination-containe"}))
0
>>> len(soup.findAll("p",{"class":"pagination-contai"}))
0
>>> len(soup.findAll("p",{"class":"pagination-container and something"}))
1
>>> len(soup.findAll("p",{"class":"pagination-conta"}))
0
因此,当我们搜索 pagination-container
时,它 returns 第一个和第二个 p
标签。这让我觉得它在寻找部分相等:类似于 if passed_string in class_attribute_value:
。所以我在 findAll
方法中缩短了字符串,但它从来没有找到任何东西!
这怎么可能?
首先,class
is a special multi-valued space-delimited attribute并且有特殊处理。
当您写 soup.findAll("p", {"class":"pag"})
时,BeautifulSoup
将搜索具有 class pag
的元素。它会将元素 class 的值按 space 进行拆分,并检查拆分后的项目中是否存在 pag
。如果您有一个带有 class="test pag"
或 class="pag"
的元素,它将被匹配。
请注意,在 soup.findAll("p", {"class": "pagination-container and something"})
的情况下,BeautifulSoup
将匹配具有确切 class
属性值的元素。在这种情况下不涉及拆分 - 它只是看到有一个元素,其中完整的 class
值等于所需的字符串。
要在 classes 之一上进行 部分匹配,您可以提供 regular expression or a function 作为 class 过滤器值:
import re
soup.find_all("p", {"class": re.compile(r"pag")}) # contains pag
soup.find_all("p", {"class": re.compile(r"^pag")}) # starts with pag
soup.find_all("p", {"class": lambda class_: class_ and "pag" in class_}) # contains pag
soup.find_all("p", {"class": lambda class_: class_ and class_.startswith("pag")}) # starts with pag
还有很多要说的,但您还应该知道 BeautifulSoup
有 CSS selector 支持(有限但涵盖大多数常见用例)。你可以这样写:
soup.select("p.pagination-container") # one of the classes is "pagination-container"
soup.select("p[class='pagination-container']") # match the COMPLETE class attribute value
soup.select("p[class^=pag]") # COMPLETE class attribute value starts with pag
处理 BeautifulSoup
中的 class
属性值是混淆和问题的常见来源,请参阅这些相关主题以获得更多理解: