Одним из решений было бы передать функцию в soup.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
Примечание: я не могу сказать, что это масштабировалось бы исключительно хорошо, потому что он использует вложенный цикл for для проверки каждой строки в каждом <td>
теге. Но, надеюсь, это сделает работу. Возможно, было бы не очень хорошей идеей просто использовать .text
, потому что это будет захватывать и другие вложенные теги, которые вы указали, что вы не хотели. Другой оптимизацией было бы сделать ленивую версию генератора из find_all()
.