【问题标题】:Populate value with Beautifulsoup when tag is empty标签为空时使用 Beautifulsoup 填充值
【发布时间】:2020-04-20 09:15:36
【问题描述】:

我正在尝试解析网页中某个类的所有 td 标签的内容,但即使标签本身没有,我也希望拥有某种占位符内容。例如,html 包含这样的 td 标签:

<td class="odds bdevtt moneylineodds " cfg="">+134</td>
<td class="odds bdevtt moneylineodds " cfg=""></td>
<td class="odds bdevtt moneylineodds " cfg="">-140</td>

我正在尝试获取类似 ['+134', '-', '-140'] 的列表作为输出,因此列表中的条目数等于带有 '-' 的匹配标签的数量作为一个占位符,表示标签为空。然而,下面只返回 ['+134','-140']。

soup.find_all('td', attrs={'class': 'odds bdevtt moneylineodds '})

【问题讨论】:

    标签: python html parsing beautifulsoup tags


    【解决方案1】:

    一种可能的解决方案是使用or 运算符:

    out = [td.get_text(strip=True) or '-' for td in soup.select('td.odds.bdevtt.moneylineodds')]
    print(out)
    

    打印:

    ['+134', '-', '-140']
    

    一些快速基准测试:

    txt = '''<td class="odds bdevtt moneylineodds " cfg="">+134</td>
    <td class="odds bdevtt moneylineodds " cfg=""></td>
    <td class="odds bdevtt moneylineodds " cfg="">-140</td>'''
    ​
    from bs4 import BeautifulSoup
    from timeit import timeit
    ​
    soup = BeautifulSoup(txt, 'html.parser')
    ​
    def using_or():
        return [td.get_text(strip=True) or '-' for td in soup.select('td.odds.bdevtt.moneylineodds')]
    ​
    def using_if_else_1():
        return [td.text if td.text else '-' for td in soup.select('td.odds.bdevtt.moneylineodds')]
    ​
    def using_if_else_2():
        return [t if (t := td.get_text(strip=True)) else '-' for td in soup.select('td.odds.bdevtt.moneylineodds')]
    ​
    ​
    t1 = timeit(lambda: using_or(), number=10_000)
    t2 = timeit(lambda: using_if_else_1(), number=10_000)
    t3 = timeit(lambda: using_if_else_2(), number=10_000)
    ​
    print(t1)
    print(t2)
    print(t3)
    ​
    

    打印出来:

    0.7735823660041206
    0.8084569670027122
    0.776867889042478
    

    看起来,解决方案在性能方面是 +/- 相同的。

    【讨论】:

    • 有趣。你知道orif else 在效率方面的比较吗?
    • 感谢您添加。想知道 2 和 3 发生了什么。甚至在更大的测试规模上。
    • @QHarr 我让它们每个运行 1_000_000 次,结果是 78.19792580400826, 81.93139944702853, 79.0471791360178,所以是的 or 方法有 slight 领先。方法 2 正在丢失,因为 td.text 被访问了 2 次。
    【解决方案2】:
    from bs4 import BeautifulSoup
    
    html = """
    <td class="odds bdevtt moneylineodds " cfg="">+134</td>
    <td class="odds bdevtt moneylineodds " cfg=""></td>
    <td class="odds bdevtt moneylineodds " cfg="">-140</td>
    """
    soup = BeautifulSoup(html,"html.parser")
    all = [i.text if i.text != "" else "-" for i in soup.find_all('td', attrs={'class': 'odds bdevtt moneylineodds '})]
    print(all)
    
    # output: ['+134', '-', '-140']
    

    【讨论】:

      【解决方案3】:

      去掉class属性值的尾随空格,你会得到预期的结果。

      代码:

      for elm in soup.find_all('td', attrs={'class': 'odds bdevtt moneylineodds'}):
        print(elm.text)
      

      输出:

      +134
      
      -140
      

      原因是在你执行代码时

      html = """
      <td class="odds bdevtt moneylineodds " cfg="">+134</td>
      <td class="odds bdevtt moneylineodds " cfg=""></td>
      <td class="odds bdevtt moneylineodds " cfg="">-140</td>
      """
      soup = BeautifulSoup(html,"html.parser")   # <-- It will trim the trailing spaces from class value
      print(soup)
      

      输出:

      <td cfg="" class="odds bdevtt moneylineodds">+134</td>
      <td cfg="" class="odds bdevtt moneylineodds"></td>
      <td cfg="" class="odds bdevtt moneylineodds">-140</td>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-10-22
        • 1970-01-01
        • 1970-01-01
        • 2012-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多