【问题标题】:Recursively search xml by entry按条目递归搜索xml
【发布时间】:2012-01-26 20:44:30
【问题描述】:

我有一个来自 Google 的 XML 提要,总共大约 300 个条目。它看起来像这样:

<?xml version="1.0"?>
-<ns0:feed ns1:etag="W/"LIESANDCRAPfyt7I2A9WhHERE."" xmlns:ns4="http://www.w3.org/2007/app" xmlns:ns3="http://schemas.google.com/contact/2008" xmlns:ns2="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:ns1="http://schemas.google.com/g/2005" xmlns:ns0="http://www.w3.org/2005/Atom">
    <ns0:updated>2012-01-25T14:52:12.867Z</ns0:updated>
    <ns0:category term="http://schemas.google.com/contact/2008#profile" scheme="http://schemas.google.com/g/2005#kind"/>
    <ns0:id>domain.com</ns0:id>
    <ns0:generator version="1.0" uri="http://www.google.com/m8/feeds">Contacts</ns0:generator>
    <ns0:author>
        <ns0:name>domain.com</ns0:name>
    </ns0:author>
    <ns0:link type="text/html" rel="alternate" href="http://www.google.com/"/>
    <ns0:link type="application/atom+xml" rel="http://schemas.google.com/g/2005#feed" href="https://www.google.com/m8/feeds/profiles/domain/domain.com/full"/>
    <ns0:link type="application/atom+xml" rel="http://schemas.google.com/g/2005#batch" href="https://www.google.com/m8/feeds/profiles/domain/domain.com/full/batch"/>
    <ns0:link type="application/atom+xml" rel="self" href="https://www.google.com/m8/feeds/profiles/domain/domain.com/full?max-results=300"/>
    <ns2:startIndex>1</ns2:startIndex>
    <ns2:itemsPerPage>300</ns2:itemsPerPage>
    <ns0:entry ns1:etag=""CRAPQR4KTit7I2A4"">
        <ns0:category term="http://schemas.google.com/contact/2008#profile" scheme="http://schemas.google.com/g/2005#kind"/>
        <ns0:id>http://www.google.com/m8/feeds/profiles/domain/domain.com/full/nperson</ns0:id>
        <ns1:name>
            <ns1:familyName>Person</ns1:familyName>
            <ns1:fullName>Name Person</ns1:fullName>
            <ns1:givenName>Name</ns1:givenName>
        </ns1:name>
        <ns0:updated>2012-01-25T14:52:13.081Z</ns0:updated>
        <ns1:organization rel="http://schemas.google.com/g/2005#work" primary="true">
            <ns1:orgTitle>JobField</ns1:orgTitle>
            <ns1:orgDepartment>DepartmentField</ns1:orgDepartment>
            <ns1:orgName>CompanyField</ns1:orgName>
        </ns1:organization>
        <ns3:status indexed="true"/>
        <ns0:title>Name Person</ns0:title>
        <ns0:link type="image/*" rel="http://schemas.google.com/contacts/2008/rel#photo" href="https://www.google.com/m8/feeds/photos/profile/domain.com/nperson"/>
        <ns0:link type="application/atom+xml" rel="self" href="https://www.google.com/m8/feeds/profiles/domain/domain.com/full/nperson"/>
        <ns0:link type="application/atom+xml" rel="edit" href="https://www.google.com/m8/feeds/profiles/domain/domain.com/full/nperson"/>
        <ns1:email rel="http://schemas.google.com/g/2005#other" address="nperson@gapps.domain.com"/>
        <ns1:email rel="http://schemas.google.com/g/2005#other" primary="true" address="nperson@domain.com"/>
        <ns4:edited>2012-01-25T14:52:13.081Z</ns4:edited>
    </ns0:entry>
    <ns0:title>domain.com's Profiles</ns0:title>
</ns0:feed>

我可以使用 beautifulstonesoup 使用以下代码从名称、组织和电子邮件字段中提取数据:

profiles_feed = gd_client.GetProfilesFeed('https://www.google.com/m8/feeds/profiles/domain/domain.com/full?max-results=300')

soup = BeautifulSoup(str(profiles_feed))


for tag in soup.findAll('ns1:name'):
    print tag.find('ns1:familyname').text
    print tag.find('ns1:fullname').text
    print tag.find('ns1:givenname').text

for tag in soup.findAll('ns1:organization'):
    print tag.find('ns1:orgtitle').text
    print tag.find('ns1:orgdepartment').text
    print tag.find('ns1:orgname').text

for tag in soup.findAll('ns1:email',address=True):
    print tag['address']

我希望能够从每个 ns0:entry 节点中一起抓取数据组,因此它会输出如下一行:姓氏、名字、组织名称、组织名称、电子邮件

我尝试过使用:

for tag in soup('ns0:entry'):
    print tag.name.familyName.text

但它把它当作一个属性来对待

我考虑过使用 xpath,但我找不到任何关于 beautifulstonesoup 和 xpath 的文档,所以我不确定它是否支持原生。那么,我如何搜索每个条目节点并返回所有特定于条目的数据,而不是所有按标签分组的数据。

【问题讨论】:

    标签: python xml


    【解决方案1】:
    >>> from BeautifulSoup import BeautifulStoneSoup
    >>> xml = """<ns0:feed ns1:etag="W/"LIESANDCRAPfyt7I2A9WhHERE."" xmlns:ns4="http://www.w3.org/2007/app" xmlns:ns3="http://schemas.google.com/contact/2008" xmlns:ns2="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:ns1="http://schemas.google.com/g/2005" xmlns:ns0="http://www.w3.org/2005/Atom">
    ...             <ns0:updated>2012-01-25T14:52:12.867Z</ns0:updated>
    ...             <ns0:category term="http://schemas.google.com/contact/2008#profile" scheme="http://schemas.google.com/g/2005#kind"/>
    ...             <ns0:id>domain.com</ns0:id>
    ...             <ns0:generator version="1.0" uri="http://www.google.com/m8/feeds">Contacts</ns0:generator>
    ...             <ns0:author>
    ...                 <ns0:name>domain.com</ns0:name>
    ...             </ns0:author>
    ...             <ns0:link type="text/html" rel="alternate" href="http://www.google.com/"/>
    ...             <ns0:link type="application/atom+xml" rel="http://schemas.google.com/g/2005#feed" href="https://www.google.com/m8/feeds/profiles/domain/domain.com/full"/>
    ...             <ns0:link type="application/atom+xml" rel="http://schemas.google.com/g/2005#batch" href="https://www.google.com/m8/feeds/profiles/domain/domain.com/full/batch"/>
    ...             <ns0:link type="application/atom+xml" rel="self" href="https://www.google.com/m8/feeds/profiles/domain/domain.com/full?max-results=300"/>
    ...             <ns2:startIndex>1</ns2:startIndex>
    ...             <ns2:itemsPerPage>300</ns2:itemsPerPage>
    ...             <ns0:entry ns1:etag=""CRAPQR4KTit7I2A4"">
    ...                 <ns0:category term="http://schemas.google.com/contact/2008#profile" scheme="http://schemas.google.com/g/2005#kind"/>
    ...                 <ns0:id>http://www.google.com/m8/feeds/profiles/domain/domain.com/full/nperson</ns0:id>
    ...                 <ns1:name>
    ...                     <ns1:familyName>Person</ns1:familyName>
    ...                     <ns1:fullName>Name Person</ns1:fullName>
    ...                     <ns1:givenName>Name</ns1:givenName>
    ...                 </ns1:name>
    ...                 <ns0:updated>2012-01-25T14:52:13.081Z</ns0:updated>
    ...                 <ns1:organization rel="http://schemas.google.com/g/2005#work" primary="true">
    ...                     <ns1:orgTitle>JobField</ns1:orgTitle>
    ...                     <ns1:orgDepartment>DepartmentField</ns1:orgDepartment>
    ...                     <ns1:orgName>CompanyField</ns1:orgName>
    ...                 </ns1:organization>
    ...                 <ns3:status indexed="true"/>
    ...                 <ns0:title>Name Person</ns0:title>
    ...                 <ns0:link type="image/*" rel="http://schemas.google.com/contacts/2008/rel#photo" href="https://www.google.com/m8/feeds/photos/profile/domain.com/nperson"/>
    ...                 <ns0:link type="application/atom+xml" rel="self" href="https://www.google.com/m8/feeds/profiles/domain/domain.com/full/nperson"/>
    ...                 <ns0:link type="application/atom+xml" rel="edit" href="https://www.google.com/m8/feeds/profiles/domain/domain.com/full/nperson"/>
    ...                 <ns1:email rel="http://schemas.google.com/g/2005#other" address="nperson@gapps.domain.com"/>
    ...                 <ns1:email rel="http://schemas.google.com/g/2005#other" primary="true" address="nperson@domain.com"/>
    ...                 <ns4:edited>2012-01-25T14:52:13.081Z</ns4:edited>
    ...             </ns0:entry>
    ...             <ns0:title>domain.com's Profiles</ns0:title>
    ...         </ns0:feed>"""
    

    来自文档的注释 (http://www.crummy.com/software/BeautifulSoup/documentation.html#Parsing XML):

    BeautifulStoneSoup 最常见的缺点是它不知道自闭合标签。 HTML 有一组固定的自闭合标签,但对于 XML,它取决于 DTD 所说的内容。您可以通过将它们的名称作为 selfClosingTags 参数传递给构造函数来告诉 BeautifulStoneSoup 某些标签是自关闭的:

    >>> soup = BeautifulStoneSoup(xml, selfClosingTags=['ns0:category','ns3:status', 'ns0:link','ns1:email'])
    >>> a = soup.findAll('ns0:entry')
    >>> a[0].find('ns1:familyname')
    <ns1:familyname>Person</ns1:familyname>
    >>> a[0].find('ns1:familyname').text
    u'Person'
    >>> a[0].find('ns1:givenname')
    <ns1:givenname>Name</ns1:givenname>
    >>> a[0].find('ns1:givenname').text
    u'Name'
    >>> for entry in a:
    ...     print ', '.join([entry.find('ns1:familyname').text, entry.find('ns1:givenname').text, entry.find('ns1:orgtitle').text, entry.find('ns1:orgname').text, entry.find('ns1:email')['address']])
    ...
    Person, Name, JobField, CompanyField, nperson@gapps.domain.com
    

    希望这会有所帮助。

    【讨论】:

    • 这很好用,感谢您帮助我解决这个问题。只有一个问题;解析器在找到空属性时停止,我在文档中找不到任何内容,你知道是否有一个标志可以忽略空属性和标签吗?
    • entry.find('ns1:email').get('address','No-address-found') 您可以将'No-address-found' 更改为您想要的任何字符串。见:docs.python.org/library/stdtypes.html#dict.get
    • 对不起,我应该更具体一些,如果文本字段为空白,地址字段的属性在我将使用的 xml 中很可能不是空白,但文本字段在类似 orgname 的地方可能。
    • 您可以检查 find 是否返回 None,如果它没有与 text 做某事:if a[0].find('ns1:familyname') != None: print a[0].find('ns1:familyname').text
    • 我已经尝试了一周才能让它工作,但我似乎无法让解析器跳过 NoneType。我有这样写的条目: writer.writerow([entry.find('ns1:familyname').text + ',' + entry.find('ns1:givenname').text + ',' + entry.find('ns1:fullname').text + ',' + entry.find('ns1:orgtitle').text + ',' + entry.find('ns1:orgdepartment').text + ',' + entry.find('ns1:orgname').text + ',' + entry.find('ns1:email',primary=True)['address']]) 它工作正常,但如果我尝试添加和条件,它打破了。我错过了什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-06
    • 2013-06-17
    • 1970-01-01
    • 2020-02-24
    • 2011-08-15
    相关资源
    最近更新 更多