#python #html #beautifulsoup
#python #HTML #beautifulsoup
Вопрос:
Пример HTML (‘x.html ‘ в фрагменте python):
<table>
<tr>
<td>a</td>
<td>b</td>
<table><tr><td>c</td></tr></table>
</tr>
</table>
Я хочу получить список с тремя столбцами из одной строки в таблице:
[
'<td>a</td>',
'<td>b</td>',
'<table><tr><td>c</td></tr></table>'
]
Я попытался просто выполнить итерацию по BeautifulSoup
объекту, но он возвращает весь HTML и пустую (ну, 'n'
) строку.
In [9]: soup = BeautifulSoup(open('x.html').read(), 'html.parser')
In [10]: for a in soup:
...: print(type(a))
...:
<class 'bs4.element.Tag'>
<class 'bs4.element.NavigableString'>
Я также пытался использовать find_all()
метод, но он находит вложенные <td>c</td>
, которые я не хочу видеть в результатах:
In [24]: len(soup.find_all('td'))
Out[24]: 4 # <-- I need 3 things, not 4
Я думал, что параметр find / find_all recursive
относится к вложенным элементам, но я не понимаю, работает ли это вообще:
Signature: soup.find_all(name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs)
In [26]: len(soup.find_all('td', recursive=False))
Out[26]: 0
Может быть, написать xml.sax
синтаксический анализатор будет проще?
Комментарии:
1. К вашему сведению, я не верю, что наличие a
<table>
в качестве дочернего элемента a<tr>
является допустимым html.2.
find
внешний<tr>
, а затем изучите.contents
— вы должны увидеть дочерние теги, которые похожи на то, что вы ищете.
Ответ №1:
Как предложила @Danielle в комментарии, вы можете получить .contents
из внешнего tr
. Но поскольку вы читаете из этого файла, вы получите ряд "n"
и других нежелательных элементов вместе с этим. Вы можете проверить, isinstance(x,Tag)
чтобы получить только содержимое тега.
В некоторых ситуациях с неправильным html может не быть такого простого решения, как это. В этих случаях вы также можете передать пользовательскую функцию в find_all
. Например. Данные, которые вы ищете, также могут быть получены с помощью этой логики — Найдите все td
и table
теги в первой таблице файла. Конечно, логика может отличаться от этой, но вы поняли идею.
from bs4 import BeautifulSoup
from bs4 import Tag
soup = BeautifulSoup(open('x.html').read(), 'html.parser')
#solution 1
print([x for x in soup.find('tr').contents if isinstance(x,Tag)])
#solution 2 with a custom function
first_table=soup.find('table')
def is_td_or_table(item):
if isinstance(item,Tag):
if item.name in ['td','table'] and item.find_parent("table") is first_table:
return True
print(first_table.find_all(is_td_or_table))