将 BeautifulSoup 4 的 `find_all` 与正则表达式一起使用时,如何访问正则表达式匹配捕获组?

Posted

技术标签:

【中文标题】将 BeautifulSoup 4 的 `find_all` 与正则表达式一起使用时,如何访问正则表达式匹配捕获组?【英文标题】:When using BeautifulSoup 4's `find_all` with a regex, how do I access regex match capture groups? 【发布时间】:2016-01-16 11:59:11 【问题描述】:

我正在使用 BeautifulSoup 4,我正在使用带有正则表达式的 find_all 来查找与特定模式匹配的所有链接。

results = page.find_all(href=re.compile("foo/bar\?baz="))
for result in results:
    ...

不过我也想从 URL 中提取一个参数。

我可以通过在参数上放置一个捕获组来标记要提取的参数:

results = page.find_all(href=re.compile("foo/bar\?baz=([^&]+)"))

但如果我这样做,我如何访问特定匹配中捕获组的值?

【问题讨论】:

现在作为一种解决方法,我只是将result["href"] 通过正则表达式再次单独放入循环中。 find_all 可以将正则表达式作为参数仅用于过滤,我认为您不能提取捕获组或整个匹配项。 @CasimiretHippolyte 对不起,我现在遇到了类似的问题,并在我的回答中提出了解决方案。 【参考方案1】:

是的,你可以。使用魔术方法 __call__()__iter__() 创建辅助类,并将此类的实例作为函数提供给 BeautifulSoup find_all() 函数。我使用zip() 将组与匹配的元素联系起来:

from bs4 import BeautifulSoup, Tag
import re

data = '''<div>
<a href="link_1">Link 1</a>
<a href="link_2">Link 1</a>
<a href="link_XXX">Link 1</a>
<a href="link_3">Link 1</a>
</div>'''

soup = BeautifulSoup(data, 'lxml')

class my_regex_searcher:
    def __init__(self, regex_string):
        self.__r = re.compile(regex_string)
        self.groups = []

    def __call__(self, what):
        if isinstance(what, Tag):
            what = what.name

        if what:
            g = self.__r.findall(what)
            if g:
                self.groups.append(g)
                return True
        return False

    def __iter__(self):
        yield from self.groups

searcher = my_regex_searcher(r'link_(\d+)')
for l, groups in zip(soup.find_all(href=searcher), searcher):
    print(l)
    print(groups)

searcher = my_regex_searcher(r'(d)(i)(v)')
for l, groups in zip(soup.find_all(searcher), searcher):
    print(l.prettify())
    print(groups)

打印:

<a href="link_1">Link 1</a>
['1']
<a href="link_2">Link 1</a>
['2']
<a href="link_3">Link 1</a>
['3']
<div>
 <a href="link_1">
  Link 1
 </a>
 <a href="link_2">
  Link 1
 </a>
 <a href="link_XXX">
  Link 1
 </a>
 <a href="link_3">
  Link 1
 </a>
</div>
[('d', 'i', 'v')]

【讨论】:

这种方法假设每个成功的正则表达式测试对应一个搜索结果,如果有多个搜索条件则可能不是这样

以上是关于将 BeautifulSoup 4 的 `find_all` 与正则表达式一起使用时,如何访问正则表达式匹配捕获组?的主要内容,如果未能解决你的问题,请参考以下文章

BeautifulSoup文档4-详细方法 | 用什么方法对文档树进行搜索?

find_all的用法 Python(bs4,BeautifulSoup)

03_BeautifulSoup的使用2-搜索文档树

BeautifulSoup库之find_all函数

BeautifulSoup库findAll()find()方法详解

带有 BeautifulSoup 的 Python Requests/Selenium 每次都没有返回 find_all