beautifulsoup table 树:找到两个对象之间的所有 tr?

beautifulsoup table tree: find all tr between two objects?

嗨,我有 HTML table 这样的(代码中的注释自我解释):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<tbody>
    <!-- there is a box -->
    <tr>RED BOX</tr>

        <!-- containing the following balls, each <td> has a ball -->
        <!-- may be more than one <tr> -->
        <tr>
            <td>ball 1</td>
            <td>ball 2</td>
        </tr>

        <tr>
            <td>ball 3</td>
        </tr>

    <!-- another box -->
    <tr>GREEN BOX</tr>

        <!-- containing the following balls -->
        <tr>
            <td>ball 4</td>
        </tr>

</tbody>

</body>
</html>

如代码中注释所示:RED BOX是一个tr,球1、2、3在RED BOX中,由球1、2、3为在 tr after <tr>RED BOX</tr> 中(球可能在一个或多个 tr 中)。 GREEN BOX是另一个tr,球4在tr之后。

我想找到每个盒子里的球。我可以通过

找到<tr>RED BOX</tr><tr>GREEN BOX</tr>
tr_box = bs.findAll(text=[regex 'something BOX'])

我可以使用

找到下一个tr
for t in tr_box:
    t[0].find_next('tr')

(可以找到球 1、2、4,但未找到球 3)

但是(1)有没有像find_between_objects这样的东西可以找到<tr>RED BOX</tr><tr>GREEN BOX</tr>之间的所有tr?或者一些将所有 tr 分成部分的函数,除以 <tr>RED BOX</tr><tr>GREEN BOX</tr>?

(2)如何找到<tr>GREEN BOX</tr>和table结尾之间的所有tr </tbody>

谢谢

选项 1: find_next_siblings()break 当您遇到带有 GREEN BOX.

的行时
red_box = soup.find("tr", text="RED BOX")
for row in red_box.find_next_siblings("tr"):
    if row.get_text(strip=True) == "GREEN BOX":
        break

    print([td.get_text(strip=True) for td in row.find_all("td")])

或者 itertools.takewhile() 如果你想更像 Pythonic 的话。

选项 2: a search function.

def filter_rows(tag):
    return tag.name == "tr" and \
           tag.find_previous_sibling("tr", text="RED BOX") and \
           tag.find_next_sibling("tr", text="GREEN BOX")

for row in soup.find_all(filter_rows):
    print([td.get_text(strip=True) for td in row.find_all("td")])

两个选项都会打印:

['ball 1', 'ball 2']
['ball 3']

(2) how to find all tr between GREEN BOX and the end of table ?

这只是:

green_box = soup.find("tr", text="GREEN BOX")
for row in green_box.find_next_siblings("tr"):
    print([td.get_text(strip=True) for td in row.find_all("td")])

这里不用打断循环,find_next_siblings()当没有其他匹配的兄弟姐妹时,自然会停止。


仅供参考,complete gist 此处。

如果您只想从 "boxes" 中获取 "balls",使用此方法可能更简单。找到所有 tr,然后在 tr 中找到所有 td

for tr in soup.find_all('tr'):
    for td in tr.find_all('td'):
        print(td.text)

打印:

ball 1
ball 2
ball 3
ball 4