【问题标题】:Using BeautifulSoup to Parse XML to a Dictionary使用 BeautifulSoup 将 XML 解析为字典
【发布时间】:2014-11-11 18:52:58
【问题描述】:

我有一段如下所示的 XML:

 <ns:Vehicle>
  <ns:Model>AVALON</ns:Model>
  <ns:ModelYear>1998</ns:ModelYear>
  <ns:MakeString>TY</ns:MakeString>
  <ns:VehicleID>VIN NUMBER GOES HERE</ns:VehicleID>
 </ns:Vehicle>

我有以下代码将车辆元素变成字典:

xml_file = open('6046179.xml')
soup = BeautifulSoup(xml_file)

# Vehicle elements
el_model = soup.find('ns:model').text
el_model_year = soup.find('ns:modelyear').text
el_make_string = soup.find('ns:makestring').text
el_vehicle_id = soup.find('ns:vehicleid').text

vehicle = {'model': '{}'.format(el_model),
           'model_year': '{}'.format(el_model_year),
           'make_string': '{}'.format(el_make_string),
           'vehicle_id': '{}'.format(el_vehicle_id)}

print vehicle

我只是想知道是否有更好的方法来做到这一点,我不介意遍历 XML 中的其余元素并像这样单独定义它们,我只是想知道是否有更清洁的方法来做到这一点。

【问题讨论】:

    标签: xml python-2.7 beautifulsoup


    【解决方案1】:

    可能会更干净一些,但本质上没有什么不同:

    tags = ['model', 'modelyear', 'makestring', 'vehicleid']
    vehicle = {}
    for tag in tags:
        vehicle[tag] = '{}'.format(soup.find('ns:' + tag).text)
    

    还有 xmltodict 可能值得一看。

    【讨论】:

    • 我尝试了 xmltodict,而我正在使用的 xml 是一大堆嵌套的 OrderedDict。谢谢你的解决方案,比我的干净得多。
    【解决方案2】:

    如果您想要所有 &lt;ns:Vehicle&gt; 元素内的子节点,则无需显式指定它们 - 只需遍历所有子元素并将它们放入字典中即可。

    from bs4 import BeautifulSoup
    
    soup = BeautifulSoup('''
     <ns:Vehicle>
      <ns:Model>AVALON</ns:Model>
      <ns:ModelYear>1998</ns:ModelYear>
      <ns:MakeString>TY</ns:MakeString>
      <ns:VehicleID>VIN NUMBER GOES HERE</ns:VehicleID>
     </ns:Vehicle>
     ''')
    
    # loop if you have multiple vehicles
    # Note that BS normalizes all tag names to lowercase -> we use 'ns:vehicle' rather 'ns:Vehicle'
    for el_vehicle in soup.find_all('ns:vehicle'): 
        vehicle = {child.name: child.text for child in el_vehicle.findChildren()}
        # stick `vehicle` in a list or do some other processing
    

    这与您的输出不完全匹配,因为它不会从驼峰式转换为下划线分隔的名称(例如,ModelYearmodel_year),并且它也不会从元素名称中剥离命名空间。如果您需要,在child.name 周围包含一个包装器以相应地更改名称应该不会太难。

    【讨论】:

      【解决方案3】:

      BeautifulSoup 并不真正适用于 XML - 它是杂乱的 HTML 的理想选择,这会破坏正确的解析器。

      你最好使用etree 接口(也许通过非常快的lxml),无论如何,IIRC 是 BS 默认使用的。然后你得到根元素并在几行代码中遍历它的所有子元素,例如:

      #!/usr/bin/env python
      
      import xml.etree.ElementTree as ET
      import re
      
      # Note the dummy namespace that must / should have been there...
      xml = '''
       <ns:Vehicle xmlns:ns="http://foo.bar">
        <ns:Model>AVALON</ns:Model>
        <ns:ModelYear>1998</ns:ModelYear>
        <ns:MakeString>TY</ns:MakeString>
        <ns:VehicleID>VIN NUMBER GOES HERE</ns:VehicleID>
       </ns:Vehicle>'''
      
      tree = ET.fromstring(xml)
      vehicle = {re.sub(r'{.*}', '', node.tag): node.text for node in tree}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多