urllib2.HTTPError Python

У меня есть файл с номерами GI, и я хочу получить FASTA последовательности от ncbi.

from Bio import Entrez
import time
Entrez.email ="[email protected]"
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 «выгнать меня»


person Ank    schedule 12.02.2013    source источник


Ответы (3)


Я не знаком с ncbi API, но я предполагаю, что вы нарушаете какое-то правило ограничения скорости (даже с помощью "sleep(1)" ), поэтому ваши предыдущие запросы работают, но после нескольких запросов сервер видит что вы бьете его часто и блокирует вас. Это проблематично для вас, потому что в вашем коде нет обработки ошибок.

Я бы рекомендовал обернуть вашу выборку данных в блок try/except, чтобы ваш скрипт ждал дольше, а затем повторил попытку, если он столкнулся с проблемами. Если ничего не помогает, запишите идентификатор, вызвавший ошибку, в файл и продолжите работу (в случае, если идентификатор каким-то образом является виновником, возможно, вызывающим создание библиотекой 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 ="[email protected]"
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()
person David Marx    schedule 12.02.2013

Существует обходной путь под названием efetch. Вы можете разделить свой список на партии по 200 штук (внутри чувствуется, что это нормальный размер партии) и использовать efetch, чтобы отправить все эти идентификаторы одновременно.

Во-первых, это НАМНОГО, намного быстрее, чем отправка 200 отдельных запросов. Во-вторых, он также эффективно соответствует правилу «3 запроса в секунду», поскольку время обработки каждого запроса превышает 0,33 секунды, но не слишком велико.

Однако вам нужен механизм, чтобы поймать «плохие яблоки». NCBI вернет 0 результатов, даже если один из ваших 200 идентификаторов неверный. Другими словами, NCBI возвращает результаты только тогда и только тогда, когда все ваши 200 идентификаторов действительны.

В случае плохого яблока я перебираю 200 идентификаторов один за другим и игнорирую плохое яблоко. Этот сценарий «что делать, если испорченное яблоко» также говорит вам не делать партию слишком большой, на случай плохого яблока. Если он большой, то, во-первых, больше шансов получить гнилое яблоко, то есть вам чаще придется перебирать все это целиком. Во-вторых, чем больше пакет, тем больше отдельных элементов вам придется повторять.

Я использую следующий код для загрузки белков 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
person dgg32    schedule 20.06.2014

Это «обычный» временный сбой Entrez API, который может произойти, даже если вы применили все правила Entrez API. Документация Biopython объясняет способ обработки в этого раздела.

Иногда вы будете получать прерывистые ошибки от Entrez, HTTPError 5XX, для решения этой проблемы мы используем блок try, исключая паузу. Например,

# 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()

Таким образом, вы не должны чувствовать себя виноватым из-за этой ошибки и просто должны ее поймать.

person BiBzz    schedule 14.03.2019
comment
Спасибо за отзыв. Я думал, что первоначальный вопрос был How can I prevent ncbi from "kicking me out". Возможно, я был недостаточно ясен, мой ответ объяснил бы, что, во-первых, ошибка, полученная OP, не означает, что NCBI API выгоняет его, и, во-вторых, как обрабатывать это исключение в соответствии с документацией Biopython, инструмент, используемый OP . Как вы думаете, какую часть я могу улучшить, чтобы точнее ответить на вопрос? - person BiBzz; 14.03.2019
comment
@BiBizz Я ошибся из-за вашего вступительного замечания Испытывает ту же ошибку, что сразу же предполагает, что у меня тоже есть эта проблема, введите ответ. Что, при рассмотрении, я вижу, что это не совсем так. Снятие отзыва. - person BoarGules; 14.03.2019
comment
Вы правы, это плохое введение, которое не очень полезно. Я удаляю это, чтобы быть более прямым. Спасибо за ваш полезный обзор. - person BiBzz; 14.03.2019