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

时间:2017-04-03 20:47:30

标签: python beautifulsoup

我很失败地使用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>

这似乎没问题。

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

非常感谢任何建议或指导!感谢

4 个答案:

答案 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']