Несколько запросов URL к API без получения ошибки от urllib2 или запросов

Я пытаюсь получить данные из разных API. Они принимаются в формате JSON, сохраняются в SQLite и затем анализируются.

Проблема, с которой я сталкиваюсь, заключается в том, что при отправке многих запросов я в конечном итоге получаю сообщение об ошибке, даже если я использую time.sleep между запросами.

Обычный подход

Мой код выглядит так, как показано ниже, где это будет внутри цикла, а URL-адрес, который нужно открыть, будет меняться:

base_url = 'https://www.whateversite.com/api/index.php?'
custom_url = 'variable_text1' + & + 'variable_text2' 

url = base_url + custom_urls #url will be changing

time.sleep(1)
data = urllib2.urlopen(url).read() 

Это выполняется тысячи раз внутри цикла. Проблема возникает после того, как скрипт проработал какое-то время (до пары часов), затем я получаю следующие ошибки или похожие:

    data = urllib2.urlopen(url).read()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 127, in urlopen
    return _opener.open(url, data, timeout)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 404, in open
    response = self._open(req, data)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 422, in _open
    '_open', req)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 382, in _call_chain
    result = func(*args)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1222, in https_open
    return self.do_open(httplib.HTTPSConnection, req)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1184, in do_open
    raise URLError(err)
urllib2.URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>

or

    uh = urllib.urlopen(url)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 87, in urlopen
    return opener.open(url)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 208, in open
    return getattr(self, name)(url)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 437, in open_https
    h.endheaders(data)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 969, in endheaders
    self._send_output(message_body)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 829, in _send_output
    self.send(msg)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 791, in send
    self.connect()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 1172, in connect
    self.timeout, self.source_address)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 553, in create_connection
    for res in getaddrinfo(host, port, 0, SOCK_STREAM):
IOError: [Errno socket error] [Errno 8] nodename nor servname provided, or not known

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

Из того, что я читал во многих разных темах о какой модуль лучше, я думаю, что для моих нужд все подойдет, и главный рычаг выбора одного заключается в том, что он может открывать как можно больше URL-адресов. По моему опыту, urllib и urllib2 в этом отношении лучше, чем requests, так как requests вылетает за меньшее время.

Предполагая, что я не хочу увеличивать время ожидания, используемое в time.sleep, я до сих пор думал об этих решениях:

Возможные решения?

A

Я думал объединить все разные модули. Это было бы:

  • Начните, например, с requests.
  • Через определенное время или при возникновении ошибки автоматически переключаться на urllib2
  • Через определенное время или при возникновении ошибки автоматически переключаться на другие модули (например, httplib2 или urllib) или обратно на requests
  • И так далее...

B

Используйте блок try .. except для обработки этого исключения, как предлагается здесь< /а>.

C

Я также читал об отправке нескольких запросов одновременно или параллельно. Я не знаю, как именно это работает и может ли это быть действительно полезным.


Однако я не убежден ни в одном из этих решений.

Можете ли вы придумать более элегантное и/или эффективное решение для устранения этой ошибки?

Я использую Python 2.7


person J0ANMM    schedule 20.08.2016    source источник
comment
Возможно, закрыть объект, возвращенный urlopen() или requests, чтобы закрыть соединение?   -  person zachyee    schedule 20.08.2016
comment
По какому адресу это происходит?   -  person Padraic Cunningham    schedule 20.08.2016
comment
@PadraicCunningham, я не уверен, понял ли я вопрос: URL-адрес относится к API. Это нужно для получения информации о поездках, поэтому обычно вам нужно указать как минимум origin_id, destination_id и дату. Это, например, url = serviceurl + segment1 + '&' + segment2 + '&' + segment3, где сегменты будут другими. Этот URL возвращает чистый JSON.   -  person J0ANMM    schedule 20.08.2016
comment
@zachyee, как я могу закрыть возвращенный объект? В этом случае, следуя коду, который я написал в объяснении, этот объект будет data, правильно?   -  person J0ANMM    schedule 20.08.2016
comment
Сокет будет закрыт автоматически, я имею в виду, какой фактический URL-адрес вы используете, это общедоступный API или вы очищаете внутренний API   -  person Padraic Cunningham    schedule 20.08.2016
comment
DeinBus.de/fapi/trips/ Документацию можно найти здесь: deinbus.de/affiliate/dokumentation.php но вам нужно зарегистрироваться и предоставить имя пользователя и пароль, чтобы действительно получить доступ к данным.   -  person J0ANMM    schedule 20.08.2016
comment
@JoanMM В конечном итоге вы сделаете что-то вроде response = urllib.urlopen(url) data = response.read() response.close() Как только он выйдет за рамки, он подходит для сборки мусора, но явное выполнение может помочь, поскольку вы пытаетесь получить доступ к большому количеству URL-адресов за небольшой промежуток времени. Еще лучше было бы использовать менеджер контекста (с ключевым словом). Дополнительная информация здесь: stackoverflow.com /вопросы/1522636/   -  person zachyee    schedule 20.08.2016
comment
Спасибо @zachyee. К сожалению, я попытался и все равно получил ошибку (на этот раз она была выброшена довольно быстро).   -  person J0ANMM    schedule 21.08.2016


Ответы (1)


Даже если я не был убежден, в итоге я попытался реализовать блок try .. except и вполне доволен результатом:

for url in list_of_urls:
    time.sleep(2)
    try:
        response = urllib2.urlopen(url)
        data = response.read()
        time.sleep(0.1)
        response.close() #as suggested by zachyee in the comments

        #code to save data in SQLite database

    except urllib2.URLError as e:
        print '***** urllib2.URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known> *****'
        #save error in SQLite
        cur.execute('''INSERT INTO Errors (error_type, error_ts, url_queried)
        VALUES (?, ?, ?)''', ('urllib2.URLError', timestamp, url))
        conn.commit()
        time.sleep(30) #give it a small break

Скрипт работал до конца.

Из тысяч запросов я получил 8 ошибок, которые были сохранены в моей базе данных с соответствующим URL-адресом. Таким образом, я могу попытаться снова получить эти URL-адреса, если это необходимо.

person J0ANMM    schedule 21.08.2016