BeautifulSoup webscraping find_all():查找完全匹配
- 2025-03-21 09:07:00
- admin 原创
- 55
问题描述:
我正在使用 Python 和 BeautifulSoup 进行网页抓取。
假设我要抓取以下 HTML 代码:
<body>
<div class="product">Product 1</div>
<div class="product">Product 2</div>
<div class="product special">Product 3</div>
<div class="product special">Product 4</div>
</body>
使用 BeautifulSoup,我只想找到具有属性 class="product" 的产品(仅限产品 1 和 2),而不是“特殊”产品
如果我执行以下操作:
result = soup.find_all('div', {'class': 'product'})
结果包括所有产品(1、2、3 和 4)。
我应该怎么做才能找到类别与“产品”完全匹配的产品?
我运行的代码:
from bs4 import BeautifulSoup
import re
text = """
<body>
<div class="product">Product 1</div>
<div class="product">Product 2</div>
<div class="product special">Product 3</div>
<div class="product special">Product 4</div>
</body>"""
soup = BeautifulSoup(text)
result = soup.findAll(attrs={'class': re.compile(r"^product$")})
print result
输出:
[<div class="product">Product 1</div>, <div class="product">Product 2</div>, <div class="product special">Product 3</div>, <div class="product special">Product 4</div>]
解决方案 1:
在 BeautifulSoup 4 中,该class
属性(以及几个其他属性,例如表格单元格元素上的accesskey
属性headers
)被视为一个集合;您可以与属性中列出的单个元素进行匹配。这遵循 HTML 标准。
因此,您不能将搜索限制在一个类内。
您必须在这里使用自定义函数来匹配类:
result = soup.find_all(lambda tag: tag.name == 'div' and
tag.get('class') == ['product'])
我使用lambda
来创建一个匿名函数;每个标签在名称上匹配(必须是'div'
),并且类属性必须与列表完全相等['product']
;例如只有一个值。
演示:
>>> from bs4 import BeautifulSoup
>>> text = """
... <body>
... <div class="product">Product 1</div>
... <div class="product">Product 2</div>
... <div class="product special">Product 3</div>
... <div class="product special">Product 4</div>
... </body>"""
>>> soup = BeautifulSoup(text)
>>> soup.find_all(lambda tag: tag.name == 'div' and tag.get('class') == ['product'])
[<div class="product">Product 1</div>, <div class="product">Product 2</div>]
为了完整起见,以下是 BeautifulSoup 源代码中的所有此类设置属性:
# The HTML standard defines these attributes as containing a
# space-separated list of values, not a single value. That is,
# class="foo bar" means that the 'class' attribute has two values,
# 'foo' and 'bar', not the single value 'foo bar'. When we
# encounter one of these attributes, we will parse its value into
# a list of values if possible. Upon output, the list will be
# converted back into a string.
cdata_list_attributes = {
"*" : ['class', 'accesskey', 'dropzone'],
"a" : ['rel', 'rev'],
"link" : ['rel', 'rev'],
"td" : ["headers"],
"th" : ["headers"],
"td" : ["headers"],
"form" : ["accept-charset"],
"object" : ["archive"],
# These are HTML5 specific, as are *.accesskey and *.dropzone above.
"area" : ["rel"],
"icon" : ["sizes"],
"iframe" : ["sandbox"],
"output" : ["for"],
}
解决方案 2:
您可以像这样使用 CSS 选择器:
result = soup.select('div.product.special')
css 选择器
解决方案 3:
soup.findAll(attrs={'class': re.compile(r"^product$")})
product
此代码匹配类末尾没有 的任何内容。
解决方案 4:
您可以解决这个问题,通过强制精确匹配仅捕获产品 1和产品 2以及西班牙凉菜汤:
from gazpacho import Soup
html = """\n<body>
<div class="product">Product 1</div>
<div class="product">Product 2</div>
<div class="product special">Product 3</div>
<div class="product special">Product 4</div>
</body>
"""
soup = Soup(html)
divs = soup.find("div", {"class": "product"}, partial=False)
[div.text for div in divs]
输出准确:
['Product 1', 'Product 2']
解决方案 5:
更改您的代码
result = soup.findAll(attrs={'class': re.compile(r"^product$")})
到
result = soup.find_all(attrs={'class': 'product'})
结果是一个列表,可以通过索引进行访问
相关推荐
热门文章
项目管理软件有哪些?
热门标签
曾咪二维码
扫码咨询,免费领取项目管理大礼包!
云禅道AD