Поиск локальных 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-адреса, вероятно, является более надежным, чем любой из перечисленных здесь методов.