BeautifulSoup webscraping find_all():找到完全匹配

Posted

技术标签:

【中文标题】BeautifulSoup webscraping find_all():找到完全匹配【英文标题】:BeautifulSoup webscraping find_all( ): finding exact match 【发布时间】:2014-05-08 17:49:54 【问题描述】:

我正在使用 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】:

您可以解决此问题,并通过强制精确匹配仅捕获 Product 1Product 2 与 gazpacho:

from gazpacho import Soup

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>
"""

soup = Soup(html)
divs = soup.find("div", "class": "product", partial=False)
[div.text for div in divs]

准确输出:

['Product 1', 'Product 2']

【讨论】:

【参考方案2】:

更改您的代码

result = soup.findAll(attrs='class': re.compile(r"^product$"))

result = soup.find_all(attrs='class': 'product')

结果是一个列表,通过索引访问

【讨论】:

【参考方案3】:
soup.findAll(attrs='class': re.compile(r"^product$"))

此代码匹配类末尾没有product 的任何内容。

【讨论】:

对不起,我看不出问题中的版本有什么不同,你能告诉我它是什么吗?【参考方案4】:

您可以像这样使用 CSS 选择器:

result = soup.select('div.product.special')

css-selectors

【讨论】:

感谢您的回复,但我正在尝试查找“产品” div,而不是“产品特殊” div .... 使用 soup.select('div.product.special') 会返回“特殊”产品.. 糟糕,误读了您的问题。那么另一种方法是删除匹配“.product.special”的div,然后您可以安全地搜索“.product”而不会遇到其他人。 你不能在:not伪选择器上使用这种方法吗:div.product:not(.special)【参考方案5】:

在 BeautifulSoup 4 中,class 属性(以及其他几个属性,例如accesskey 和表格单元格元素上的headers 属性)被视为一个集合;您匹配属性中列出的各个元素。这遵循 HTML 标准。

因此,您不能将搜索限制为仅一类。

您必须在此处使用 custom function 来匹配该类:

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"],
    

【讨论】:

终于找到了一个可行的解决方案!!我有两个要匹配的类,并且正在使用soup.find_all('div', 'class': ['class1','class2']),但它也使用了只有class2divs。有了它,它正在做我所期望的。不知道为什么我使用的那个不起作用...

以上是关于BeautifulSoup webscraping find_all():找到完全匹配的主要内容,如果未能解决你的问题,请参考以下文章

Beautifulsoup webscraping - 从 <a> 标签中提取值

Selenium Webdriver / Beautifulsoup + Web Scraping + 错误 416

Webscraping - 试图提取一些数据,但陷入了最后的障碍

使用 BeautifulSoup 进行网页抓取(Google)[重复]

Python - 网页抓取 - BeautifulSoup & CSV

Python的基本Web Scraping(Beautifulsoup和Requests)