【问题标题】:Find a List of Tags Based on Text Value of Children in Beautiful Soup根据Beautiful Soup中儿童的文本值查找标签列表
【发布时间】:2013-12-09 17:22:03
【问题描述】:

我有一个关于使用其子项属性之一的条件选择标签列表(或单个标签)的问题。具体来说,给定 HTML 代码:

<tbody>
<tr class="" data-row="0">
<tr class="" data-row="1">
<tr class="" data-row="2">
    <td align="right" csk="13">13</td>
    <td align="left" csk="Jones,Andre"><a href="/players/andre-jones-2.html">Andre Jones</a>       
    </td>
<tr class="" data-row="3">
    <td align="right" csk="7">7</td>
    <td align="left" csk="Jones,DeAndre"><a href="/players/deandre-jones-1.html">DeAndre Jones</a>
    </td>
 <tr class="" data-row="4">
 <tr class="" data-row="5">

我有一个来自外部循环的 unicode 变量,我试图查看表中的每一行以提取带有Player==Table.tr.a.text&lt;tr&gt; 标记,并在Table 中识别重复的玩家名称。因此,例如,如果有多个玩家使用Player=Andre Jones,则MyRow 对象返回所有包含该玩家名称的&lt;tr&gt; 标签,而如果只有一行带有Player=Andre Jones,则MyRow 只是包含单个元素&lt;tr&gt;,其锚文本属性等于Andre Jones。我一直在尝试类似

Table = soup.find('tbody')
MyRow = Table.find_all(lambda X: X.name=='tr' and Player == X.text)

但这会为MyRow 返回[]。如果我使用

MyRow = Table.find_all(lambda X: X.name=='tr' and Player in X.text)

这将选择任何具有Player&lt;tr&gt; 作为X.text 的子字符串。在上面的示例代码中,它使用Table.tr.td.a.text=='Andre Jones'Table.tr.td.a.text=='DeAndre Jones' 提取&lt;tr&gt; 标签。任何帮助将不胜感激。

【问题讨论】:

    标签: python python-2.7 beautifulsoup


    【解决方案1】:

    随心所欲。 :)

    解决方案1

    逻辑:在该标签的文本中找到第一个标签名称为 tr 且包含“FooName”的标签,包括其子标签。

    # Exact Match  (text is unicode, turn into str)
    print Table.find(lambda tag: tag.name=='tr' and 'FooName' == tag.text.encode('utf-8'))
    # Fuzzy Match
    # print Table.find(lambda tag: tag.name=='tr' and 'FooName' in tag.text)
    

    输出:

    <tr class="" data-row="2">
    <td align="right" csk="3">3</td>
    <td align="left" csk="Wentz,Parker">
    <a href="/players/Foo-Name-1.html">FooName</a>
    </td>
    </tr>
    

    解决方案2

    逻辑:查找其文本包含FooName 的元素,在本例中为anchor 标签。然后上树搜索标签名为tr的所有父母(包括祖先)

    # Exact Match
    print Table.find(text='FooName').find_parent('tr')
    # Fuzzy Match
    # import re
    # print Table.find(text=re.compile('FooName')).find_parent('tr')
    

    输出

    <tr class="" data-row="2">
    <td align="right" csk="3">3</td>
    <td align="left" csk="Wentz,Parker">
    <a href="/players/Foo-Name-1.html">FooName</a>
    </td>
    </tr>
    

    【讨论】:

    • 太棒了!非常感谢您的帮助。
    • @MarkClements 请将最能帮助您的答案标记为已接受,以便其他人可以轻松搜索。
    • 代码似乎匹配名字或姓氏,而不是整个名字。因此,它不仅将“Andre Jones”和“DeAndre Jones”视为相同,而且将“Terrance”和“Terrance Saulsberry”视为相同。
    • 我在使用解决方案 1 或解决方案 2 时遇到了问题。我在 &lt;a&gt; 的文本属性中的两个不同行中有两个名称 "Andre Jones""DeAndre Jones"。然而,该代码只挑选出带有“DeAndre Jones”的&lt;tr&gt; 标签。我可以看到这一点,因为如果我在解决方案 1 和 Player="Andre Jones" 中使用 find_all,它会返回一个包含两个元素的列表:&lt;tr&gt; 带有文本 "Andre Jones""DeAndre Jones" 的标签。但是,如果Player="DeAndre Jones" 代码返回一个包含单个元素的列表:&lt;tr&gt; 标记和文本"DeAndre Jones"。我不知道这里发生了什么。
    • @MarkClements 我注释掉了旧逻辑并将完全匹配的解决方案放在那里。我正在使用fuzzy match,它试图查找包含 fooname 的标签,这就是它为您返回多条记录的原因。如果您还有其他名称匹配问题,例如使用我已注释掉的正则表达式方法,您需要自定义我编写的函数以满足您的口味。
    【解决方案2】:

    您可以使用 XPath 和 lxml 轻松做到这一点:

    import lxml.html
    
    root = lxml.html.fromstring('''...''')
    td = root.xpath('//tr[.//a[text() = "FooName"]]')
    

    BeautifulSoup “等效”类似于:

    rows = soup.find('tbody').find_all('tr')
    td = next(row for row in rows if row.find('a', text='FooName'))
    

    或者如果你反过来想:

    td = soup.find('a', text='FooName').find_parent('tr')
    

    【讨论】:

    • 你提供的漂亮的汤代码只会让我第一次出现text='FooName'。我已经完善了我的问题,以更具体地说明我在寻找什么。感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多