Несколько 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>
или же
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
Вот решения, которые я до сих пор думал:
Возможные решения?
Я думал о комбинировании всех разных модулей. Это было бы:
- Начните, например, с
requests
, - Через определенное время или при возникновении ошибки автоматически переключитесь на
urllib2
- По истечении определенного времени или при возникновении ошибки автоматически переключайтесь на другие модули (например,
httplib2
или жеurllib
) или вернуться кrequests
- И так далее...
В
использование try .. except
блок для обработки этого исключения, как предлагается здесь.
С
Я также читал об отправке нескольких запросов одновременно или параллельно. Я не знаю, как это работает, и может ли это быть полезным
Однако я не убежден ни в одном из этих решений.
Можете ли вы придумать какое-нибудь более элегантное и / или эффективное решение для устранения этой ошибки?
Я с Python 2.7
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 снова после этого, если это необходимо.