What is the easiest way to check whether the response received from a requests post was "200 OK" or an error has occurred?
I tried doing something like this:
....
resp = requests.post(my_endpoint_var, headers=header_var, data=post_data_var)
print(resp)
if resp == "<Response [200]>":
print ('OK!')
else:
print ('Boo!')
The output on the screen is:
Response [200] (including the "<" and ">")
Boo!
So even though I am getting a 200, my check in the if statement is somehow not matching?
According to the docs, there's a status_code property on the response-object. So you can do the following:
if resp.status_code == 200:
print ('OK!')
else:
print ('Boo!')
EDIT:
As others have pointed out, a simpler check would be
if resp.ok:
print ('OK!')
else:
print ('Boo!')
if you want to consider all 2xx response codes and not 200 explicitly.
You may also want to check Peter's answer for a more python-like way to do this.
Just check the response attribute resp.ok. It is True for all 2xx responses, but False for 4xx and 5xx. However, the pythonic way to check for success would be to optionally raise an exception with Response.raise_for_status():
try:
resp = requests.get(url)
resp.raise_for_status()
except requests.exceptions.HTTPError as err:
print(err)
EAFP: It’s Easier to Ask for Forgiveness than Permission: You should just do what you expect to work and if an exception might be thrown from the operation then catch it and deal with that fact.
Much simpler check would be
if resp.ok :
print ('OK!')
else:
print ('Boo!')
Since any 2XX class response is considered successful in HTTP, I would use:
if 200 <= resp.status_code <= 299:
print ('OK!')
else:
print ('Boo!')
I'm surprised no one has mentioned this so:
If you want to check for exactly a 200 response:
if resp.status_code == requests.codes.ok:
The status_code of a response contains the HTTP status returned.
requests.codes.ok is exactly 200.
If you want to check if the status code is "ok", and not an error:
if resp.ok:
The ok attribute of a response checks that the status code of the response is less than 400.
Make sure you know what it is you want to check, for example a 201 HTTP Created is a successful response that you would be omitting if you only check for exactly 200.
resp.status_code will return the status code as an integer.
See http://docs.python-requests.org/en/master/
try:
if resp.status_code == 200:
print ('OK!')
else:
print ('Boo!)
In easy case:
import requests
response = requests.get(url)
if not response:
#handle error here
else:
#handle normal response
Related
url = "https://www.avito.ma/fr/2_mars/sacs_et_accessoires/Ch%C3%A2les_en_Vrai_Soie_Chanel_avec_boite_38445885.htm"
try
r = requests.get(url,headers={'User-Agent': ua.random},timeout=timeout) # execute a timed website request
if r.status_code > 299: # check for bad status
r.raise_for_status() # if confirmed raise bad status
else:
print(r.status_code, url) # otherwise print status code and url
except Exception as e:
print('\nThe following exception: {0}, \nhas been found found on the following post: "{1}".\n'.format(e,url))
Expected status = 301 Moved Permanently
You can visit the page or check http://www.redirect-checker.org/index.php with the url for a correct terminal print.
Returned status = 200 OK
The page has been moved and it should return the above 301 Moved Permanently, however it returns a 200. I read the requests doc and checked all the parameters (allow_redirects=False etc.) but I don't think it is a mistake of configuration.
I am puzzled at why requests wouldn't see the redirects.
Any ideas?
Thank you in advance.
Python Requests module has the allow_redirect parameter in True by default. I've tested it with False and it gives the 301 code that you're looking for.
Note after reading your comment above: r.history saves each response_code before the one that you're right now which is saved in r.status_code (only if you leave the parameter in True).
As seen here, max-retries can be set for requests.Session(), but I only need the head.status_code to check if a url is valid and active.
Is there a way to just get the head within a mount session?
import requests
def valid_active_url(url):
try:
site_ping = requests.head(url, allow_redirects=True)
except requests.exceptions.ConnectionError:
print('Error trying to connect to {}.'.format(url))
try:
if (site_ping.status_code < 400):
return True
else:
return False
except Exception:
return False
return False
Based on docs am thinking I need to either:
see if the session.mount method results return a status code (which I haven't found yet)
roll my own retry method, perhaps with a decorator like this or this or a (less eloquent) loop like this.
In terms of the first approach I have tried:
s = requests.Session()
a = requests.adapters.HTTPAdapter(max_retries=3)
s.mount('http://redirected-domain.com', a)
resp = s.get('http://www.redirected-domain.org')
resp.status_code
Are we only using s.mount() to get in and set max_retries? Seems to be a redundancy, aside from that the http connection would be pre-established.
Also resp.status_code returns 200 where I am expecting a 301 (which is what requests.head returns.
NOTE: resp.ok might be all I need for my purposes here.
After a mere two hours of developing the question, the answer took five minutes:
def valid_url(url):
if (url.lower() == 'none') or (url == ''):
return False
try:
s = requests.Session()
a = requests.adapters.HTTPAdapter(max_retries=5)
s.mount(url, a)
resp = s.head(url)
return resp.ok
except requests.exceptions.MissingSchema:
# If it's missing the schema, run again with schema added
return valid_url('http://' + url)
except requests.exceptions.ConnectionError:
print('Error trying to connect to {}.'.format(url))
return False
Based on this answer it looks like the head request will be slightly less resource intensive than the get, particularly if the url contains a large amount of data.
The requests.adapters.HTTPAdapter is the built in adaptor for the urllib3 library that underlies the Requests library.
On another note, I'm not sure what the correct term or phrase for what I'm checking here is. A url could still be valid if it returns an error code.
I am trying to parse json data from a site that shows values of crypto currency. I am trying to parse it using python. I am a little lost on how to show the output.
API: https://min-api.cryptocompare.com/data/price?fsym=XMR&tsyms=USD
# code starts below
import requests
# Set the request parameters
url = 'https://min-api.cryptocompare.com/data/price?fsym=XMR&tsyms=USD'
# Fetch url
print("Fetching url..")
# Do the HTTP get request
response = requests.get(url, verify=True) #Verify is check SSL certificate
# Error handling
# Check for HTTP codes other than 200
if response.status_code != 200:
print('Status:', response.status_code, 'Problem with the request. Exiting.')
exit()
# Decode the JSON response into a dictionary and use the data
USD = response.json()
output = USD[0]['USD']
print('Output USD:'), USD
# code ends
I am getting a response code 200 because IDLE tries to exit. The code is based off another project and I don't believe I am parsing json correctly?
The problem is here:
if response.status_code != 200:
print('Status:', response.status_code, 'Problem with the request. Exiting.')
exit()
The way you've indented, Python will always call exit(). You want it to call exit() only if there was actually an error, like so:
if response.status_code != 200:
print('Status:', response.status_code, 'Problem with the request. Exiting.')
exit()
However, you have another problem. You're trying to assign "output" the value of an object in USD; USD doesn't exist:
data = response.json()
output = USD[0]['USD'] #"USD" doesn't exist. It's the value you're trying to find, not the json that contains the object itself.
print('Output USD:'), USD #"USD" doesn't exist. I think you meant to print "output" here, which is the value you're setting in the line above.
Instead, try this:
data = response.json()
output = data["USD"]
print('Output USD:'), output
Your exit() line is not indented correctly. Try this:
if response.status_code != 200:
print('Status:', response.status_code, 'Problem with the request. Exiting.')
exit()
Additionally, even though you are parsing the JSON correctly, you incorrectly use the resulting data. Try this:
output = USD['USD'] # Note: "[0]" not required
print('Output USD:', USD) # Note: ", USD" inside the parentheses
My question is closely related to this one.
I'm using the Requests library to hit an HTTP endpoint.
I want to check if the response is a success.
I am currently doing this:
r = requests.get(url)
if 200 <= response.status_code <= 299:
# Do something here!
Instead of doing that ugly check for values between 200 and 299, is there a shorthand I can use?
The response has an ok property. Use that:
if response.ok:
...
The implementation is just a try/except around Response.raise_for_status, which is itself checks the status code.
#property
def ok(self):
"""Returns True if :attr:`status_code` is less than 400, False if not.
This attribute checks if the status code of the response is between
400 and 600 to see if there was a client error or a server error. If
the status code is between 200 and 400, this will return True. This
is **not** a check to see if the response code is ``200 OK``.
"""
try:
self.raise_for_status()
except HTTPError:
return False
return True
I am a Python newbie but I think the easiest way is:
if response.ok:
# whatever
The pythonic way to check for requests success would be to optionally raise an exception with
try:
resp = requests.get(url)
resp.raise_for_status()
except requests.exceptions.HTTPError as err:
print(err)
EAFP: It’s Easier to Ask for Forgiveness than Permission: You should just do what you expect to work and if an exception might be thrown from the operation then catch it and deal with that fact.
I have a program which uses the requests module to send a get request which (correctly) responds with a 304 "Not Modified". After making the request, I check to make sure response.status_code == requests.codes.ok, but this check fails. Does requests not consider a 304 as "ok"?
There is a property called ok in the Response object that returns True if the status code is not a 4xx or a 5xx.
So you could do the following:
if response.ok:
# 304 is included
The code of this property is pretty simple:
#property
def ok(self):
try:
self.raise_for_status()
except HTTPError:
return False
return True
You can check actual codes in the source. ok means 200 only.
You can check the implementation of requests.status code here source code.The implementation allows you to access all/any kind of status_codes as follow:
import requests
import traceback
url = "https://google.com"
req = requests.get(url)
try:
if req.status_code == requests.codes['ok']: # Check the source code for all the codes
print('200')
elif req.status_code == requests.codes['not_modified']: # 304
print("304")
elifreq.status_code == requests.codes['not_found']: # 404
print("404")
else:
print("None of the codes")
except:
traceback.print_exc(file=sys.stdout)
In conclusion, you can access any request-response like demonstrated. I am sure there are better ways but this worked for me.
.ok "..If the status code is between 200 and 400, this will return True."
mentioned in source code as:
"""Returns True if :attr:status_code is less than 400, False if not.
This attribute checks if the status code of the response is between
400 and 600 to see if there was a client error or a server error. If
the status code is between 200 and 400, this will return True. This
is not a check to see if the response code is 200 OK.
"""