Python requests 모듈을 사용하지 않는 올바른 방법?
try:
r = requests.get(url, params={'s': thing})
except requests.ConnectionError, e:
print(e)
이거 맞는건가요?이것을 구조화하는 더 좋은 방법이 있을까요?이것으로 내 모든 근거가 충족될까?
Requests 예외 문서를 확인합니다.요컨대:
네트워크 문제(DNS 장애, 연결 거부 등)가 발생했을 경우 요청에서 예외가 발생합니다.
드물게 비활성 HTTP 응답이 발생할 경우 요청에서 예외가 발생합니다.
요청이 타임아웃되면 예외가 발생합니다.
요구가 설정된 최대 리다이렉션 수를 초과하면 예외가 발생합니다.
Requests가 명시적으로 발생시키는 모든 예외는 에서 상속됩니다.
질문에 답하기 위해, 당신이 보여주는 것이 당신의 모든 근거를 커버하지는 않을 것입니다.접속 관련 오류만 검출되고 타임아웃된 오류는 검출되지 않습니다.
예외를 발견했을 때 무엇을 할지는 스크립트/프로그램 설계에 달려 있습니다.나가도 되나요?다시 한 번 시도해 주시겠어요?에러가 치명적이어서 계속할 수 없는 경우 SystemExit(오류 인쇄와 호출을 모두 수행하는 좋은 방법)을 실행하여 프로그램을 중단할 수 있습니다.sys.exit
를 참조해 주세요.
베이스 클래스의 예외를 검출해, 모든 케이스를 처리할 수 있습니다.
try:
r = requests.get(url, params={'s': thing})
except requests.exceptions.RequestException as e: # This is the correct syntax
raise SystemExit(e)
아니면 따로 잡아서 여러 가지 일을 할 수도 있어요.
try:
r = requests.get(url, params={'s': thing})
except requests.exceptions.Timeout:
# Maybe set up for a retry, or continue in a retry loop
except requests.exceptions.TooManyRedirects:
# Tell the user their URL was bad and try a different one
except requests.exceptions.RequestException as e:
# catastrophic error. bail.
raise SystemExit(e)
Christian이 지적했듯이:
http 오류(401 Unauthorized 등)로 예외를 발생시키려면 에 문의하십시오.그렇게 하면
HTTPError
(「http」http 「」를 참조).
예:
try:
r = requests.get('http://www.google.com/nothere')
r.raise_for_status()
except requests.exceptions.HTTPError as err:
raise SystemExit(err)
인쇄:
404 Client Error: Not Found for url: http://www.google.com/nothere
명시적인 제안 하나 더 있습니다.특정 에러가 일반 에러에 의해 가려지지 않도록 특정 에러 스택에서 일반 에러 스택으로 이동하는 것이 가장 좋습니다.
url='http://www.google.com/blahblah'
try:
r = requests.get(url,timeout=3)
r.raise_for_status()
except requests.exceptions.HTTPError as errh:
print ("Http Error:",errh)
except requests.exceptions.ConnectionError as errc:
print ("Error Connecting:",errc)
except requests.exceptions.Timeout as errt:
print ("Timeout Error:",errt)
except requests.exceptions.RequestException as err:
print ("OOps: Something Else",err)
Http Error: 404 Client Error: Not Found for url: http://www.google.com/blahblah
대
url='http://www.google.com/blahblah'
try:
r = requests.get(url,timeout=3)
r.raise_for_status()
except requests.exceptions.RequestException as err:
print ("OOps: Something Else",err)
except requests.exceptions.HTTPError as errh:
print ("Http Error:",errh)
except requests.exceptions.ConnectionError as errc:
print ("Error Connecting:",errc)
except requests.exceptions.Timeout as errt:
print ("Timeout Error:",errt)
OOps: Something Else 404 Client Error: Not Found for url: http://www.google.com/blahblah
응답도 되어 있습니다.e.response
서버로부터의 응답으로 에러 본문을 확인할 필요가 있는 경우에 편리합니다.예를 들어 다음과 같습니다.
try:
r = requests.post('somerestapi.com/post-here', data={'birthday': '9/9/3999'})
r.raise_for_status()
except requests.exceptions.HTTPError as e:
print (e.response.text)
일반적인 뜻입니다.그것은 적어도 모든 것을 둘러싸지 않아도 된다는 것을 의미합니다.requests
try ... except
:
기본 버전
# see the docs: if you set no timeout the call never times out! A tuple means "max
# connect time" and "max read time"
DEFAULT_REQUESTS_TIMEOUT = (5, 15) # for example
def log_exception(e, verb, url, kwargs):
# the reason for making this a separate function will become apparent
raw_tb = traceback.extract_stack()
if 'data' in kwargs and len(kwargs['data']) > 500: # anticipate giant data string
kwargs['data'] = f'{kwargs["data"][:500]}...'
msg = f'BaseException raised: {e.__class__.__module__}.{e.__class__.__qualname__}: {e}\n' \
+ f'verb {verb}, url {url}, kwargs {kwargs}\n\n' \
+ 'Stack trace:\n' + ''.join(traceback.format_list(raw_tb[:-2]))
logger.error(msg)
def requests_call(verb, url, **kwargs):
response = None
exception = None
try:
if 'timeout' not in kwargs:
kwargs['timeout'] = DEFAULT_REQUESTS_TIMEOUT
response = requests.request(verb, url, **kwargs)
except BaseException as e:
log_exception(e, verb, url, kwargs)
exception = e
return (response, exception)
NB
- 에
ConnectionError
기본 제공이고 수업과는 아무런 관련이 없습니다.requests.ConnectionError
*. 더인 생각은 없습니다 이런 *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. *. 。 - (非) 비검사의
None
반환되었습니다.requests.RequestException
클래스 「」의requests
포함)requests.ConnectionError
문서에 따르면 )는 ""가 아닙니다.아마 답변이 받아들여진 이후로 바뀐 것 같아요.**requests.exceptions.RequestException
- 이것은 분명히 로거가 설정되어 있는 것을 전제로 하고 있습니다. " "
logger.exception
except
블록은 좋은 생각처럼 보이지만, 이 메서드 내에서 스택만 제공합니다.대신에, 이 메서드에의 콜에 이르는 트레이스를 취득해 주세요.그런 다음 로그 기록(예외 및 문제의 원인이 된 콜 세부 정보 포함)
.*소스코드입니다.requests.ConnectionError
분류하다requests.RequestException
은 단일 분류합니다.IOError
Builtin)(빌트인)
** 단, 이 페이지 하단에 "요청"이 있습니다.예외입니다.RequestException" (2022-02)...위 페이지에 링크되어 있습니다.혼란스럽네요.
사용법은 매우 간단합니다.
search_response, exception = utilities.requests_call('get',
f'http://localhost:9200/my_index/_search?q={search_string}')
하세요. 만약 약약그면면면면None
뭔가 재미있는 일이 일어났기 때문에 상황에 따라(그리고 예외에 따라) 어떤 식으로든 행동해야 하는 예외가 있습니다.Gui 어플리케이션(PyQt5)에서는 보통 사용자에게 출력(및 로그 파일에도 동시에 기록)을 제공하기 위해 "시각 로그"를 구현하지만 추가된 메시지는 기술 이외의 것이어야 합니다.따라서 일반적으로 다음과 같은 것이 뒤따릅니다.
if search_response == None:
# you might check here for (e.g.) a requests.Timeout, tailoring the message
# accordingly, as the kind of error anyone might be expected to understand
msg = f'No response searching on |{search_string}|. See log'
MainWindow.the().visual_log(msg, log_level=logging.ERROR)
return
response_json = search_response.json()
if search_response.status_code != 200: # NB 201 ("created") may be acceptable sometimes...
msg = f'Bad response searching on |{search_string}|. See log'
MainWindow.the().visual_log(msg, log_level=logging.ERROR)
# usually response_json will give full details about the problem
log_msg = f'search on |{search_string}| bad response\n{json.dumps(response_json, indent=4)}'
logger.error(log_msg)
return
# now examine the keys and values in response_json: these may of course
# indicate an error of some kind even though the response returned OK (status 200)...
스택 트레이스가 자동적으로 로그에 기록되기 때문에, 그 이상은 필요 없습니다.
json 개체가 반환된 경우의 고급 버전
(... 잠재적으로 많은 양의 보일러 플레이트가 필요합니다!)
T를 건너려면 json 개체가 반환될 것으로 예상되는 경우:
위와 같이 예외로 인해 비기술 사용자에게 "응답 없음" 메시지가 표시되고 200 이외의 상태가 "불량 응답"인 경우 다음을 권장합니다.
- 응답의 JSON 구조에서 예상 키가 누락되면 "Anomalous response"라는 메시지가 나타납니다.
- 예기치 않은 응답 메시지에 대한 범위를 벗어나거나 이상한 값
- "error" 또는 "error와 같은이 "Error", "Error" 또는 ""와 같은 키가 하며 값이 "Error", "Error" 또는 "Error"는 "Error"와 "Error"로 됩니다.
True
또는 "Error response(오류 응답)" 메시지에 대해
이로 인해 코드가 계속되지 않을 수도 있고 그렇지 않을 수도 있습니다.
제 에는 이 포괄적으로 가 있습니다.사실 제 생각에는 이 과정을 더욱 포괄적으로 만들 가치가 있습니다.기능들은 보통 의 '보다', '보다', '다', '다', '다', '다'를 사용하여 .requests_call
처리 및 로그 메시지의 대부분을 표준화할 수 있습니다. 개 의 ★★★★★★★★★★★★★★★★★*requests
프로젝트에 전화를 걸면 코드가 훨씬 좋아지고 비대해지지 않습니다.
def log_response_error(response_type, call_name, deliverable, verb, url, **kwargs):
# NB this function can also be used independently
if response_type == 'No': # exception was raised (and logged)
if isinstance(deliverable, requests.Timeout):
MainWindow.the().visual_log(f'Time out of {call_name} before response received!', logging.ERROR)
return
else:
if isinstance(deliverable, BaseException):
# NB if response.json() raises an exception we end up here
log_exception(deliverable, verb, url, kwargs)
else:
# if we get here no exception has been raised, so no stack trace has yet been logged.
# a response has been returned, but is either "Bad" or "Anomalous"
response_json = deliverable.json()
raw_tb = traceback.extract_stack()
if 'data' in kwargs and len(kwargs['data']) > 500: # anticipate giant data string
kwargs['data'] = f'{kwargs["data"][:500]}...'
added_message = ''
if hasattr(deliverable, 'added_message'):
added_message = deliverable.added_message + '\n'
del deliverable.added_message
call_and_response_details = f'{response_type} response\n{added_message}' \
+ f'verb {verb}, url {url}, kwargs {kwargs}\nresponse:\n{json.dumps(response_json, indent=4)}'
logger.error(f'{call_and_response_details}\nStack trace: {"".join(traceback.format_list(raw_tb[:-1]))}')
MainWindow.the().visual_log(f'{response_type} response {call_name}. See log.', logging.ERROR)
def check_keys(req_dict_structure, response_dict_structure, response):
# so this function is about checking the keys in the returned json object...
# NB both structures MUST be dicts
if not isinstance(req_dict_structure, dict):
response.added_message = f'req_dict_structure not dict: {type(req_dict_structure)}\n'
return False
if not isinstance(response_dict_structure, dict):
response.added_message = f'response_dict_structure not dict: {type(response_dict_structure)}\n'
return False
for dict_key in req_dict_structure.keys():
if dict_key not in response_dict_structure:
response.added_message = f'key |{dict_key}| missing\n'
return False
req_value = req_dict_structure[dict_key]
response_value = response_dict_structure[dict_key]
if isinstance(req_value, dict):
# if the response at this point is a list apply the req_value dict to each element:
# failure in just one such element leads to "Anomalous response"...
if isinstance(response_value, list):
for resp_list_element in response_value:
if not check_keys(req_value, resp_list_element, response):
return False
elif not check_keys(req_value, response_value, response): # any other response value must be a dict (tested in next level of recursion)
return False
elif isinstance(req_value, list):
if not isinstance(response_value, list): # if the req_value is a list the reponse must be one
response.added_message = f'key |{dict_key}| not list: {type(response_value)}\n'
return False
# it is OK for the value to be a list, but these must be strings (keys) or dicts
for req_list_element, resp_list_element in zip(req_value, response_value):
if isinstance(req_list_element, dict):
if not check_keys(req_list_element, resp_list_element, response):
return False
if not isinstance(req_list_element, str):
response.added_message = f'req_list_element not string: {type(req_list_element)}\n'
return False
if req_list_element not in response_value:
response.added_message = f'key |{req_list_element}| missing from response list\n'
return False
# put None as a dummy value (otherwise something like {'my_key'} will be seen as a set, not a dict
elif req_value != None:
response.added_message = f'required value of key |{dict_key}| must be None (dummy), dict or list: {type(req_value)}\n'
return False
return True
def process_json_requests_call(verb, url, **kwargs):
# "call_name" is a mandatory kwarg
if 'call_name' not in kwargs:
raise Exception('kwarg "call_name" not supplied!')
call_name = kwargs['call_name']
del kwargs['call_name']
required_keys = {}
if 'required_keys' in kwargs:
required_keys = kwargs['required_keys']
del kwargs['required_keys']
acceptable_statuses = [200]
if 'acceptable_statuses' in kwargs:
acceptable_statuses = kwargs['acceptable_statuses']
del kwargs['acceptable_statuses']
exception_handler = log_response_error
if 'exception_handler' in kwargs:
exception_handler = kwargs['exception_handler']
del kwargs['exception_handler']
response, exception = requests_call(verb, url, **kwargs)
if response == None:
exception_handler('No', call_name, exception, verb, url, **kwargs)
return (False, exception)
try:
response_json = response.json()
except BaseException as e:
logger.error(f'response.status_code {response.status_code} but calling json() raised exception')
# an exception raised at this point can't truthfully lead to a "No response" message... so say "bad"
exception_handler('Bad', call_name, e, verb, url, **kwargs)
return (False, response)
status_ok = response.status_code in acceptable_statuses
if not status_ok:
response.added_message = f'status code was {response.status_code}'
log_response_error('Bad', call_name, response, verb, url, **kwargs)
return (False, response)
check_result = check_keys(required_keys, response_json, response)
if not check_result:
log_response_error('Anomalous', call_name, response, verb, url, **kwargs)
return (check_result, response)
호출 예(이 버전에서는 NB, "전달 가능"은 json 구조를 전달하는 예외 또는 응답 중 하나임):
success, deliverable = utilities.process_json_requests_call('get',
f'{ES_URL}{INDEX_NAME}/_doc/1',
call_name=f'checking index {INDEX_NAME}',
required_keys={'_source':{'status_text': None}})
if not success: return False
# here, we know the deliverable is a response, not an exception
# we also don't need to check for the keys being present:
# the generic code has checked that all expected keys are present
index_status = deliverable.json()['_source']['status_text']
if index_status != 'successfully completed':
# ... i.e. an example of a 200 response, but an error nonetheless
msg = f'Error response: ES index {INDEX_NAME} does not seem to have been built OK: cannot search'
MainWindow.the().visual_log(msg)
logger.error(f'index |{INDEX_NAME}|: deliverable.json() {json.dumps(deliverable.json(), indent=4)}')
return False
예를 들어, 키 "status_text"가 누락된 경우 사용자가 볼 수 있는 "visual log" 메시지는 "Anomalous response checking index XYZ"입니다.로그를 참조해 주세요." (이 로그는 스택트레이스뿐만 아니라 문제의 키 누락에 대한 상세도 포함하여 자동으로 작성되는 보다 상세한 기술 메시지를 제공합니다).
NB
- 수 k k kwarg:
call_name
"kwargs:"required_keys
,acceptable_statuses
,exception_handler
. required_keys
dict
까지 할 수- 예외 는 ''를 할 수 있습니다.
exception_handler
kwargs
, 잊지 )requests_call
는, 의 상세,, 및 「」, 「」, 「」, 「」를 참조해 .__str__
★★★★★★★★★★★★★★★★★」 - 에서는, 「데이터」의 키 합니다.
kwargs
기록될 수 있습니다.이는 대량 작업(예: Elastic Search의 경우 인덱스를 채우는 작업)이 거대한 문자열로 구성될 수 있기 때문입니다.예를 들어 처음 500자로 줄입니다.
네, ,, 고 ps 、 고 、 고 、 고 니 。elasticsearch
Python 주변의 ")requests
위의 내용은 모두 설명용입니다.
언급URL : https://stackoverflow.com/questions/16511337/correct-way-to-try-except-using-python-requests-module
'programing' 카테고리의 다른 글
Quota Exceeded Error: 돔 예외 22: 할당량을 초과하는 항목을 스토리지에 추가하려고 했습니다. (0) | 2022.09.12 |
---|---|
vuex 알 수 없는 로컬 변환 유형: updateValue, 글로벌 유형: app/updateValue.돌연변이가 작동하지 않음 (0) | 2022.09.12 |
PHP - 스트림을 열지 못했습니다. 해당 파일 또는 디렉터리가 없습니다. (0) | 2022.09.12 |
Seaborn 상자 그림에 제목을 추가하는 방법 (0) | 2022.09.12 |
MySQL 연결이 작동하지 않음: 2002 해당 파일 또는 디렉터리가 없습니다. (0) | 2022.09.12 |