Getting a machine's external IP address with Python
Asked Answered
T

32

157

Looking for a better way to get a machines current external IP #... Below works, but would rather not rely on an outside site to gather the information ... I am restricted to using standard Python 2.5.1 libraries bundled with Mac OS X 10.5.x

import os
import urllib2

def check_in():

    fqn = os.uname()[1]
    ext_ip = urllib2.urlopen('http://whatismyip.org').read()
    print ("Asset: %s " % fqn, "Checking in from IP#: %s " % ext_ip)
Tsushima answered 22/2, 2010 at 14:36 Comment(1)
related: Discovering public IP programaticallyHealall
B
49

If you are behind a router which obtains the external IP, I'm afraid you have no other option but to use external service like you do. If the router itself has some query interface, you can use it, but the solution will be very environment-specific and unreliable.

Boisterous answered 22/2, 2010 at 14:41 Comment(1)
Yes, agree. Those Cloud Servers provided by AWS&GoogleGCP all only provide internal IP address in its local interface query. We must use external to query its public IP address.Manly
I
186

I liked the http://ipify.org. They even provide Python code for using their API.

# This example requires the requests library be installed.  You can learn more
# about the Requests library here: http://docs.python-requests.org/en/latest/
from requests import get

ip = get('https://api.ipify.org').content.decode('utf8')
print('My public IP address is: {}'.format(ip))
Impearl answered 24/3, 2016 at 16:44 Comment(1)
Sometimes this site is requested for a very long time (for example, I waited 2 minutes and didn't get a response)Ron
N
117

Python3, using nothing else but the standard library

As mentioned before, one can use an external service like ident.me in order to discover the external IP address of your router.

Here is how it is done with python3, using nothing else but the standard library:

import urllib.request

external_ip = urllib.request.urlopen('https://ident.me').read().decode('utf8')

print(external_ip)

Both IPv4 and IPv6 addresses can be returned, based on availability and client preference; use https://v4.ident.me/ for IPv4 only, or https://v6.ident.me/ for IPv6 only.

Nottingham answered 2/1, 2017 at 20:20 Comment(6)
Although the OP was for python 2, I think this should be the accepted answer for Python 3 because it doesn't use any third-party libs. Note however, that ident.me (and others like ipv4bot.whatismyipaddress.com) requests take about twice the amount of time as required by api.ipify.org or ipinfo.io/ip, using the same code as this answer. The fastest and simplest response that I have found (among half a dozen) is that of api.ipify.org.Lycopodium
@Lycopodium Following your suggestion, I tested both api.ipify.org and ident.me Over here in Europe, ident.me is roughly three times faster than api.ipify.org I understand you are located in Canada.Nottingham
Serge haha good to know that makes sense, thanks for reporting back. Yes Canada.Lycopodium
Note that ident.me returned an IPv6 address when I used it from my host, while the others returned IPv4 addresses from the same location.Fender
Indeed ident.me runs from Europe (previously UK, now Germany). @Fender you're looking at v4.ident.me for specifically IPv4; api.ident.me for more info :)Monomer
Cert expired this morning, so don't recommend using ident.me as its not reliable enough.Sunk
B
50

I prefer this Amazon AWS endpoint:

import requests
ip = requests.get('https://checkip.amazonaws.com').text.strip()
Beanery answered 20/8, 2019 at 18:0 Comment(2)
Especially for those that use boto3!Infrequent
Yes, this is much more reliable than ident.me which allowed their cert to expire, thanks!Sunk
B
49

If you are behind a router which obtains the external IP, I'm afraid you have no other option but to use external service like you do. If the router itself has some query interface, you can use it, but the solution will be very environment-specific and unreliable.

Boisterous answered 22/2, 2010 at 14:41 Comment(1)
Yes, agree. Those Cloud Servers provided by AWS&GoogleGCP all only provide internal IP address in its local interface query. We must use external to query its public IP address.Manly
S
40

You should use the UPnP protocol to query your router for this information. Most importantly, this does not rely on an external service, which all the other answers to this question seem to suggest.

There's a Python library called miniupnp which can do this, see e.g. miniupnpc/testupnpigd.py.

pip install miniupnpc

Based on their example you should be able to do something like this:

import miniupnpc

u = miniupnpc.UPnP()
u.discoverdelay = 200
u.discover()
u.selectigd()
print('external ip address: {}'.format(u.externalipaddress()))
Spermaceti answered 29/12, 2016 at 18:8 Comment(3)
This works even when you are connected to a VPN. ThanksReveille
won't work when connected to openvpn. Exception: No UPnP device discoveredConversable
Good way to do! depending on the external service may block requests on the grounds of Too many requestsMiter
L
13

In my opinion the simplest solution is

import requests
f = requests.request('GET', 'http://myip.dnsomatic.com')
ip = f.text

Thats all.

Luiseluiza answered 27/6, 2015 at 18:48 Comment(2)
It is probably worth mentioning you need to import requests. See pypi.python.org/pypi/requestsGonfalonier
Does not technically answer the question since "Requests officially supports Python 2.6–2.7 & 3.3–3.7, and runs great on PyPy." However, it is still useful to others.Middendorf
C
9

Use requests module:

import requests

myip = requests.get('https://www.wikipedia.org').headers['X-Client-IP']

print("\n[+] Public IP: "+myip)
Cicero answered 8/2, 2019 at 2:16 Comment(1)
I like this one for simple tasks. No need to download the whole page though, we only need the headers. For this I suggest using requests.head instead. Much more efficient.Abomb
L
8

If you don't want to use external services (IP websites, etc.) You can use the UPnP Protocol.

Do to that we use a simple UPnP client library (https://github.com/flyte/upnpclient)

Install:

pip install upnpclient

Simple Code:

import upnpclient

devices = upnpclient.discover()

if(len(devices) > 0):
    externalIP = devices[0].WANIPConn1.GetExternalIPAddress()
    print(externalIP)
else:
    print('No Connected network interface detected')

Full Code (to get more information as mentioned in the github readme)

In [1]: import upnpclient

In [2]: devices = upnpclient.discover()

In [3]: devices
Out[3]: 
[<Device 'OpenWRT router'>,
 <Device 'Harmony Hub'>,
 <Device 'walternate: root'>]

In [4]: d = devices[0]

In [5]: d.WANIPConn1.GetStatusInfo()
Out[5]: 
{'NewConnectionStatus': 'Connected',
 'NewLastConnectionError': 'ERROR_NONE',
 'NewUptime': 14851479}

In [6]: d.WANIPConn1.GetNATRSIPStatus()
Out[6]: {'NewNATEnabled': True, 'NewRSIPAvailable': False}

In [7]: d.WANIPConn1.GetExternalIPAddress()
Out[7]: {'NewExternalIPAddress': '123.123.123.123'}
Life answered 25/11, 2018 at 9:55 Comment(0)
D
8

As simple as running this in Python3:

import os

externalIP  = os.popen('curl -s ifconfig.me').readline()
print(externalIP)
Dagan answered 2/3, 2019 at 11:21 Comment(2)
This requires curl installedRodriques
This is the best answer to that question, thanks a lot.Ambrotype
U
8

Try:

import requests 
ip = requests.get('http://ipinfo.io/json').json()['ip']

Hope this is helpful

Ungraceful answered 7/8, 2020 at 18:15 Comment(0)
G
5

If you think and external source is too unreliable, you could pool a few different services. For most ip lookup pages they require you to scrape html, but a few of them that have created lean pages for scripts like yours - also so they can reduce the hits on their sites:

Gayla answered 22/2, 2010 at 14:52 Comment(0)
L
5

There are a few other ways that do not rely on Python checking an external web site, however the OS can. Your primary issue here, is that even if you were not using Python, if you were using the command line, there are no "built-in" commands that can just simply tell you the external (WAN) IP. Commands such as "ip addr show" and "ifconfig -a" show you the server's IP address's within the network. Only the router actually holds the external IP. However, there are ways to find the external IP address (WAN IP) from the command line.

These examples are:

http://ipecho.net/plain ; echo
curl ipinfo.io/ip
dig +short myip.opendns.com @resolver1.opendns.com
dig TXT +short o-o.myaddr.l.google.com @ns1.google.com

Therefore, the python code would be:

import os
ip = os.popen('wget -qO- http://ipecho.net/plain ; echo').readlines(-1)[0].strip()
print ip

OR

import os
iN, out, err = os.popen3('curl ipinfo.io/ip')
iN.close() ; err.close()
ip = out.read().strip()
print ip

OR

import os
ip = os.popen('dig +short myip.opendns.com @resolver1.opendns.com').readlines(-1)[0].strip()
print ip

Or, plug any other of the examples above, into a command like os.popen, os.popen2, os.popen3, or os.system.

P.S. you can use "pip3 install pytis" and use/take a look at, the "getip" program, written in Python. You can also find it's code here: https://github.com/PyTis/PyTis/blob/development/src/pytis/getip.py

Lyford answered 19/9, 2018 at 18:14 Comment(0)
S
5

I use IPGrab because it's easy to remember:

# This example requires the requests library be installed.  You can learn more
# about the Requests library here: http://docs.python-requests.org/en/latest/
from requests import get

ip = get('http://ipgrab.io').text
print('My public IP address is: {}'.format(ip))
Selfexcited answered 4/1, 2021 at 15:0 Comment(0)
G
5

Unfortunately, there is no way to get your external IP address without consulting a computer on the internet. At best, you can get the local network IP address of your network card (which is likely a 192.16.. address).

You can use the whatismyip module to get the external IP addres. It has no dependencies outside the Python 3 standard library. It connects to public STUN servers and what-is-my-ip websites to find the IPv4 or IPv6 address. Run pip install whatismyip

Example:

>>> import whatismyip
>>> whatismyip.amionline()
True
>>> whatismyip.whatismyip()  # Prefers IPv4 addresses, but can return either IPv4 or IPv6.
'69.89.31.226'
>>> whatismyip.whatismyipv4()
'69.89.31.226'
>>> whatismyip.whatismyipv6()
'2345:0425:2CA1:0000:0000:0567:5673:23b5'
Gschu answered 21/2, 2022 at 1:41 Comment(1)
that's actually the only answer that worked for my ISP, ident.me and ipify.org returned a different ip address for some reasonCaseworm
C
3
import requests
import re


def getMyExtIp():
    try:
        res = requests.get("http://whatismyip.org")
        myIp = re.compile('(\d{1,3}\.){3}\d{1,3}').search(res.text).group()
        if myIp != "":
            return myIp
    except:
        pass
    return "n/a"
Cnut answered 31/3, 2017 at 4:39 Comment(1)
Damn this is a bit faster than just using BeautifulSoup, thanksStoll
H
2

I tried most of the other answers on this question here and came to find that most of the services used were defunct except one.

Here is a script that should do the trick and download only a minimal amount of information:

#!/usr/bin/env python

import urllib
import re

def get_external_ip():
    site = urllib.urlopen("http://checkip.dyndns.org/").read()
    grab = re.findall('([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', site)
    address = grab[0]
    return address

if __name__ == '__main__':
  print( get_external_ip() )
Hillock answered 5/6, 2013 at 23:18 Comment(1)
Regex is broken. Should be \d{1,3}.Acroterion
E
2

The most simple (non python) working solution I can think of is

wget -q -O- icanhazip.com

I'd like to add a very short Python3 solution which makes use of the JSON API of http://hostip.info.

from urllib.request import urlopen
import json
url = 'http://api.hostip.info/get_json.php'
info = json.loads(urlopen(url).read().decode('utf-8'))
print(info['ip'])

You can of course add some error checking, a timeout condition and some convenience:

#!/usr/bin/env python3
from urllib.request import urlopen
from urllib.error import URLError
import json

try:
    url = 'http://api.hostip.info/get_json.php'
    info = json.loads(urlopen(url, timeout = 15).read().decode('utf-8'))
    print(info['ip'])
except URLError as e:
    print(e.reason, end=' ') # e.g. 'timed out'
    print('(are you connected to the internet?)')
except KeyboardInterrupt:
    pass
Entoblast answered 9/5, 2014 at 10:39 Comment(0)
F
2

Working with Python 2.7.6 and 2.7.13

import urllib2  
req = urllib2.Request('http://icanhazip.com', data=None)  
response = urllib2.urlopen(req, timeout=5)  
print(response.read())
Fermat answered 26/3, 2018 at 17:40 Comment(0)
D
1

If the machine is being a firewall then your solution is a very sensible one: the alternative being able to query the firewall which ends-up being very dependent on the type of firewall (if at all possible).

Drugstore answered 22/2, 2010 at 14:39 Comment(0)
F
1
In [1]: import stun

stun.get_ip_info()
('Restric NAT', 'xx.xx.xx.xx', 55320)
Favela answered 26/3, 2014 at 22:10 Comment(1)
Where does the stun library come from?Midriff
D
1

Linux only solution.

On Linux Systems, you can use Python to execute a command on the shell. I think it might help someone.

Something like this, (assuming 'dig/drill' is working on the os)

import os 
command = "dig TXT +short o-o.myaddr.l.google.com @ns1.google.com | awk -F\'\"\' '{print $2}' " 
ip = os.system(command)

For Arch users, please replace 'dig' with 'drill'.

Dissension answered 5/8, 2019 at 14:51 Comment(0)
S
1

I liked Sergiy Ostrovsky's answer, but I think there is an even tidier way to do this now.

  1. Install ipify library.
pip install ipify
  1. Import and use the library in your Python program.
import ipify
ip = ipify.get_ip()
Snowstorm answered 26/5, 2021 at 20:38 Comment(0)
P
0
ipWebCode = urllib.request.urlopen("http://ip.nefsc.noaa.gov").read().decode("utf8")
ipWebCode=ipWebCode.split("color=red> ")
ipWebCode = ipWebCode[1]
ipWebCode = ipWebCode.split("</font>")
externalIp = ipWebCode[0]

this is a short snippet I had written for another program. The trick was finding a simple enough website so that dissecting the html wasn't a pain.

Pitre answered 5/2, 2013 at 3:23 Comment(1)
Unfortunate at the service is gone :cAccessory
T
0

Here's another alternative script.

def track_ip():
   """
   Returns Dict with the following keys:
   - ip
   - latlong
   - country
   - city
   - user-agent
   """

   conn = httplib.HTTPConnection("www.trackip.net")
   conn.request("GET", "/ip?json")
   resp = conn.getresponse()
   print resp.status, resp.reason

   if resp.status == 200:
       ip = json.loads(resp.read())
   else:
       print 'Connection Error: %s' % resp.reason

   conn.close()
   return ip

EDIT: Don't forget to import httplib and json

Tangible answered 19/1, 2014 at 12:59 Comment(1)
This answer used to work for me, but the packages break when updating using conda, so I've abandoned this answer for a simplier solution @Hors Sujet in #24509230Dactylo
G
0

If you're just writing for yourself and not for a generalized application, you might be able to find the address on the setup page for your router and then scrape it from that page's html. This worked fine for me with my SMC router. One read and one simple RE search and I've found it.

My particular interest in doing this was to let me know my home IP address when I was away from home, so I could get back in via VNC. A few more lines of Python stores the address in Dropbox for outside access, and even emails me if it sees a change. I've scheduled it to happen on boot and once an hour thereafter.

Gutierrez answered 4/5, 2014 at 21:39 Comment(0)
E
0

Use this script :

import urllib, json

data = json.loads(urllib.urlopen("http://ip.jsontest.com/").read())
print data["ip"]

Without json :

import urllib, re

data = re.search('"([0-9.]*)"', urllib.urlopen("http://ip.jsontest.com/").read()).group(1)
print data
Erida answered 29/2, 2016 at 18:37 Comment(0)
D
0

import os public_ip = os.system("inxi -i |grep 'WAN IP'") print(public_ip)

Douville answered 18/8, 2021 at 18:55 Comment(3)
Please provide some explanation as to what the code is doing, and how it is different from other solutions.Libava
@Libava I would not recommend this solution, as it assumes that you are using a system that has inxi (smxi.org/docs/inxi.htm) installed, and unless you're using a Linux distribution that ships with it, you probably don't have it.Rhizocarpous
this is for linux onlyDouville
G
0

To get external IP address, use this code:

from requests import get

def get_external_ip()->str:
    return get('https://api.ipify.org/').text
Gilbertine answered 1/9, 2023 at 11:36 Comment(1)
This duplicates another answer and adds no new content. Many of the answers use an approach like this. In fact, the top voted answer includes the line get('https://api.ipify.org'). Please don't post an answer unless you actually have something new to contribute. You can show your support for an original answer by upvoting.Campus
D
0

If you are checking frequently, the amazon page blocks the request. Maybe others do so too. This code chooses each call a new link, and only returns if there is a valid result. Maybe it is also a good idea if the response really contains an IP address. Because of that, I used the regex from here: https://stackoverflow.com/a/36760050

import re
import random
import requests

ipreg = re.compile(
    r"""^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$"""
)


def _getip(link, action):
    result = None
    try:
        with requests.get(link) as fa:
            result = action(fa)
            result = ipreg.findall(result)[0]
    except Exception:
        pass
    return result


def get_ip_of_this_pc():
    fu1 = lambda fa: fa.text.strip()
    fu2 = lambda fa: fa.json()["ip"].strip()
    sites_and_actions = [
        ("https://checkip.amazonaws.com", fu1),
        ("https://api.ipify.org", fu1),
        ("https://ident.me", fu1),
        ("http://myip.dnsomatic.com", fu1),
        ("http://ipinfo.io/json", fu2),
        ("http://ipgrab.io", fu1),
        ("http://icanhazip.com/", fu1),
        ("https://www.trackip.net/ip", fu1),
    ]
    random.shuffle(sites_and_actions)
    for link, action in sites_and_actions:
        result = _getip(link, action)
        if result:
            return result


myip = get_ip_of_this_pc()
print(myip)
Discrown answered 4/9, 2023 at 3:55 Comment(0)
P
0

Above answers are either outdated or intricate. This works currently on latest python 3.11=

import urllib.request
import json

def get_external_ip():
    try:
        response = urllib.request.urlopen("https://httpbin.org/ip")
        data = json.load(response)
        address = data['origin']
        return address
    except Exception as e:
        return str(e)

if __name__ == '__main__':
    print(get_external_ip())
Palacios answered 25/9, 2023 at 19:1 Comment(0)
D
-2

If you are not interested in hitting any url to get public ip, I think following code can help you to get public ip using python of your machine

import os
externalIP  = os.popen("ifconfig | grep 'inet' | cut -d: -f2 | awk '{print $2}' | sed -n 3p").readline()
print externalIP

sed -n 3p line varies as per the network you are using for connecting device.

I was facing same issue, I was needed public ip of iot device which is hitting my server. but public ip is totally different in ifconfig command and ip i am getting in server from request object. after this I am adding extra param into my request to send ip of device to my server.

hope this is helpful

Dual answered 14/1, 2020 at 10:53 Comment(0)
C
-4
import os
externalIp = os.popen("ipconfig").read().split(":")[15][1:14]

some numbers may need to be changed but this works for me

Cyanine answered 3/1, 2021 at 17:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.