我很失败地使用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>
这似乎没问题。
我很确定我错过了什么或做错了什么。我应该在哪里看?我采取了错误的做法吗?
非常感谢任何建议或指导!感谢
答案 0 :(得分:9)
请考虑这种方法:
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'])
您的解决方案的问题是传递包含在 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和S汤时遇到了一些麻烦,我认为通过提供按名称而不是索引访问所有相关信息的可能性,我可以尽可能简单地创建此示例。
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?
答案 1 :(得分:1)
问题是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>]
从那里,修复代码以将“传递”压缩到列表中是微不足道的:
>>> 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中,测试结果非常重要,因为输入 way 太动态,无法信任你的记忆。我经常在类和模块中包含静态test
函数,以确保返回类型和值是我期望的。
答案 2 :(得分:0)
您的“标记”可以包含多个“统计”条目。你只有一个“标签”条目吗?
如果是,则首先找到“tag”,然后遍历“tag”条目中包含的“stat”条目。类似的东西:
for stat in soup.find("tag").find_all("stat"):
print(stat["pass"])
答案 3 :(得分:0)
如果您像我一样在这里寻求最简单和简短的解决方案,请尝试使用此方法从您的标签中获取属性。
soup = BeautifulSoup('''
<html>
<h2 class="hello"> Heading 1 </h2>
<h1> Heading 2 </h1>
</html>
''', "lxml")
# Get the whole h2 tag
tag = soup.h2
# Get the attribute
attribute = tag['class']