首页 文章

Python中的BeautifulSoup中的.find()

提问于
浏览
2

我正在尝试使用Beautiful Soup来搜索html文档 . 有没有办法在文档中搜索包含某些关键字字符串的表?例如,如果我有 table :

<table>
  <tr>
    <td> 'abc' </td>
    <td> 'other data' </td>
  </tr>
  <tr>
    <td> 'def' </td>
    <td> 'other data' </td>
  </tr>
  <tr>
    <td> '123' </td>
    <td> 'other data' </td>
  </tr>
  <tr>
    <td> '456' </td>
    <td> 'other data' </td>
  </tr>
</table>

在一个包含许多其他表的html文档中,但这是唯一一个包含字符串“abc”,“def”和“456”的表,是否有办法搜索此表?

我的想法是使用for循环来搜索所有表格,行和数据,但这似乎是不必要的步骤数(文档非常大) . 是否有办法使用BeautifulSoup形成问题,(显然这不起作用,但也许它可以让我知道我想要写的东西):

.find('table', string=('abc'), string=('def'), string=re.compile('456'))

编辑:是的,表需要所有这些字符串 . html文件还包含其他表,这些表可能包含任何这些字符串,但只有1个表包含所有3个字符串 . 是的,我只会在标签中寻找字符串(可能是'text'而不是'string',我不确定区别) .

1 回答

  • 1

    一个解决方案是pass a functionsoup.find() . 该函数必须采用一个且只有一个参数( bs4.element.Tag 对象),其目的是仅返回True或False:如果表符合您设置的条件,则返回True .

    如果您想测试不同的字符串,可以从一个带有两个参数的函数开始,然后使用 functools.partial() 将其缩减为一个:

    from functools import partial
    
    def _table_contains_strs(tag, strings):
        """Return True if `tag` has <td> tags that contain `strings`."""
        if tag.name != 'table':
            return False
        tds = tag.find_all('td')
        if not tds:
            return False
        test = {s: False for s in strings}
        for tag in tds:
            for s in strings:
                if s in tag:
                    test[s] = True
            if all(test.values()):
                # You can return early (without full iteration)
                # if all strings already matched.
                return True
        return False
    
    def _make_single_arg_function(func, *args, **kwargs):
        return partial(_table_contains_strs, *args, **kwargs)
    
    table_contains_strs = _make_single_arg_function(
        _table_contains_strs,
        strings=('abc', 'def', '456')
    )
    

    现在 table_contains_strs 是一个带有单个参数的函数, Tag .

    这是一个例子:

    from bs4 import BeautifulSoup
    
    # Add some text to other tags to make sure you're
    # finding only in <td>s
    html = """\
    <table>
        <th>field1</th>
        <th>field2</th>
      <tr>
        <td>abc</td>
        <td>other data</td>
      </tr>
      <tr>
        <td>def</td>
        <td>other data</td>
      </tr>
      <tr>
        <td>123</td>
        <td>other data</td>
      </tr>
      <tr>
        <td>456</td>
        <td>other data</td>
      </tr>
    </table>"""
    
    soup = BeautifulSoup(html, 'html.parser')
    
    soup.find(table_contains_strs)
    # Should return the table above
    

    注意:我可以't say this would scale exceptionally well because it'使用嵌套的for循环来检查每个 <td> 标记中的每个字符串 . 但希望它能完成工作 . 使用 .text 可能不是一个好主意,因为这也会捕获其他嵌套标记,您指定的是您不想要的 . 另一个优化是使 find_all() 的惰性generator version .

相关问题