【问题标题】:BeautifulSoup: `find_all` and `get_text`BeautifulSoup:`find_all` 和 `get_text`
【发布时间】:2019-12-20 09:51:51
【问题描述】:

我有一些格式如下的 xml:

  <Paragraph Type="Character">
   <Text>
    TED
   </Text>
  </Paragraph>
  <Paragraph Type="Dialogue">
   <Text>
    I thought we had a rule against that.
   </Text>
  </Paragraph>
  <Paragraph Type="Character">
   <Text>
    ANNIE
   </Text>
  </Paragraph>
  <Paragraph Type="Dialogue">
   <Text>
    ...oh.  

我正在尝试提取数据,使其看起来像这样:

Character   Dialogue

TED         I thought we had a rule against that.
ANNIE       ...oh. 

我一直在尝试:

soup.find(Type = "Character").get_text()
soup.find(Type = "Dialogue").get_text()

一次返回一行。当我尝试做不止一个时,soup.find_all,即:

soup.find_all(Type = "Character").get_text()

我得到错误:

AttributeError: ResultSet object has no attribute 'get_text'. You're probably treating a list of items like a single item. Did you call find_all() when you meant to call find()?

我知道find_all() 返回一个元素数组(感谢之前的回答:https://stackoverflow.com/a/21997788/8742237),我应该选择数组中的一个元素,但我想获取数组中的所有元素变成我上面展示的格式。

【问题讨论】:

    标签: python xml beautifulsoup


    【解决方案1】:

    要获得一对CharacterDialogue,可以使用zip()方法:

    html_data = '''  <Paragraph Type="Character">
       <Text>
        TED
       </Text>
      </Paragraph>
      <Paragraph Type="Dialogue">
       <Text>
        I thought we had a rule against that.
       </Text>
      </Paragraph>
      <Paragraph Type="Character">
       <Text>
        ANNIE
       </Text>
      </Paragraph>
      <Paragraph Type="Dialogue">
       <Text>
        ...oh.
       </Text>
      </Paragraph>
      '''
    
    from bs4 import BeautifulSoup
    
    soup = BeautifulSoup(html_data, 'html.parser')
    
    print('{: <10} {}'.format('Character', 'Dialogue'))
    print()
    for character, dialogue in zip(soup.select('[Type="Character"]'), soup.select('[Type="Character"] + [Type="Dialogue"]')):
        print('{: <10} {}'.format( character.get_text(strip=True), dialogue.get_text(strip=True)) )
    

    打印:

    Character  Dialogue
    
    TED        I thought we had a rule against that.
    ANNIE      ...oh.
    

    CSS 选择器[Type="Character"] + [Type="Dialogue"] 将选择带有Type=Dialogue 的标签,该标签紧跟在带有Type=Character 的标签之后

    更多:CSS Selectors Reference

    【讨论】:

    • 对于将来遇到这个问题的人来说,上面的 CSS 选择器参考链接非常好。
    • 我仍在努力解决这个问题,因为我仍在学习和搜索每个命令。如果我想将输出保存在列表或 zip 对象中,有没有简单的方法可以做到这一点?
    • 没关系,我想通了。谢谢。
    【解决方案2】:

    您是否尝试过遍历数组并获取这样的文本?

    [x.get_text() for x in soup.find_all(Type = "Character")]
    

    数组没有 get_text() 属性,但元素应该有。

    【讨论】:

    • 效果很好,我会考虑通过循环提取所有内容。您对如何将 Dialogue 文本与紧接在其前面的 Character 文本配对,如我上面显示的所需输出有什么建议吗?
    • 在这种情况下我不会使用find_all(),因为您现在有两个单独的段落列表,它们可能并不完全相关。相反,使用find() 获取第一段,然后使用next_siblingwhile 循环中移动到下一段。检查每个段落的类型以决定如何格式化。
    • 只创建字符列表,然后创建对话列表并执行 list(zip(character list, dialog list)) 假设列表的长度相同。这将使他们配对
    【解决方案3】:

    Andrej Kesely 的答案正是我想要的: https://stackoverflow.com/a/57484760/8742237

    以防万一以后看到这个问题的人是初学者,我尝试将其分解:

    list1 = [x.get_text(strip = True) for x in soup.select('[Type="Character"]')]
    print(list1)
    
    list2 = [x.get_text(strip = True) for x in soup.select('[Type="Dialogue"]')]
    print(list2)
    
    zip1 = zip(list1, list2)
    print(list(zip1))
    

    【讨论】:

      猜你喜欢
      • 2014-03-26
      • 2016-01-23
      • 1970-01-01
      • 2021-01-22
      • 1970-01-01
      • 2015-12-27
      • 2012-09-02
      • 2016-05-09
      相关资源
      最近更新 更多