如何使用 BeautifulSoup 和 Python 获取属性值?

新手上路,请多包涵

我在使用 BeautifulSoup 和 Python 获取属性值时失败得很惨。以下是 XML 的结构:

 ...
</total>
<tag>
    <stat fail="0" pass="1">TR=111111 Sandbox=3000613</stat>
    <stat fail="0" pass="1">TR=121212 Sandbox=3000618</stat>
    ...
    <stat fail="0" pass="1">TR=999999 Sandbox=3000617</stat>
</tag>
<suite>
...

我想要得到的是 pass 价值,但对于我的生活,我就是无法理解如何去做。我检查了 BeautifulSoup ,似乎我应该使用类似 stat['pass'] 的东西,但这似乎不起作用。

这是我的代码:

 with open('../results/output.xml') as raw_resuls:
results = soup(raw_resuls, 'lxml')
for stat in results.find_all('tag'):
            print stat['pass']

如果我这样做 results.stat['pass'] 它返回另一个标记内的值,在 XML blob 中向上。

如果我打印 stat 变量,我得到以下信息:

 <stat fail="0" pass="1">TR=787878 Sandbox=3000614</stat>
...
<stat fail="0" pass="1">TR=888888 Sandbox=3000610</stat>

这似乎没问题。

我很确定我遗漏了什么或做错了什么。我应该看哪里?我采取了错误的方法吗?

任何建议或指导将不胜感激!谢谢

原文由 user7656533 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 473
2 个回答

请考虑这种方法:

 from bs4 import BeautifulSoup

with open('test.xml') as raw_resuls:
    results = BeautifulSoup(raw_resuls, 'lxml')

for element in results.find_all("tag"):
    for stat in element.find_all("stat"):
        print(stat['pass'])

您的解决方案的问题是 pass 包含在 stat 中,而不是在您搜索它的 标签 中。

该解决方案搜索所有 _标签_,并在这些 标签 中搜索 stat 。从这些结果来看,它 通过 了。

对于 XML 文件

<tag>
    <stat fail="0" pass="1">TR=111111 Sandbox=3000613</stat>
    <stat fail="0" pass="1">TR=121212 Sandbox=3000618</stat>
    <stat fail="0" pass="1">TR=999999 Sandbox=3000617</stat>
</tag>

上面的脚本得到输出

1
1
1

添加

由于某些细节似乎仍不清楚(请参阅评论),请考虑使用 BeautifulSoup 这个完整的解决方法来获得您想要的一切。如果您遇到性能问题,这种使用字典作为列表元素的解决方案可能并不完美。但是由于您似乎在使用 Python 和 Soup 时遇到了一些麻烦,我想我尽可能简单地创建了这个示例,方法是提供按名称而不是索引访问所有相关信息的可能性。

 from bs4 import BeautifulSoup

# Parses a string of form 'TR=abc123 Sandbox=abc123' and stores it in a dictionary with the following
# structure: {'TR': abc123, 'Sandbox': abc123}. Returns this dictionary.
def parseTestID(testid):
    dict = {'TR': testid.split(" ")[0].split("=")[1], 'Sandbox': testid.split(" ")[1].split("=")[1]}
    return dict

# Parses the XML content of 'rawdata' and stores pass value, TR-ID and Sandbox-ID in a dictionary of the
# following form: {'Pass': pasvalue, TR': TR-ID, 'Sandbox': Sandbox-ID}. This dictionary is appended to
# a list that is returned.
def getTestState(rawdata):
    # initialize parser
    soup = BeautifulSoup(rawdata,'lxml')
    parsedData= []

    # parse for tags
    for tag in soup.find_all("tag"):
        # parse tags for stat
        for stat in tag.find_all("stat"):
            # store everthing in a dictionary
            dict = {'Pass': stat['pass'], 'TR': parseTestID(stat.string)['TR'], 'Sandbox': parseTestID(stat.string)['Sandbox']}
            # append dictionary to list
            parsedData.append(dict)

    # return list
    return parsedData

您可以按如下方式使用上面的脚本来做任何您想做的事情(例如,只需打印出来)

 # open file
with open('test.xml') as raw_resuls:
    # get list of parsed data
    data = getTestState(raw_resuls)

# print parsed data
for element in data:
    print("TR = {0}\tSandbox = {1}\tPass = {2}".format(element['TR'],element['Sandbox'],element['Pass']))

输出看起来像这样

TR = 111111 Sandbox = 3000613   Pass = 1
TR = 121212 Sandbox = 3000618   Pass = 1
TR = 222222 Sandbox = 3000612   Pass = 1
TR = 232323 Sandbox = 3000618   Pass = 1
TR = 333333 Sandbox = 3000605   Pass = 1
TR = 343434 Sandbox = ZZZZZZ    Pass = 1
TR = 444444 Sandbox = 3000604   Pass = 1
TR = 454545 Sandbox = 3000608   Pass = 1
TR = 545454 Sandbox = XXXXXX    Pass = 1
TR = 555555 Sandbox = 3000617   Pass = 1
TR = 565656 Sandbox = 3000615   Pass = 1
TR = 626262 Sandbox = 3000602   Pass = 1
TR = 666666 Sandbox = 3000616   Pass = 1
TR = 676767 Sandbox = 3000599   Pass = 1
TR = 737373 Sandbox = 3000603   Pass = 1
TR = 777777 Sandbox = 3000611   Pass = 1
TR = 787878 Sandbox = 3000614   Pass = 1
TR = 828282 Sandbox = 3000600   Pass = 1
TR = 888888 Sandbox = 3000610   Pass = 1
TR = 999999 Sandbox = 3000617   Pass = 1

让我们总结一下所使用的核心元素:

查找 XML 标签 要查找 XML 标签,您可以使用 soup.find("tag") 返回第一个匹配的标签或 soup.find_all("tag") 查找所有匹配的标签并将它们存储在列表中。通过遍历列表可以轻松访问单个标签。

查找嵌套标签 要查找嵌套标签,您可以使用 find()find_all() 再次将其应用于第一个 find_all() 的结果

访问标签的内容 要访问标签 的内容,您可以将 string 应用于单个标签。例如,如果 tag = <tag>I love Soup!</tag> tag.string = "I love Soup!"

查找属性值 要获取属性值,您可以使用下标表示法。例如,如果 tag = <tag color=red>I love Soup!</tag> tag['color']="red"

为了解析形式为 "TR=abc123 Sandbox=abc123" 的字符串,我使用了常见的 Python 字符串拆分。您可以在此处阅读更多相关信息: How can I split and parse a string in Python?

原文由 dtell 发布,翻译遵循 CC BY-SA 3.0 许可协议

问题是 find_all('tag') 返回标题为 tag 的整个 html 块:

 >>> results.find_all('tag')
[<tag>
<stat fail="0" pass="1">TR=111111 Sandbox=3000613</stat>
<stat fail="0" pass="1">TR=121212 Sandbox=3000618</stat>
<stat fail="0" pass="1">TR=999999 Sandbox=3000617</stat>
</tag>]

您的目的是收集每个 stat 块,因此您应该使用 results.find_all('stat')

 >>> stat_blocks = results.find_all('stat')
[<stat fail="0" pass="1">TR=111111 Sandbox=3000613</stat>, <stat fail="0" pass="1">TR=121212 Sandbox=3000618</stat>, <stat fail="0" pass="1">TR=999999 Sandbox=3000617</stat>]

从那里开始,修复代码以将“pass”压缩到列表中是微不足道的:

 >>> passes = [s['pass'] if s is not None else None for s in stat_blocks]
>>> passes
['1', '1', '1']

或打印:

 >>> for s in stat_blocks:
...     print(s['pass'])
...
1
1
1

在 Python 中,测试结果非常重要,因为输入过于动态以至于 无法 相信您的记忆。我经常在类和模块中包含一个静态 test 函数,以确保返回类型和值符合我的预期。

原文由 Aaron3468 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题