如何迭代地解析和保存作为一个字符串出现的XML响应?

时间:2017-08-21 15:11:22

标签: python xml xml-parsing api-design

我正在进行API调用,即检索ID,每次调用代表10000个ID,我一次只能检索10000个。 我的目标是将每个XML调用保存到一个列表中,以自动计算平台中有多少人。

我遇到的问题有两个问题。

  1. 每个调用都作为响应对象,当我附加到列表时,响应对象追加为单个字符串,因此我无法计算ID的总数

  2. 要获取下一个10000个ID列表,我必须使用另一个API调用来获取有关每个ID的信息,并检索一条名为网站ID的信息,并使用该信息从#中调用下一个10000 1

  3. 我还想阻止列表中的任何重复ID,但我觉得这是最简单的任务。

    这是我的代码:

    1

    • 呼叫配置文件ID(每次呼叫带回10000)
    • 将响应对象'r'追加到列表'lst'

      导入请求     将xml.etree.ElementTree导入为et     将pandas导入为pd     来自lxml import etree     进口时间

      lst = []
      
      
      
      xml = '''
      <?xml version="1.0" encoding="utf-8" ?>
      <YourMembership>
          <Version>2.25</Version>
          <ApiKey>*****</ApiKey>
          <CallID>009</CallID>
          <SaPasscode>*****</SaPasscode>
          <Call Method="Sa.People.All.GetIDs">
              <Timestamp></Timestamp>
              <WebsiteID></WebsiteID>
              <Groups>
                  <Code></Code>
                  <Name></Name>
              </Groups>
          </Call>
      </YourMembership>
      '''
      headers = {'Content-Type': 'application/x-www-form-urlencoded'}
      r = requests.post('https://api.yourmembership.com', data=xml, headers=headers)
      lst.append(r.text)
      

    API调用结果

    <YourMembership_Response>
    <Sa.People.All.GetIDs>
    <People>
    <ID>1234567</ID>
    </People>
    </Sa.People.All.GetIDs>
    </YourMembership_Response>
    

    2

    • 我从#1中的API调用中获取最后一个ID并手动输入该值 进入下面的“ID”标签中的API调用。

      xml_2 = '''
      <?xml version="1.0" encoding="utf-8" ?>
      
      <YourMembership>
          <Version>2.25</Version>
          <ApiKey>****</ApiKey>
          <CallID>001</CallID>
          <SaPasscode>****</SaPasscode>
          <Call Method="Sa.People.Profile.Get">
              <ID>1234567</ID>
          </Call>
      </YourMembership>
      '''
      headers = {'Content-Type': 'application/x-www-form-urlencoded'}
      r_2 = requests.post('https://api.yourmembership.com', data=xml_2, headers=headers)
      print (r_2.text)
      

    API调用结果:

    <YourMembership_Response>
    <ErrCode>0</ErrCode>
    <ExtendedErrorInfo></ExtendedErrorInfo>
    <Sa.People.Profile.Get>
    <ID>1234567</ID>
    <WebsiteID>7654321</WebsiteID>
    </YourMembership_Response>
    

    我获取网站ID,并在填写了网站ID标签的#1(示例)的API调用中重新运行此代码,获取下一个10000,直到没有更多结果返回:

    xml = '''
            <?xml version="1.0" encoding="utf-8" ?>
            <YourMembership>
                <Version>2.25</Version>
                <ApiKey>*****</ApiKey>
                <CallID>009</CallID>
                <SaPasscode>*****</SaPasscode>
                <Call Method="Sa.People.All.GetIDs">
                    <Timestamp></Timestamp>
                    <WebsiteID>7654321</WebsiteID>
                    <Groups>
                        <Code></Code>
                        <Name></Name>
                    </Groups>
                </Call>
            </YourMembership>
            '''
            headers = {'Content-Type': 'application/x-www-form-urlencoded'}
            r = requests.post('https://api.yourmembership.com', data=xml, headers=headers)
            lst.append(r.text)
    

    希望我的问题有道理,并提前感谢你。

1 个答案:

答案 0 :(得分:1)

我曾经开始构建一些东西来爬行API,这听起来与你想要实现的类似。我的情况有一个不同之处是响应来自json而不是xml,但不应该是一个大问题。

在您的问题中无法证明您确实在使用xml解析器的强大功能。看看docs。例如,您可以轻松地从您要添加到列表中的项目中获取ID号:

xml_sample = """
<YourMembership_Response>
<Sa.People.All.GetIDs>
<People>
<ID>1234567</ID>
</People>
</Sa.People.All.GetIDs>
</YourMembership_Response>
"""

import xml.etree.ElementTree as ET
root = ET.fromstring(xml_sample)
print (root[0][0][0].text)
>>> '1234567'

实验,将它应用于循环中列表中的每个元素,或者您将很幸运,整个响应对象将解析而无需查看事物。

您现在应该能够以编程方式而不是在下一位代码中手动输入该数字。

您的网站ID下一部分的XML似乎在其中包含无效行<Sa.People.Profile.Get>一旦我将其删除,就可以对其进行解析:

xml_sample2 = """
<YourMembership_Response>
<ErrCode>0</ErrCode>
<ExtendedErrorInfo></ExtendedErrorInfo>

<ID>1234567</ID>
<WebsiteID>7654321</WebsiteID>
</YourMembership_Response>
"""
root2 = ET.fromstring(xml_sample2)
print (root2[3].text)
>>> '7654321'

因此不确定那里是否总是存在无效行,或者如果您忘记粘贴某些内容,可能会在应用xtree之前使用正则表达式删除该行。

建议您尝试使用sqlite来帮助您完成 1 2 之间的互动。我认为它可以达到五十万行,否则你需要挂钩到一个合适的数据库。它将文件保存在您的目录中,并且与正确的数据库相比,设置时间和使用时间更少。也许,用sqlite测试这个概念,如果需要,可以迁移到postgresql。

您可以将您喜欢用户ID,网站ID的解析后的xml中的任何有用元素存储到表中,然后再将其拉出以用于其他部分。如果您需要使用pandas.read_sqlpandas.DataFrame.to_sql并希望这有帮助,也很难从sqlite到pandas数据帧来回转换..