100

I’m looking for a quick way to get an HTTP response code from a URL (i.e. 200, 404, etc). I’m not sure which library to use.

8 Answers 8

132

Update using the wonderful requests library. Note we are using the HEAD request, which should happen more quickly then a full GET or POST request.

import requests
try:
    r = requests.head("https://stackoverflow.com")
    print(r.status_code)
    # prints the int of the status code*
except requests.ConnectionError:
    print("failed to connect")

*Find more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Status

Sign up to request clarification or add additional context in comments.

6 Comments

requests is much better than urllib2, for such a link: dianping.com/promo/208721#mod=4, urllib2 give me a 404 and requests give a 200 just as what I get from a browser.
httpstatusrappers.com...awesome!! My code is on that Lil Jon status, son!
This is the best solution. Much better than any of the others.
@WKPlus for the record, now requests gives 403 for your link, although it's still working in browser.
@Gourneau Ha! That wasn't what I intended with my comment, I think it was perfectly fine, and in this context, people should try understand why it "Just works" in the browser, but returns a 403 in code, when in actuality, the same thing's happening both places.
|
66

Here's a solution that uses httplib instead.

import httplib

def get_status_code(host, path="/"):
    """ This function retreives the status code of a website by requesting
        HEAD data from the host. This means that it only requests the headers.
        If the host cannot be reached or something else goes wrong, it returns
        None instead.
    """
    try:
        conn = httplib.HTTPConnection(host)
        conn.request("HEAD", path)
        return conn.getresponse().status
    except StandardError:
        return None


print get_status_code("stackoverflow.com") # prints 200
print get_status_code("stackoverflow.com", "/nonexistant") # prints 404

8 Comments

+1 for HEAD request — no need to retrieve the entire entity for a status check.
Although you really should restrict that except block to at least StandardError so that you don't incorrectly catch things like KeyboardInterrupt.
I was wondering if HEAD requests are reliable. Because websites might not have (properly) implemented the HEAD method, which could result in status codes like 404, 501 or 500. Or am I being paranoid?
How would one make this follow 301s ?
@Blaise If a website doesn't allow HEAD requests then performing a HEAD request should result in a 405 error. For an example of this, try running curl -I http://www.amazon.com/.
|
26

You should use urllib2, like this:

import urllib2
for url in ["http://entrian.com/", "http://entrian.com/does-not-exist/"]:
    try:
        connection = urllib2.urlopen(url)
        print connection.getcode()
        connection.close()
    except urllib2.HTTPError, e:
        print e.getcode()

# Prints:
# 200 [from the try block]
# 404 [from the except block]

2 Comments

This is not a valid solution because urllib2 will follow redirects, so you will not get any 3xx responses.
@sorin: That depends - you might well want to follow redirects. Perhaps you want to ask the question "If I were to visit this URL with a browser, would it show content or give an error?" In that case, if I changed http://entrian.com/ to http://entrian.com/blog in my example, the resulting 200 would be correct even though it involved a redirect to http://entrian.com/blog/ (note the trailing slash).
9

In future, for those that use python3 and later, here's another code to find response code.

import urllib.request

def getResponseCode(url):
    conn = urllib.request.urlopen(url)
    return conn.getcode()

1 Comment

This will raise a HTTPError for status codes like 404, 500, etc.
3

The urllib2.HTTPError exception does not contain a getcode() method. Use the code attribute instead.

1 Comment

It does for me, using Python 2.6.
2

Addressing @Niklas R's comment to @nickanor's answer:

from urllib.error import HTTPError
import urllib.request

def getResponseCode(url):
    try:
        conn = urllib.request.urlopen(url)
        return conn.getcode()
    except HTTPError as e:
        return e.code

Comments

1

It depends on multiple factories, but try to test these methods:

import requests

def url_code_status(url):
    try:
        response = requests.head(url, allow_redirects=False)
        return response.status_code
    except Exception as e:
        print(f'[ERROR]: {e}')

or:

import http.client as httplib
import urllib.parse

def url_code_status(url):
    try:
        protocol, host, path, query, fragment = urllib.parse.urlsplit(url)
        if protocol == "http":
            conntype = httplib.HTTPConnection
        elif protocol == "https":
            conntype = httplib.HTTPSConnection
        else:
            raise ValueError("unsupported protocol: " + protocol)
        conn = conntype(host)
        conn.request("HEAD", path)
        resp = conn.getresponse()
        conn.close()
        return resp.status
    except Exception as e:
        print(f'[ERROR]: {e}')

Benchmark results for 100 URLs:

  • First method: 20.90 seconds
  • Second method: 23.15 seconds

Comments

0

Here's an httplib solution that behaves like urllib2. You can just give it a URL and it just works. No need to mess about splitting up your URLs into hostname and path. This function already does that.

import httplib
import socket
def get_link_status(url):
  """
    Gets the HTTP status of the url or returns an error associated with it.  Always returns a string.
  """
  https=False
  url=re.sub(r'(.*)#.*$',r'\1',url)
  url=url.split('/',3)
  if len(url) > 3:
    path='/'+url[3]
  else:
    path='/'
  if url[0] == 'http:':
    port=80
  elif url[0] == 'https:':
    port=443
    https=True
  if ':' in url[2]:
    host=url[2].split(':')[0]
    port=url[2].split(':')[1]
  else:
    host=url[2]
  try:
    headers={'User-Agent':'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:26.0) Gecko/20100101 Firefox/26.0',
             'Host':host
             }
    if https:
      conn=httplib.HTTPSConnection(host=host,port=port,timeout=10)
    else:
      conn=httplib.HTTPConnection(host=host,port=port,timeout=10)
    conn.request(method="HEAD",url=path,headers=headers)
    response=str(conn.getresponse().status)
    conn.close()
  except socket.gaierror,e:
    response="Socket Error (%d): %s" % (e[0],e[1])
  except StandardError,e:
    if hasattr(e,'getcode') and len(e.getcode()) > 0:
      response=str(e.getcode())
    if hasattr(e, 'message') and len(e.message) > 0:
      response=str(e.message)
    elif hasattr(e, 'msg') and len(e.msg) > 0:
      response=str(e.msg)
    elif type('') == type(e):
      response=e
    else:
      response="Exception occurred without a good error message.  Manually check the URL to see the status.  If it is believed this URL is 100% good then file a issue for a potential bug."
  return response

1 Comment

Not sure why this was downvoted without feedback. It works with HTTP and HTTPS URLs. It uses the HEAD method of HTTP.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.