首页 > 解决方案 > 使用美丽的汤从各种标签中提取标题

问题描述

我如何使用漂亮的汤从以下 html 中的两种表格类型中提取表格标题

<body>
    <p>some other data 1</p>
    <p>Table1 heading</p>
    <div></div>
    <div>
        <div><table width="15%"><tbody>
            <tr>
                <td><p>data1_00</p></td>
                <td><p>data1_01</p></td>
            </tr>
            <tr>
                <td><p>data1_10</p></td>
                <td><p>data1_11</p></td>
            </tr>
        </tbody></table></div>
    </div>

    <br><br>

    <div>some other data 2</div>
    <div>Table2 heading</div>
    <div>
        <div><table width="15%"><tbody>
            <tr>
                <td><p>data2_00</p></td>
                <td><p>data2_01</p></td>
            </tr>
            <tr>
                <td><p>data2_10</p></td>
                <td><p>data2_11</p></td>
            </tr>
        </tbody></table></div>
    </div>
</body>

在第一个表中,标题在<p>标签内,在第二个表上,标题在<div>标签内。同样在第二张桌子上,桌子<div>上方有一个空白标签。
如何提取两个表格标题?

目前我正在<div>使用上面的当前表搜索上一个,table.find_previous('div')其中的文本将保存为标题。

from bs4 import BeautifulSoup
import urllib.request

htmlpage = urllib.request.urlopen(url)
    page = BeautifulSoup(htmlpage, "html.parser")
    all_divtables = page.find_all('table')
    for table in all_divtables:
        curr_div = table
        while True:
            curr_div = curr_div.find_previous('div')
            if len(curr_div.find_all('table')) > 0:
                continue
            else:
                heading = curr_div.text.strip()
                print(heading)
                break

所需的输出:
Table1 heading
Table2 heading

标签: pythonhtmlpython-3.xbeautifulsoupscrapy

解决方案


您可以使用find_previous()带有 lambda 参数的函数,该函数选择不包含其他表且不包含空字符串的前一个标记:

data = '''<body>
    <p>some other data 1</p>
    <p>Table1 heading</p>
    <div></div>
    <div>
        <div><table width="15%"><tbody>
            <tr>
                <td><p>data1_00</p></td>
                <td><p>data1_01</p></td>
            </tr>
            <tr>
                <td><p>data1_10</p></td>
                <td><p>data1_11</p></td>
            </tr>
        </tbody></table></div>
    </div>

    <br><br>

    <div>some other data 2</div>
    <div>Table2 heading</div>
    <div>
        <div><table width="15%"><tbody>
            <tr>
                <td><p>data2_00</p></td>
                <td><p>data2_01</p></td>
            </tr>
            <tr>
                <td><p>data2_10</p></td>
                <td><p>data2_11</p></td>
            </tr>
        </tbody></table></div>
    </div>

    <div>some other data 3</div>
    <div>Table3 heading</div>
    <div>
        <div><table width="15%"><tbody>
            <tr>
                <td><p>data2_00z</p></td>
                <td><p>data2_01z</p></td>
            </tr>
            <tr>
                <td><p>data2_10z</p></td>
                <td><p>data2_11z</p></td>
            </tr>
        </tbody></table></div>
    </div>
    <div>
        <div><table width="15%"><tbody>
            <tr>
                <td><p>data2_00x</p></td>
                <td><p>data2_01x</p></td>
            </tr>
            <tr>
                <td><p>data2_10x</p></td>
                <td><p>data2_11x</p></td>
            </tr>
        </tbody></table></div>
    </div>

</body>'''

from bs4 import BeautifulSoup

soup = BeautifulSoup(data, 'lxml')

for table in soup.select('table'):
    for i in table.find_previous(lambda t: not t.find('table') and t.text.strip() != ''):
        if i.find_parents('table'):
            continue
        print(i)
        print('*' * 80)

印刷:

Table1 heading
********************************************************************************
Table2 heading
********************************************************************************
Table3 heading
********************************************************************************

推荐阅读