Отримання зовнішньої IP-адреси машини за допомогою Python


82

Шукаю кращого способу отримати машини, що мають поточний зовнішній IP-номер ... Нижче працює, але я б волів не покладатися на зовнішній сайт для збору інформації ... Я обмежуюсь використанням стандартних бібліотек Python 2.5.1 в комплекті з 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)

пов'язані:
Програмне

Відповіді:


37

Якщо ви стоїте за маршрутизатором, який отримує зовнішній IP, я боюся, у вас немає іншого вибору, крім як використовувати зовнішню службу, як ви. Якщо сам маршрутизатор має якийсь інтерфейс запиту, ви можете використовувати його, але рішення буде дуже специфічним для навколишнього середовища та ненадійним.


Так, погодьтеся. Ці хмарні сервери, що надаються AWS та GoogleGCP, надають лише внутрішню IP-адресу в запиті локального інтерфейсу. Ми повинні використовувати зовнішній для запиту його загальнодоступну IP-адресу.
Годинник ЧЖОНГ

100

Мені сподобався http://ipify.org . Вони навіть надають код Python для використання їх 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').text
print('My public IP address is: {}'.format(ip))

52

Python3, використовуючи не що інше, як стандартну бібліотеку

Як зазначалося раніше, можна скористатися зовнішньою службою, такою як https://ident.me , щоб виявити зовнішню IP-адресу вашого маршрутизатора.

Ось як це робиться python3, використовуючи не що інше, як стандартну бібліотеку:

import urllib.request

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

print(external_ip)

3
Хоча OP був для python 2, я думаю, що це має бути прийнятою відповіддю для Python 3, оскільки він не використовує сторонні бібліотеки. Однак зверніть увагу, що запити ident.me (та інші, такі як ipv4bot.whatismyipaddress.com ) займають приблизно вдвічі більше часу, ніж вимагає api.ipify.org або ipinfo.io/ip , використовуючи той самий код, що і відповідь. Найшвидший і найпростіший відгук, який я знайшов (серед півдюжини), - це відповідь api.ipify.org.
Олівер,

1
@Oliver За вашою пропозицією я протестував і те, api.ipify.orgі інше ident.meтут, в Європі, ident.meприблизно втричі швидше, ніж api.ipify.orgя розумію, ви знаходитесь у Канаді.
Серж Стробандт,

Сержу ха-ха, добре знати, що це має сенс, дякую за звіт. Так Канада.
Олівер,

1
Зверніть увагу, що адреса ident.meповерталася, IPv6коли я використовував її від хоста, тоді як інші повертали IPv4адреси з того самого місця.
jcoppens

26

Вам слід використовувати протокол UPnP для запиту маршрутизатора щодо цієї інформації. Найголовніше, що це не покладається на зовнішню послугу, яку, мабуть, пропонують усі інші відповіді на це питання.

Існує бібліотека Python з назвою miniupnp, яка може це зробити, див., Наприклад, miniupnpc / testupnpigd.py .

pip install miniupnpc

На їх прикладі ви зможете зробити щось подібне:

import miniupnpc

u = miniupnpc.UPnP()
u.discoverdelay = 200
u.discover()
u.selectigd()
print('external ip address: {}'.format(u.externalipaddress()))

1
Це працює, навіть коли ви підключені до VPN. Дякую
pumazi

не буде працювати при підключенні до openvpn. Exception: No UPnP device discovered
Нуреттін


10

На мій погляд, найпростішим рішенням є

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

Це все.


2
Напевно, варто згадати, що вам потрібно import requests. Див. Pypi.python.org/pypi/requests
Іван,

Технічно не відповідає на запитання, оскільки " Запити офіційно підтримують Python 2.6–2.7 & 3.3–3.7 і чудово працюють на PyPy". Однак він все-таки корисний іншим.
JerodG

6

Якщо ви вважаєте, що зовнішнє джерело занадто ненадійне, ви можете об’єднати кілька різних служб. Для більшості сторінок пошуку по ip вони вимагають зішкребти html, але деякі з них, які створили чисті сторінки для таких сценаріїв, як ваш, також можуть зменшити кількість звернень на своїх сайтах:


5

Спробуйте:

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

Сподіваюся, це корисно


4

Використовувати модуль запитів :

import requests

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

print("\n[+] Public IP: "+myip)

3

Якщо ви не хочете використовувати зовнішні послуги (веб-сайти IP тощо), ви можете використовувати протокол UPnP .

Для цього ми використовуємо просту клієнтську бібліотеку UPnP ( https://github.com/flyte/upnpclient )

Встановити :

pip встановити upnpclient - -

Простий код :

import upnpclient

devices = upnpclient.discover()

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

Повний код (щоб отримати більше інформації, як згадується в 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'}

2

Я спробував тут більшість інших відповідей на це питання і виявив, що більшість використовуваних послуг не працюють, окрім однієї.

Ось сценарій, який повинен зробити трюк і завантажити лише мінімальну кількість інформації:

#!/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() )

Regex порушено. Має бути \ d {1,3}.
Танос Діакакіс

2
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"

Блін, це трохи швидше, ніж просто використання BeautifulSoup, дякую
Елі

2

Є кілька інших способів, які не покладаються на перевірку Python зовнішнього веб-сайту, проте ОС може. Ваша основна проблема тут полягає в тому, що навіть якщо ви не використовували Python, якщо ви використовували командний рядок, немає "вбудованих" команд, які можуть просто повідомити вам зовнішній (WAN) IP. Такі команди, як "ip addr show" та "ifconfig -a", показують вам IP-адресу сервера в мережі. Лише маршрутизатор насправді має зовнішній IP. Однак є способи знайти зовнішню IP-адресу (WAN IP) з командного рядка.

Ці приклади:

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

Тому код python буде таким:

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

АБО

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

АБО

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

Або підключіть будь-який з наведених вище прикладів до такої команди, як os.popen, os.popen2, os.popen3 або os.system.


2

Так само просто, як запустити це в Python3:

import os

externalIP  = os.popen('curl -s ifconfig.me').readline()
print(externalIP)

1
Для цього потрібно встановити завиток
Мохімі

2

Рішення лише для Linux.

У системах Linux ви можете використовувати Python для виконання команди в оболонці. Думаю, це може комусь допомогти.

Щось на зразок цього (припускаючи, що функція 'dig / drill' працює на ОС)

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

Для користувачів Arch, будь ласка, замініть 'dig' на 'drill'.


результати в sh: 1: Синтаксична помилка: Невизначений цитований рядок
havlock

@havlock виправив. Будь ласка, перевірте.
Арпан Шрівастава

1

Якщо машина є брандмауером, ваше рішення є дуже розумним: альтернативою є можливість запиту брандмауера, який в кінцевому підсумку дуже залежить від типу брандмауера (якщо це можливо).


1

Найпростіше (непитонове) робоче рішення, яке я можу придумати, це

wget -q -O- icanhazip.com

Я хотів би додати дуже коротке рішення Python3, яке використовує JSON API 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'])

Звичайно, ви можете додати перевірку помилок, умову очікування та деяку зручність:

#!/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


1

Робота з Python 2.7 .6 та 2.7.13

import urllib2  
req = urllib2.Request('http://icanhazip.com', data=None)  
response = urllib2.urlopen(req, timeout=5)  
print(response.read())

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]

це короткий фрагмент, який я написав для іншої програми. Фокусом було знайти досить простий веб-сайт, щоб розбирати html не було болем.


Нещасний на службі зник: c
jkmartindale

0

Ось ще один альтернативний сценарій.

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

РЕДАГУВАТИ: Не забудьте імпортувати httplib та json


Ця відповідь використовується для роботи для мене, але пакетів перерви при оновленні з допомогою Конде, тому я відмовився від цієї відповіді для вирішення @Hors простіше Суб'єкт в stackoverflow.com/questions/24508730 / ...
nagordon

0

Якщо ви пишете лише для себе, а не для узагальненого додатка, можливо, ви зможете знайти адресу на сторінці налаштування вашого маршрутизатора, а потім викреслити її з html цієї сторінки. Це добре працювало для мене з моїм SMC-маршрутизатором. Одне читання та один простий пошук RE, і я його знайшов.

Мій особливий інтерес зробити це - повідомити свою домашню IP-адресу, коли я був далеко від дому, щоб я міг повернутися через VNC. Ще кілька рядків Python зберігають адресу в Dropbox для зовнішнього доступу і навіть надсилають мені електронного листа, якщо помічають зміни. Я запланував, що це відбуватиметься під час завантаження та один раз на годину після цього.


0

Використовуйте цей сценарій:

import urllib, json

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

Без json:

import urllib, re

data = re.search('"([0-9.]*)"', urllib.urlopen("http://ip.jsontest.com/").read()).group(1)
print data

0

Якщо ви не зацікавлені натискати будь-яку URL-адресу, щоб отримати загальнодоступний ip, я думаю, що наступний код може допомогти вам отримати загальнодоступний ip за допомогою python на вашій машині

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

sed -n 3p лінія змінюється залежно від мережі, яку ви використовуєте для підключення пристрою.

Я стикався з такою ж проблемою, мені потрібен був загальнодоступний ip пристрою iot, який потрапляє на мій сервер. але загальний ip абсолютно інший в команді ifconfig та ip, який я отримую на сервері від об'єкта запиту. після цього я додаю додатковий параметр у свій запит про надсилання ip пристрою на мій сервер.

сподіваюся, це корисно


0
import os
externalIp = os.popen("ipconfig").read().split(":")[15][1:14]

деякі номери, можливо, доведеться змінити, але це працює для мене


0

Я використовую IPGrab, тому що це легко запам'ятати:

# 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))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.