【问题标题】:urllib2.HTTPError Pythonurllib2.HTTPError Python
【发布时间】:2013-01-27 10:32:56
【问题描述】:

我有一个包含 GI 编号的文件,想从 ncbi 获取 FASTA 序列。

from Bio import Entrez
import time
Entrez.email ="eigtw59tyjrt403@gmail.com"
f = open("C:\\bioinformatics\\gilist.txt")
for line in iter(f):
    handle = Entrez.efetch(db="nucleotide", id=line, retmode="xml")
    records = Entrez.read(handle)
    print ">GI "+line.rstrip()+" "+records[0]["GBSeq_primary-accession"]+" "+records[0]["GBSeq_definition"]+"\n"+records[0]["GBSeq_sequence"]
    time.sleep(1) # to make sure not many requests go per second to ncbi
f.close()

此脚本运行良好,但在几个序列后我突然收到此错误消息。

Traceback (most recent call last):
  File "C:/Users/Ankur/PycharmProjects/ncbiseq/getncbiSeq.py", line 7, in <module>
    handle = Entrez.efetch(db="nucleotide", id=line, retmode="xml")
  File "C:\Python27\lib\site-packages\Bio\Entrez\__init__.py", line 139, in efetch
    return _open(cgi, variables)
  File "C:\Python27\lib\site-packages\Bio\Entrez\__init__.py", line 455, in _open
    raise exception
urllib2.HTTPError: HTTP Error 500: Internal Server Error

当然我可以使用http://www.ncbi.nlm.nih.gov/sites/batchentrez,但我正在尝试创建一个管道并且想要一些自动化的东西。

如何防止 ncbi “踢我”

【问题讨论】:

    标签: python urllib2 biopython ncbi


    【解决方案1】:

    我不熟悉 ncbi API,但我的猜测是您违反了某种速率限制规则(即使使用 "sleep(1)" ),所以您之前的请求有效,但经过几次请求服务器看到你经常点击它并阻止你。这对您来说是有问题的,因为您的代码中没有错误处理。

    我建议将您的数据提取包装在 try/except 块中,以使您的脚本等待更长时间,然后在遇到问题时重试。如果一切都失败了,将导致错误的 id 写入文件并继续(如果 id 是罪魁祸首,可能会导致 Entrez 库生成错误的 URL)。

    尝试将您的代码更改为这样的内容(未经测试):

    from urllib2 import HTTPError
    from Bio import Entrez
    import time
    
    def get_record(_id):
        handle = Entrez.efetch(db="nucleotide", id=_id, retmode="xml")
        records = Entrez.read(handle)
        print ">GI "+line.rstrip()+" "+records[0]["GBSeq_primary-accession"]+" "+records[0]["GBSeq_definition"]+"\n"+records[0]["GBSeq_sequence"]
        time.sleep(1) # to make sure not many requests go per second to ncbi
    
    Entrez.email ="eigtw59tyjrt403@gmail.com"
    f = open("C:\\bioinformatics\\gilist.txt")
    for id in iter(f):
        try:
            get_record(id)
        except HTTPError:
            print "Error fetching", id
            time.sleep(5) # we have angered the API! Try waiting longer?
            try:
                get_record(id)
            except:
                with open('error_records.bad','a') as f:
                    f.write(str(id)+'\n')
                continue # 
    f.close()
    

    【讨论】:

      【解决方案2】:

      有一个名为 efetch 的变通方法。您可以将您的列表分成 200 个批次(直觉认为这是一个不错的批次大小),然后使用 efetch 一次性发送所有这些 id。

      首先,这比发送 200 个单独的查询要快得多。其次,它也有效地遵守了“每秒 3 次查询”的规则,因为每次查询的处理时间长于 0.33 秒,但不会太长。

      但是,您确实需要一种机制来捕捉“坏苹果”。即使您的 200 个 id 中有一个是坏的,NCBI 也会返回 0 结果。换句话说,只有当且仅当所有 200 个 id 都有效时,NCBI 才会返回结果。

      如果是坏苹果,我会一个一个地遍历 200 个 id 并忽略坏苹果。这个“如果坏苹果怎么办”场景也告诉你不要让批次太大,以防坏苹果。如果它很大,首先,有一个坏苹果的机会就更大,也就是说,你需要更频繁地迭代整个事情。其次,批次越大,您需要迭代的单个项目就越多。

      我使用以下代码下载 CAZy 蛋白,效果很好:

      import urllib2
      
      
      prefix = "http://www.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=protein&rettype=fasta&id="
      id_per_request = 200
      
      
      def getSeq (id_list):
          url = prefix + id_list[:len(id_list)-1]
      
          temp_content = ""
          try:
              temp_content += urllib2.urlopen(url).read()
      
      ### if there is a bad apple, try one by one
          except:
              for id in id_list[:len(id_list)-1].split(","):
                  url = prefix + id
          #print url
                  try:
                      temp_content += urllib2.urlopen(url).read()
                  except:
                  #print id
                      pass
          return temp_content
      
      
      content = ""
      counter = 0
      id_list = ""
      
      #define your accession numbers first, here it is just an example!!
      
      accs = ["ADL19140.1","ABW01768.1","CCQ33656.1"]
      for acc in accs:
      
          id_list += acc + ","
          counter += 1
      
          if counter == id_per_request:
              counter = 0
              content += getSeq(id_list)
              id_list = ""
      
      if id_list != "":
          content += getSeq(id_list)
          id_list = ""
      
      
      print content
      

      【讨论】:

        【解决方案3】:

        这是一个“正常”的 Entrez API 临时故障,即使您已应用所有 Entrez API 规则,也可能发生这种故障。 Biopython 文档在this section 中解释了处理它的方法。

        有时您会收到来自 Entrez 的间歇性错误,HTTPError 5XX,我们使用除暂停重试块之外的尝试来解决此问题。例如,

        # This assumes you have already run a search as shown above,
        # and set the variables count, webenv, query_key
        
        try:
            from urllib.error import HTTPError  # for Python 3
        except ImportError:
            from urllib2 import HTTPError  # for Python 2
        
        batch_size = 3
        out_handle = open("orchid_rpl16.fasta", "w")
        for start in range(0, count, batch_size):
            end = min(count, start+batch_size)
            print("Going to download record %i to %i" % (start+1, end))
            attempt = 0
            while attempt < 3:
                attempt += 1
                try:
                    fetch_handle = Entrez.efetch(db="nucleotide",
                                                 rettype="fasta", retmode="text",
                                                 retstart=start, retmax=batch_size,
                                                 webenv=webenv, query_key=query_key,
                                                 idtype="acc")
                except HTTPError as err:
                    if 500 <= err.code <= 599:
                        print("Received error from server %s" % err)
                        print("Attempt %i of 3" % attempt)
                        time.sleep(15)
                    else:
                        raise
            data = fetch_handle.read()
            fetch_handle.close()
            out_handle.write(data)
        out_handle.close()
        

        因此,您不必为此错误感到内疚,只需抓住它。

        【讨论】:

        • 感谢您的评论。我以为最初的问题是How can I prevent ncbi from "kicking me out"。也许我不够清楚,我的回答会解释,首先,OP收到的错误并不意味着NCBI API“将他踢出去”,其次,如何根据工具Biopython的文档处理此异常使用了 OP。您认为我可以改进哪一部分以更准确地回答问题?
        • @BiBizz 我被你的开场白弄错了 Experiencing the same error 这立即表明“我也有这个问题”类型的答案。考虑到这一点,我可以看出它不是真的。撤回审查。
        • 你是对的,这是一个糟糕的介绍,不是很有用。我将其删除以更直接。感谢您的有益评论。
        猜你喜欢
        • 2012-07-12
        • 2014-09-05
        • 1970-01-01
        • 2016-08-24
        • 1970-01-01
        • 2013-07-16
        • 1970-01-01
        • 2017-12-29
        • 2017-04-22
        相关资源
        最近更新 更多