【问题标题】:Get values from different tags using a condition in BeautifulSoup使用 BeautifulSoup 中的条件从不同标签中获取值
【发布时间】:2021-11-27 23:50:28
【问题描述】:

我有一个这样的 xml 文件:

data =   """<entity type="protein" entityId="A">
    <segment segId="7ddd_A_1_1208" start="1" end="1208">
      <listResidue>
        <residue dbSource="PDBe" dbCoordSys="PDBe" dbResNum="1" dbResName="MET">
          <crossRefDb dbSource="PDB" dbCoordSys="PDBresnum" dbAccessionId="7ddd" dbResNum="null" dbResName="MET" dbChainId="A"/>
          <crossRefDb dbSource="UniProt" dbCoordSys="UniProt" dbAccessionId="P0DTC2" dbResNum="1" dbResName="M"/>
          <crossRefDb dbSource="NCBI" dbCoordSys="UniProt" dbAccessionId="2697049" dbResNum="1" dbResName="M"/>
          <residueDetail dbSource="PDBe" property="Annotation">Not_Observed</residueDetail>
        </residue>
        <residue dbSource="PDBe" dbCoordSys="PDBe" dbResNum="14" dbResName="GLN">
          <crossRefDb dbSource="PDB" dbCoordSys="PDBresnum" dbAccessionId="7ddd" dbResNum="14" dbResName="GLN" dbChainId="A"/>
          <crossRefDb dbSource="UniProt" dbCoordSys="UniProt" dbAccessionId="P0DTC2" dbResNum="13" dbResName="Q"/>
          <crossRefDb dbSource="NCBI" dbCoordSys="UniProt" dbAccessionId="2697049" dbResNum="14" dbResName="Q"/>
          <residueDetail dbSource="PDBe" property="codeSecondaryStructure">T</residueDetail>
          <residueDetail dbSource="PDBe" property="nameSecondaryStructure">loop</residueDetail>
        </residue>
  </entity>
  <entity type="protein" entityId="B">
    <segment segId="7ddd_B_1_1208" start="1" end="1208">
      <listResidue>
        <residue dbSource="PDBe" dbCoordSys="PDBe" dbResNum="1" dbResName="MET">
          <crossRefDb dbSource="PDB" dbCoordSys="PDBresnum" dbAccessionId="7ddd" dbResNum="1" dbResName="MET" dbChainId="B"/>
          <crossRefDb dbSource="UniProt" dbCoordSys="UniProt" dbAccessionId="PXCDT" dbResNum="1" dbResName="M"/>
          <crossRefDb dbSource="NCBI" dbCoordSys="UniProt" dbAccessionId="2697049" dbResNum="1" dbResName="M"/>
          <residueDetail dbSource="PDBe" property="Annotation">Not_Observed</residueDetail>
        </residue>
        <residue dbSource="PDBe" dbCoordSys="PDBe" dbResNum="16" dbResName="VAL">
          <crossRefDb dbSource="PDB" dbCoordSys="PDBresnum" dbAccessionId="7ddd" dbResNum="16" dbResName="VAL" dbChainId="B"/>
          <crossRefDb dbSource="UniProt" dbCoordSys="UniProt" dbAccessionId="P0DTC2" dbResNum="16" dbResName="V"/>
          <crossRefDb dbSource="NCBI" dbCoordSys="UniProt" dbAccessionId="2697049" dbResNum="16" dbResName="V"/>
          <residueDetail dbSource="PDBe" property="codeSecondaryStructure">T</residueDetail>
          <residueDetail dbSource="PDBe" property="nameSecondaryStructure">loop</residueDetail>
        </residue>"""

我要做的是从与 dbSource="PDB" 和 dbSource="UniProt" 相同的行中检索 dbResNum 值。但是,只有当 dbSource="PDB" 行中没有 dbResNum="null" 并且与 dbSource="UniProt" 行中的 dbAccessionId="P0DTC2" 没有任何不同的值时,我才需要这些值。所以,我的输出会是这样的:

PDB_Res = '13', '16' Uniprot_Res = '14, '16'

我尝试这样做的代码:

from bs4 import BeautifulSoup
import re
def not_null(dbresnum):
    return dbresnum and not re.compile("null").search(dbresnum)

xml_file = BeautifulSoup(data, 'lxml')
XML_without_null = xml_file.find_all(dbresnum=not_null)
for cross in XML_without_null:
    if cross('crossrefdb', {"dbaccessionid":"P0DTC2"}):
        Uniprot_id = cross['dbresnum']
    if cross('crossrefdb', {"dbsource":"PDB"}):
        PDB_id = cross['dbresnum']

问题是函数 not_null 不能正常工作。欢迎任何想法。

【问题讨论】:

  • 嗨。欢迎来到 StackOverflow。是否所有对 crossRefDb 元素的处理都相互独立,或者如果给定的残基有子 crossRefDb dbresnum = "null",则该残基组中的所有 crossRefDb 元素都被忽略了吗?为什么 dbResNum=1 未包含在您的预期输出中?
  • 您好,谢谢您的欢迎。所以是的,如果我在与 dbSource="PDB" 相同的行中的 dbresnum 中得到一个空值,它将跳过该孩子的任何 dbresnum。所以,脚本应该忽略第一个孩子,因为它在 dbresnum 中得到一个空值

标签: python python-3.x xml beautifulsoup xml-parsing


【解决方案1】:

首先,需要将解析器从“lxml”改为“xml”。
lxmllxml.html.soupparser的别名,用于HTML。

另请注意,您问题中的 XML sn-p 是无效的 XML 文件,没有结束段或 listResidue 元素。没有根 XML 元素,只有 2 个无效的实体元素。 BeautifulSoup 处理无效文档,但如果可能,始终建议从有效的 XML 文档开始。

如果要跳过整个 residue 组和其中的所有 crossRefDb 子组,则需要遍历所有 residue 并检查是否有子组crossRefDb 与 dbSource="PDB" 在同一行的 dbresnum 中有一个空值。

试试这样的:

from bs4 import BeautifulSoup

data = '''<entity ...'''

soup = BeautifulSoup(data, 'xml')
uni_res = set()
pdb_res = set()
for residue in soup.find_all('residue'):
    if residue.find('crossRefDb', {'dbSource': 'PDB', 'dbResNum': 'null'}):
        continue
    for cross in residue.find_all('crossRefDb'):
        res_num = cross.get('dbResNum')
        if cross.get("dbAccessionId") == "P0DTC2":
            uni_res.add(res_num)
        if cross.get("dbSource") == "PDB":
            pdb_res.add(res_num)

print("PDB_Res =", pdb_res, "Uniprot =", uni_res)

输出:

PDB_Res = {'1', '16', '14'} Uniprot_Res = {'16', '13'}

【讨论】:

  • 感谢您的反馈。问题是它应该跳过第一个孩子,因为它在 dbresnum 标记中得到一个空值。而且由于我在另一个孩子身上得到了一个 dbAccession Id="PXCDT",它也需要跳过它。所以,我的输出应该是这样的: PDB_Res= {'14', 16'} Uniprot_Res= {'13', '16'}
  • 我已经改变了一点你的解决方案,我添加了这一行: if residual.find('crossRefDb', {'dbSource': 'UniProt', 'dbAccessionId': "P0DTC2"''}) ,因为我只想要 dbAccessionId 为“P0DTC2”'的值。但是非常感谢您,您的示例有助于解决问题。我真的很感激。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-07
  • 1970-01-01
相关资源
最近更新 更多