Вопрос-Ответ

Finding local IP addresses using Python's stdlib

Поиск локальных IP-адресов с помощью stdlib в Python

Как я могу найти локальные IP-адреса (например, 192.168.x.x или 10.0.x.x) в платформе Python независимо и используя только стандартную библиотеку?

Переведено автоматически
Ответ 1

Я только что нашел это, но это кажется немного хакерским, однако они говорят, что попробовали это на * nix, а я сделал на Windows, и это сработало.

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
print(s.getsockname()[0])
s.close()

Предполагается, что у вас есть доступ в Интернет и что локального прокси-сервера нет.

Ответ 2
import socket
socket.gethostbyname(socket.gethostname())

Это будет работать не всегда (возвращает 127.0.0.1 на машинах, имеющих имя хоста в /etc/hosts виде 127.0.0.1), альтернативным вариантом было бы то, что показывает gimel, используйте socket.getfqdn() вместо этого. Конечно, вашему компьютеру нужно разрешаемое имя хоста.

Ответ 3

Этот метод возвращает "основной" IP-адрес в локальном окне (тот, у которого маршрут по умолчанию).


  • НЕ требует маршрутизируемого сетевого доступа или какого-либо подключения вообще.

  • Работает, даже если все интерфейсы отключены от сети.

  • Не требует и даже не пытается получить где-либо еще.

  • Работает с NAT, общедоступными, частными, внешними и внутренними IP-адресами

  • Чистый Python 2 (или 3) без внешних зависимостей.

  • Работает в Linux, Windows и OSX.

Python 3 или 2:

    import socket
def get_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(0)
try:
# doesn't even have to be reachable
s.connect(('10.254.254.254', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
print(get_ip())

Это возвращает единственный IP-адрес, который является основным (с маршрутом по умолчанию). Если вместо этого вам нужны все IP-адреса, подключенные ко всем интерфейсам (включая localhost и т.д.), посмотрите что-то вроде этого ответа.

Если вы находитесь за брандмауэром NAT, например, за вашим домашним маршрутизатором Wi-Fi, то это не покажет ваш общедоступный IP-адрес NAT, а вместо этого ваш частный IP-адрес в локальной сети, который имеет маршрут по умолчанию к вашему локальному маршрутизатору Wi-Fi. Если вместо этого вам нужен ваш внешний IP-адрес:


  • запуск этой функции на ЭТОМ внешнем устройстве (wifi-маршрутизаторе) или



  • подключение к внешней службе, такой как https://www.ipify.org / которая могла бы отражать IP-адрес таким, каким он виден из внешнего мира



... но эти идеи полностью отличаются от первоначального вопроса. :)

Ответ 4

В качестве псевдонима называется myip:

alias myip="python -c 'import socket; print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith(\"127.\")][:1], [[(s.connect((\"8.8.8.8\", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])'"

  • Корректно работает с Python 2.x, Python 3.x, современными и старыми дистрибутивами Linux, OSX / macOS и Windows для поиска текущего IPv4-адреса.

  • Не вернет правильный результат для машин с несколькими IP-адресами, IPv6, без настроенного IP-адреса или без доступа в Интернет.

  • Как сообщается, это не работает в последних версиях macOS.

ПРИМЕЧАНИЕ: Если вы собираетесь использовать что-то подобное в программе на Python, правильный способ - использовать модуль Python, поддерживающий IPv6.


То же, что и выше, но только код на Python:

import socket
print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])

  • Это вызовет исключение, если IP-адрес не настроен.


Версия, которая также будет работать в локальных сетях без подключения к Интернету:

import socket
print((([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")] or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) + ["no IP found"])[0])

(спасибо @ccpizza)


Справочная информация:

Использование socket.gethostbyname(socket.gethostname()) здесь не сработало, потому что на одном из компьютеров, на которых я был, был /etc/hosts с дублирующимися записями и ссылками на самого себя. socket.gethostbyname() возвращает только последнюю запись в /etc/hosts.

Это была моя первая попытка, которая отсеивает все адреса, начинающиеся с "127.":

import socket
print([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1])

Это работает с Python 2 и 3 в Linux и Windows, но не работает с несколькими сетевыми устройствами или IPv6. Однако в последних дистрибутивах Linux это перестало работать, поэтому я попробовал этот альтернативный метод. Он пытается подключиться к DNS-серверу Google по адресу 8.8.8.8 через порт 53:

import socket
print([(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1])

Этот метод также работает в последних версиях macOS!

Затем я объединил два вышеперечисленных метода в однострочный, который должен работать везде, и создал myip псевдоним и фрагмент Python вверху этого ответа.

С ростом популярности IPv6 и для серверов с несколькими сетевыми интерфейсами использование модуля Python сторонних производителей для поиска IP-адреса, вероятно, является более надежным, чем любой из перечисленных здесь методов.

2023-04-25 23:11 python