是否有可能在BeautifulSoup4中通过HTML-Tree迭代



示例html('x.html'in python snippet):

<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解析器会更容易?

正如@danielle在评论中所建议的那样,您可以获得外部tr.contents。但是,由于您正在从此文件中读取,因此您将获得许多"n"和其他不需要的元素。您可以检查isinstance(x,Tag)是否仅获取标签内容。

在某些情况下,HTML不正确,可能没有这样的简单解决方案。在这种情况下,您也可以将自定义功能传递给find_all。例如。您要查找的数据也可以使用此逻辑获得 - 在文件的第一个表中找到所有tdtable标签。当然,逻辑可以与此不同,但是您会得到这个想法。

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

最新更新