Как я могу получить IP-адрес eth0 в Python?

42

При возникновении ошибки в Python script в Unix отправляется электронное письмо.

Мне было предложено добавить {Testing Environment} в строку темы письма, если IP-адрес 192.168.100.37, который является сервером тестирования. Таким образом, мы можем иметь одну версию script и способ узнать, поступает ли почта из испорченных данных на тестовом сервере.

Однако, когда я google, я продолжаю находить этот код:

import socket
socket.gethostbyname(socket.gethostname())

Однако это дает мне IP-адрес 127.0.1.1. Когда я использую ifconfig, я получаю это

eth0      Link encap:Ethernet  HWaddr 00:1c:c4:2c:c8:3e
          inet addr:192.168.100.37  Bcast:192.168.100.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:75760697 errors:0 dropped:411180 overruns:0 frame:0
          TX packets:23166399 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:59525958247 (59.5 GB)  TX bytes:10142130096 (10.1 GB)
          Interrupt:19 Memory:f0500000-f0520000

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:25573544 errors:0 dropped:0 overruns:0 frame:0
          TX packets:25573544 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:44531490070 (44.5 GB)  TX bytes:44531490070 (44.5 GB)

Во-первых, я не знаю, откуда он получил 127.0.1.1, но в любом случае это не то, что я хочу. Когда я google, я продолжаю приходить к тому же синтаксису, Bash сценарии или сетевые файлы, и я пытаюсь использовать стандартные библиотеки.

Итак, как я могу получить IP-адрес eth0 в Python?

  • 0
    «Я не знаю, откуда он взял 127.0.1.1» из файла /etc/hosts .
  • 0
    Вы упомянули « 127.0.1.1 ». Вы 127.0.0.1 виду " 127.0.0.1 "? Потому что это ваш локальный петлевой интерфейс, lo (вторая запись в вашем выводе ifconfig ); и первая запись, если вы cat /etc/hosts .
Теги:

8 ответов

127
Лучший ответ

Два метода:

Метод # 1 (используйте внешний пакет)

Вам нужно задать IP-адрес, привязанный к вашему интерфейсу eth0. Это доступно из пакета netifaces

import netifaces as ni
ni.ifaddresses('eth0')
ip = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
print ip  # should print "192.168.100.37"

Вы также можете получить список всех доступных интерфейсов через

ni.interfaces()

Метод № 2 (без внешнего пакета)

Здесь можно получить IP-адрес без использования пакета python:

import socket
import fcntl
import struct

def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', ifname[:15])
    )[20:24])

get_ip_address('eth0')  # '192.168.0.110'

Примечание. Определение IP-адреса для определения того, какая среда вы используете, - это взломать. Почти все фреймворки предоставляют очень простой способ установить/изменить переменную среды, чтобы указать текущую среду. Попробуйте и посмотрите на свою документацию. Это должно быть так же просто, как делать

if app.config['ENV'] == 'production':
  #send production email
else:
  #send development email
  • 1
    Netifaces стандартная библиотека?
  • 1
    Этого нет в стандартной библиотеке, но он добавил ссылку
Показать ещё 17 комментариев
56

В качестве альтернативы, если вы хотите получить IP-адрес какого-либо интерфейса, который используется для подключения к сети, не зная его имени, вы можете использовать это:

import socket
def get_ip_address():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(("8.8.8.8", 80))
    return s.getsockname()[0]

Я знаю, это немного отличается от вашего вопроса, но другие могут приехать сюда и найти это еще один полезный. Для этого вам не нужно иметь маршрут до 8.8.8.8. Все, что он делает, это открыть сокет, но не отправлять какие-либо данные.

  • 1
    8.8.8.8 - это DNS-сервер Google, верно?
  • 2
    Да, вероятно, никуда не денется, но некоторые локальные сети могут не подвергаться этому.
Показать ещё 7 комментариев
15

Простой подход, который возвращает строку с ip-адресами для интерфейсов:

from subprocess import check_output

ips = check_output(['hostname', '--all-ip-addresses'])

для получения дополнительной информации см. hostname.

  • 0
    Мне особенно нравится этот, поскольку он обеспечивает правильный IP-адрес контейнера докера, находясь внутри контейнера. В противном случае можно было бы перейти к первому сообщаемому. Замечательно!
  • 1
    Это характерно для версии имени hostname Linux net-tools. Команда имени хоста Mac / BSD не предоставляет эту функциональность. Если вы используете версию для Linux, это, вероятно, самый простой способ сделать это.
Показать ещё 1 комментарий
15

Если вам нужно только работать в Unix, вы можете использовать системный вызов (ref. Qaru question Разбор ifconfig для получения только моего IP-адреса с помощью Bash):

import os
f = os.popen('ifconfig eth0 | grep "inet\ addr" | cut -d: -f2 | cut -d" " -f1')
your_ip=f.read()
  • 0
    это хорошо, мне не нравится внешний пакет.
  • 2
    Этот характерен для дистрибутива. Например, на RHEL, команды cut обрезают неверный термин. Так что этот не переносится на дистрибутивы * nix.
Показать ещё 1 комментарий
10

Поскольку большинство ответов используют ifconfig для извлечения IPv4 из интерфейса eth0, который устарел в пользу ip addr, вместо этого можно использовать следующий код:

import os

ipv4 = os.popen('ip addr show eth0 | grep "\<inet\>" | awk \'{ print $2 }\' | awk -F "/" \'{ print $1 }\'').read().strip()
ipv6 = os.popen('ip addr show eth0 | grep "\<inet6\>" | awk \'{ print $2 }\' | awk -F "/" \'{ print $1 }\'').read().strip()

UPDATE:

В качестве альтернативы вы можете перенести часть задачи синтаксического анализа на интерпретатор python, используя split() вместо grep и awk, поскольку @serg указывает в комментарии:

import os

ipv4 = os.popen('ip addr show eth0').read().split("inet ")[1].split("/")[0]
ipv6 = os.popen('ip addr show eth0').read().split("inet6 ")[1].split("/")[0]

Но в этом случае вам нужно проверить границы массива, возвращаемые каждым вызовом split().

ОБНОВЛЕНИЕ 2:

Другая версия с использованием регулярного выражения:

import os
import re

ipv4 = re.search(re.compile(r'(?<=inet )(.*)(?=\/)', re.M), os.popen('ip addr show eth0').read()).groups()[0]
ipv6 = re.search(re.compile(r'(?<=inet6 )(.*)(?=\/)', re.M), os.popen('ip addr show eth0').read()).groups()[0]
  • 3
    хорошая работа по использованию ip addr но на самом деле нет необходимости направлять вывод в grep и awk. Python более чем способен анализировать вывод с помощью split ()
  • 0
    Чтобы сделать его немного более машинно-разборным, попробуйте опцию -oneline . "output each record on a single line, replacing line feeds with the '\' character. This is convenient when you want to count records with wc(1) or to grep(1) the output."
Показать ещё 1 комментарий
2

попробуйте под кодом, он работает для меня в Mac10.10.2:

import subprocess

if __name__ == "__main__":
    result = subprocess.check_output('ifconfig en0 |grep -w inet', shell=True) # you may need to use eth0 instead of en0 here!!!
    print 'output = %s' % result.strip()
    # result = None
    ip = ''
    if result:
        strs = result.split('\n')
        for line in strs:
            # remove \t, space...
            line = line.strip()
            if line.startswith('inet '):
                a = line.find(' ')
                ipStart = a+1
                ipEnd = line.find(' ', ipStart)
                if a != -1 and ipEnd != -1:
                    ip = line[ipStart:ipEnd]
                    break
    print 'ip = %s' % ip
0

Найдите IP-адрес первой записи eth/wlan в ifconfig, что RUNNING:

import itertools
import os
import re

def get_ip():
    f = os.popen('ifconfig')
    for iface in [' '.join(i) for i in iter(lambda: list(itertools.takewhile(lambda l: not l.isspace(),f)), [])]:
        if re.findall('^(eth|wlan)[0-9]',iface) and re.findall('RUNNING',iface):
            ip = re.findall('(?<=inet\saddr:)[0-9\.]+',iface)
            if ip:
                return ip[0]
    return False
0

Это сработало для меня

 import subprocess
 my_ip = subprocess.Popen(['ifconfig eth0 | awk "/inet /" | cut -d":" -f 2 | cut -d" " -f1'], stdout=subprocess.PIPE, shell=True)
 (IP,errors) = my_ip.communicate()
 my_ip.stdout.close()
 print IP
  • 0
    Я предполагаю, что кто-то -1 это сделал, потому что Linux не использует разделитель ":" в выводе ifconfig. Эта команда будет работать только на некоторых Unix, которые включают такую вещь.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню