Pythonのstdlibを使用してローカルIPアドレスを見つける


547

PythonライブラリでローカルIPアドレス(つまり、192.168.xxまたは10.0.xx)を個別に検索し、標準ライブラリのみを使用するにはどうすればよいですか?


7
ローカルIP?またはパブリックIPですか?複数のIPを持つシステムにどのように対処しますか?
Sargun Dhillon、

ifconfig -aそこからの出力を使用し、使用します...
Fredrik Pihl

16
@Fredrikそれは悪い考えです。まず、不必要に新しいプロセスをforkしているため、プログラムが厳格にロックされた構成で機能しない可能性があります(または、プログラムに必要のない権限を許可する必要があります)。次に、異なるロケールのユーザー向けにバグを紹介します。第三に、あればあなたはすべての新しいプログラムを開始することを決定、あなたは非推奨のものを起動してはならない- ip addr(ブートに、かつ容易に解析するために)はるかに適しています。
phihag

12
@phihagあなたは完全に正しいです。私の愚かさを正してくれてありがとう
Fredrik Pihl

1
ここでのより根本的な問題は、適切に作成された最新のネットワークプログラムでは、ローカルIPアドレス(のセット)がピアまたは潜在的なピアのセットに依存していることです。bind特定のインターフェースへのソケットにローカルIPアドレスが必要な場合、それはポリシーの問題です。ローカルIPアドレスがピアに引き渡して、ピアが「コールバック」できるように、つまりローカルマシンへの接続を開くために必要な場合、NAT(ネットワークアドレス変換)があるかどうかによって状況が異なります。間にボックス。NATがない場合getsocknameは、を選択してください。
Pekka Nikander

回答:


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

これは常に機能するわけではありません(127.0.0.1ホスト名が/etc/hostsas であるマシンで返されます127.0.0.1socket.getfqdn()。もちろん、マシンには解決可能なホスト名が必要です。


43
これはプラットフォームに依存しないソリューションではないことに注意してください。多くのLinuxは、この方法を使用してIPアドレスとして127.0.0.1を返します。
Jason Baker、

20
バリエーション:socket.gethostbyname(socket.getfqdn())
ギメル2008年

55
これは単一のIPアドレスのみを返すようです。マシンに複数のアドレスがある場合はどうなりますか?
Jason R. Coombs、

26
Ubuntuでは、何らかの理由で127.0.1.1を返します。
slikts

13
@Jason R.クームス、ホストマシンに属しているIPv4アドレスのリストを取得するために使用、次のコード:socket.gethostbyname_ex(socket.gethostname())[-1]
Barmaley

460

私はこれを見つけたばかりですが、少しハッカらしいようですが、* 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()

これは、インターネットアクセスがあり、ローカルプロキシがないことを前提としています。


31
マシンに複数のインターフェースがあり、たとえばgmail.comにルーティングするインターフェースが必要な場合
elzapp

4
s.connect()によって発生する可能性のあるsocket.error例外をキャッチすることをお勧めします!
phobie

39
ドメイン名の代わりにIPアドレスを使用することをお勧めします。DNSの可用性とは無関係に高速である必要があります。たとえば、8.8.8.8 IPを使用できます-GoogleのパブリックDNSサーバー。
ウォブメン

10
非常に賢く、完璧に動作します。該当する場合は、Gmailまたは8.8.8.8の代わりに、表示したいサーバーのIPまたはアドレスを使用することもできます。
ファルケン教授の契約が

3
この例には、実際にgmail.comを解決できるという外部依存関係があります。ローカルLANにないIPアドレスに設定した場合(アップかダウンかは関係ありません)、依存関係やネットワークトラフィックがなくても機能します。
2015年

254

このメソッドは、ローカルボックス(デフォルトルートを持つもの)の「プライマリ」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)
    try:
        # doesn't even have to be reachable
        s.connect(('10.255.255.255', 1))
        IP = s.getsockname()[0]
    except Exception:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP

これは、プライマリ(デフォルトルートを持つIP)である単一のIPを返します。代わりに、すべてのインターフェース(localhostなどを含む)に接続されているすべてのIPが必要な場合は、この回答を参照してください。

自宅のwifiボックスなどのNATファイアウォールの背後にいる場合、これはパブリックNAT IPを表示せず、ローカルWIFIルーターへのデフォルトルートを持つローカルネットワーク上のプライベートIPを表示します。wifiルーターの外部IPを取得するには、このボックスでこれを実行するか、whatismyip.com / whatismyipaddress.comなどのIPを反映する外部サービスに接続する必要がありますが、元の質問とはまったく異なります。:)


7
Python 2および3のRaspbianで動作します!
pierce.jason 2015

3
鮮やかさ。Win7、8、8.1 + Linux Mint&Arch(VMを含む)で動作します。
シャーミー

2
Windows 10 Proで動作します!ジェイミソン・ベッカー、ありがとう!
varantes 2017

3
何らかの理由で、これはMac OS X El Capitan 10.11.6では機能しません(例外のOSエラーが生成されます:[Errno 49]要求されたアドレスを割り当てられません)。ポートを「0」から「1」に変更:s.connect(( '10.255.255.255'、1))は、Mac OS XとLinux Ubuntu 17.04の両方で機能しました
Pedro Scarapicchia Junior

10
これは受け入れられる答えになるはずです。 socket.gethostbyname(socket.gethostname())恐ろしい結果をもたらします。
ジェイソンフロイド

142

と呼ばれるエイリアスとして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])'"
  • 現在のIPv4アドレスを見つけるために、Python 2.x、Python 3.x、最新および古いLinuxディストリビューション、OSX / macOS、Windowsで正しく動作します。
  • 複数のIPアドレス、IPv6、構成済みのIPアドレスがない、またはインターネットアクセスがないマシンでは、正しい結果を返しません。

上記と同じですが、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アドレスが構成されていない場合は、例外がスローされます。

インターネット接続のないLANでも機能するバージョン:

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())私が使用していたコンピュータの1つに、/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])

これは、LinuxおよびWindows上のPython 2および3で動作しますが、いくつかのネットワークデバイスまたはIPv6には対応していません。ただし、最近のLinuxディストリビューションでは機能しなくなったため、代わりにこの代替手法を試しました。8.8.8.8ポートでGoogle DNSサーバーに接続しようとします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])

次に、上記の2つの手法を組み合わせて、どこでも機能するワンライナーを作成し、myipこの回答の上部にエイリアスとPythonスニペットを作成しました。

IPv6の人気が高まり、複数のネットワークインターフェイスを備えたサーバーでは、サードパーティのPythonモジュールを使用してIPアドレスを検索する方が、ここに記載されているどの方法よりも堅牢で信頼性が高いでしょう。


2
@Alexander:この答えは、以前よりはるかに役に立たないと言っているだけです(そして、重複を除外するのは大したことではありません;)。ドキュメントによると、socket.getaddrinfo()プラットフォーム間で一貫して動作するはずですが、私はLinuxでのみ確認し、他のオペレーティングシステムについては気にしませんでした。
Wladimir Palant 2013年

1
@Alexander、/etc/resolve.conf: No such file or directoryそして私はで示されるローカルIPv4アドレスを持っていますifconfig
anatly techtonik 2013

2
更新されたバージョンは、Python2とPy3kの両方でUbuntu 14.04で動作することを確認できます。
UliKöhler2014

4
「更新」は、UDPソケットでconnect()を使用する優れたトリックを示しています。トラフィックは送信しませんが、指定した受信者へのパケットの送信者アドレスを見つけることができます。ポートはおそらく無関係です(0でも機能するはずです)。マルチホームホストでは、正しいサブネットでアドレスを選択することが重要です。
Peter Hansen

17
そのコードを1行で記述できるからといって、そうする必要があるわけではありません...
JackLeo

91

netifacesモジュールを使用できます。入力するだけです:

pip install netifaces

コマンドシェルで実行すると、デフォルトのPythonインストールに自動的にインストールされます。

その後、次のように使用できます。

from netifaces import interfaces, ifaddresses, AF_INET
for ifaceName in interfaces():
    addresses = [i['addr'] for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr':'No IP addr'}] )]
    print '%s: %s' % (ifaceName, ', '.join(addresses))

私のコンピューターではそれが印刷されました:

{45639BDC-1050-46E0-9BE9-075C30DE1FBC}:192.168.0.100
{D43A468B-F3AE-4BF9-9391-4863A4500583}:10.5.9.207

このモジュールの作成者は、Windows、UNIX、およびMac OS Xで動作するはずであると主張しています。


20
質問で述べたように、追加のインストールは必要ないので、デフォルトのインストールから何かが欲しいです。
UnkwnTech

4
これは、netifacesがWindowsでIPv6をサポートしておらず、メンテナンスされていないように見えることを除いて、私のお気に入りの答えです。WindowsでIPv6アドレスを取得する方法を誰かが理解しましたか?
Jean-Paul Calderone

3
netifacesはpy3kをサポートしておらず、Windows上のPITAであるCコンパイラを必要とします。
マットジョイナー

4
@MattJoinerこのどちらも当てはまりません(最新バージョンではPyPIにWindowsバイナリがあり、Py3Kをサポートしています)。
alastair 2014年

4
ジャンPaulCalderone FWIW、netifacesの最新バージョン@ 行い、Windows上でIPv6をサポートしています。
alastair 2014年

47

ソケットAPIメソッド

https://stackoverflow.com/a/28950776/711085を参照してください

欠点:

  • クロスプラットフォームではありません。
  • インターネット上の特定のアドレスの存在に関連する、より多くのフォールバックコードが必要
  • これは、NATの背後にいる場合も機能しません。
  • おそらくUDP接続を作成し、(通常はISPの)DNSの可用性とは無関係です(8.8.8.8の使用などのアイデアについては、他の回答を参照してください:Google(偶然にもDNS)サーバー)
  • 未使用であることが保証されている数値IPアドレスのように、宛先アドレスを必ず到達不能にしてください。fakesubdomain.google.comやsomefakewebsite.comなどのドメインは使用しないでください。あなたはまだそのパーティーをスパムしているでしょう(現在または将来)。その過程であなた自身のネットワークボックスもスパムします。

リフレクター方式

(これは、192.168などのローカルIPアドレスのOPの質問に答えないことに注意してください。これは、パブリックIPアドレスを提供します。これは、ユースケースによってはより望ましい場合があります。)

whatismyip.com(ただしAPIを使用)などのサイトにクエリを実行できます。

from urllib.request import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

またはpython2を使用している場合:

from urllib import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

利点:

  • この方法の利点の1つは、クロスプラットフォームであることです。
  • それは醜いNAT(例えばあなたのホームルーター)の後ろから動作します。

短所(および回避策):

  • このWebサイトが稼働していること、形式が変更されないこと(ほとんどの場合変更されないこと)、およびDNSサーバーが機能していることが必要です。障害が発生した場合に、他のサードパーティのIPアドレスリフレクターをクエリすることで、この問題を軽減できます。
  • 複数のリフレクターにクエリを実行しない場合(侵害されたリフレクターがアドレスがそうでないものであると通知しないようにするため)、またはHTTPSを使用しない場合(中間者攻撃のふりを防ぐため)サーバーになる)

編集:最初はこれらの方法は本当に悪いと思っていましたが(多くのフォールバックを使用しない限り、コードは何年も関係ない可能性があります)、「インターネットとは何ですか?」コンピュータには、多くの異なるネットワークを指す多くのインターフェイスがある場合があります。トピックのより完全な説明については、google forgateways and routes。コンピュータは、内部ゲートウェイを介して内部ネットワークにアクセスしたり、ルーターなどのゲートウェイ(通常はケース)を介してワールドワイドウェブにアクセスしたりできます。OPが要求するローカルIPアドレスは、単一のリンクレイヤーに関してのみ明確に定義されているため、それを指定する必要があります(「ネットワークカード、またはイーサネットケーブルのことですか?」) 。提示されているように、この質問に対する複数の一意でない回答がある場合があります。ただし、ワールドワイドWeb上のグローバルIPアドレスはおそらく明確に定義されています(大規模なネットワークの断片化がない場合)。おそらく、TLDにアクセスできるゲートウェイ経由のリターンパスです。


NATの背後にいる場合は、LAN全体のアドレスが返されます。インターネットに接続している場合は、パブリックIPアドレスの1つを返すWebサービスに接続できます。
phihag

UDP接続を作成するため、TCP接続は作成されません。
Anuj Gupta

2
ソケットAPIバージョンの代替手段として、s.connect(( 'INSERT SOME TARGET WEBSITE.com'、0))をs.setsockopt(socket.SOL_SOCKET、socket.SO_BROADCAST、1); s.connect(( '< broadcast> '、0))DNSルックアップを回避します。(ファイアウォールがある場合、ブロードキャストに問題があると思います)
dlm

45

コンピューターにインターネットへのルートがある場合、/ etc / hostsが正しく設定されていなくても、これは常に優先ローカルIPアドレスを取得するために機能します。

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 1))  # connect() for UDP doesn't send packets
local_ip_address = s.getsockname()[0]

これはどのように作動しますか ?、8.8.8.8Google DNSサーバーはローカルDNSサーバーで実行できますか?
Ciasto piekarz

39

Linuxの場合:

>>> import socket, struct, fcntl
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> sockfd = sock.fileno()
>>> SIOCGIFADDR = 0x8915
>>>
>>> def get_ip(iface = 'eth0'):
...     ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)
...     try:
...         res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq)
...     except:
...         return None
...     ip = struct.unpack('16sH2x4s8x', res)[2]
...     return socket.inet_ntoa(ip)
... 
>>> get_ip('eth0')
'10.80.40.234'
>>> 

つまり、これは実質的に何もしないソケットを開き、そのソケットに関する生データをチェックしてローカルIPを取得しますか?
Dave、

1
ソケットは、fdがカーネルと通信するために開かれます(を介してioctl)。ソケットは、addr情報が必要なインターフェイスにバインドされていません。ユーザー空間とカーネル間の単なる通信メカニズムです。en.wikipedia.org/wiki/Ioctl lxr.free-electrons.com/source/net/socket.c
tMC

2
Python3で動作し、1つの変更:struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)置き換えられる必要がありますstruct.pack('16sH14s', iface.encode('utf-8'), socket.AF_INET, b'\x00'*14)
pepoluan

1
@ChristianFischer ioctlはレガシーインターフェイスであり、IPv6をサポートしているとは信じていません。私は「正しい」方法は、Pythonではあまり簡単ではないNetlinkを経由していると思います。libcにはpythonsモジュールgetifaddrs経由でアクセスできる機能が必要ctypesです。man7.org/ linux / man - pages / man3 / getifaddrs.3.html
linux

1
@Maddy ioctlはレガシーインターフェイスであり、IPv6をサポートしているとは信じていません。私は「正しい」方法は、Pythonではあまり簡単ではないNetlinkを経由していると思います。libcには、機能する可能性があるpythons ctypesモジュールを介してアクセスできる関数getifaddrsが必要です-man7.org/linux/man-pages/man3/getifaddrs.3.html
tMC

27

私は次のモジュールを使用しています:

#!/usr/bin/python
# module for getting the lan ip address of the computer

import os
import socket

if os.name != "nt":
    import fcntl
    import struct
    def get_interface_ip(ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(
                s.fileno(),
                0x8915,  # SIOCGIFADDR
                struct.pack('256s', bytes(ifname[:15], 'utf-8'))
                # Python 2.7: remove the second argument for the bytes call
            )[20:24])

def get_lan_ip():
    ip = socket.gethostbyname(socket.gethostname())
    if ip.startswith("127.") and os.name != "nt":
        interfaces = ["eth0","eth1","eth2","wlan0","wlan1","wifi0","ath0","ath1","ppp0"]
        for ifname in interfaces:
            try:
                ip = get_interface_ip(ifname)
                break;
            except IOError:
                pass
    return ip

単一のIPv4ベースのLANにあるシステムでの使用を目的としたWindowsおよびLinuxでテストされています(これらのモジュールを追加する必要はありません)。

インターフェース名の固定リストは、Alexanderによって指摘された予測可能なインターフェース名に関するsystemd v197の変更を採用した最近のLinuxバージョンでは機能しません。このような場合は、リストをシステムのインターフェース名に手動で置き換えるか、netifacesなどの別のソリューションを使用する必要があります。


2
これは、などの新しい予測可能なLinuxインターフェイス名と互換性がありませんenp0s25。詳細については、wiki.archlinux.org / index.php / Network_Configuration
Alexander

2
私はpython 3.4を使用していて、「struct.pack(...)」の部分を「struct.pack( '256s'、bytes(ifname [:15]、 'utf-8'))」に変更する必要がありました。この質問を参照してください:stackoverflow.com/q/27391167/76010
Bakanekobrain

1
Python 2.7.3を使用するRaspbianでは-bytes()は2番目の引数が好きではありませんでした。しかし、これは機能しました: struct.pack('256s', bytes(ifname[:15]))
colm.anseo

24

私はこれを私のubuntuマシンで使用します。

import commands
commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]

これは機能しません。


素敵でシンプル。AmazonのLinux AMIでも動作しますが、私がrootである場合のみです。そうしないと、エラーが発生します: 'sh:ifconfig:command not found'
IgorGanapolsky

したがって、gavaletzが言ったように「/ sbin / ifconfig」を使用する必要があります。Red Hat 4.1.2-48でも動作します。
IgorGanapolsky 2010年

7
2.6以降非推奨。コマンドを実行するには、サブプロセスモジュールを使用します。
Colin Dunklau 2013年

5
また、ifconfigも非推奨になりました。iproute2を使用します。
Helmut Grohne 2013

すべてのIPを取得します。shをインポートします。[ip.split()[1] [5:] for ip in filter(lambda x: 'inet addr' in x、sh.ifconfig()。split( "\ n"))]
Gabriel Littman

20

外部パッケージを使用したくない場合や、外部のインターネットサーバーに依存したくない場合は、これが役立つ場合があります。これは、Google Code Searchで見つけ、必要な情報を返すように変更したコードサンプルです。

def getIPAddresses():
    from ctypes import Structure, windll, sizeof
    from ctypes import POINTER, byref
    from ctypes import c_ulong, c_uint, c_ubyte, c_char
    MAX_ADAPTER_DESCRIPTION_LENGTH = 128
    MAX_ADAPTER_NAME_LENGTH = 256
    MAX_ADAPTER_ADDRESS_LENGTH = 8
    class IP_ADDR_STRING(Structure):
        pass
    LP_IP_ADDR_STRING = POINTER(IP_ADDR_STRING)
    IP_ADDR_STRING._fields_ = [
        ("next", LP_IP_ADDR_STRING),
        ("ipAddress", c_char * 16),
        ("ipMask", c_char * 16),
        ("context", c_ulong)]
    class IP_ADAPTER_INFO (Structure):
        pass
    LP_IP_ADAPTER_INFO = POINTER(IP_ADAPTER_INFO)
    IP_ADAPTER_INFO._fields_ = [
        ("next", LP_IP_ADAPTER_INFO),
        ("comboIndex", c_ulong),
        ("adapterName", c_char * (MAX_ADAPTER_NAME_LENGTH + 4)),
        ("description", c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)),
        ("addressLength", c_uint),
        ("address", c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH),
        ("index", c_ulong),
        ("type", c_uint),
        ("dhcpEnabled", c_uint),
        ("currentIpAddress", LP_IP_ADDR_STRING),
        ("ipAddressList", IP_ADDR_STRING),
        ("gatewayList", IP_ADDR_STRING),
        ("dhcpServer", IP_ADDR_STRING),
        ("haveWins", c_uint),
        ("primaryWinsServer", IP_ADDR_STRING),
        ("secondaryWinsServer", IP_ADDR_STRING),
        ("leaseObtained", c_ulong),
        ("leaseExpires", c_ulong)]
    GetAdaptersInfo = windll.iphlpapi.GetAdaptersInfo
    GetAdaptersInfo.restype = c_ulong
    GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, POINTER(c_ulong)]
    adapterList = (IP_ADAPTER_INFO * 10)()
    buflen = c_ulong(sizeof(adapterList))
    rc = GetAdaptersInfo(byref(adapterList[0]), byref(buflen))
    if rc == 0:
        for a in adapterList:
            adNode = a.ipAddressList
            while True:
                ipAddr = adNode.ipAddress
                if ipAddr:
                    yield ipAddr
                adNode = adNode.next
                if not adNode:
                    break

使用法:

>>> for addr in getIPAddresses():
>>>    print addr
192.168.0.100
10.5.9.207

に依存しているためwindll、これはWindowsでのみ機能します。


上記の1つのライナーソリューションは、通常、Windowsで機能します。問題となっているのはLinuxの問題です。
ricree 09年

14
+1この手法は、少なくともマシン上のすべてのアドレスを返そうとします。
Jason R. Coombs

1
このスクリプトは、最初のアドレスを返した後、私のマシンで失敗します。エラーは「AttributeError: 'LP_IP_ADDR_STRING' object has no attribute 'ipAddress'」です。IPv6アドレスと関係があるのではないかと思います。
Jason R. Coombs

1
問題は、最初のIPアドレス以外の場合は、adNodeが逆参照されないことが判明したことです。whileループの例にもう1行追加すると、私にとってはうまくいきます。adNode = adNode.contents
Jason R. Coombs

18

Debian(テスト済み)と私はほとんどのLinuxを疑っています。

import commands

RetMyIP = commands.getoutput("hostname -I")

MS Windows(テスト済み)

import socket

socket.gethostbyname(socket.gethostname())

1
macOSでは機能しません:hostname: illegal option -- I\nusage: hostname [-fs] [name-of-host]
Derek款會功夫

18

信じられないバージョンがまだ投稿されています。Ubuntu 12.04でpython 2.7を使用してテストしました。

このソリューションはhttp://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/にあります

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')
'38.113.228.130'

2
Python3、Ubuntu 18.04で動作します。文字列はバイトである必要があります:>>> socket.inet_ntoa(fcntl.ioctl(s.fileno()、0x8915、struct.pack( '256s'、 'enp0s31f6' [:15] .encode( 'utf-8') ))[20:24]) '192.168.1.1'
後任

12

ninjageckoの答えのバリエーション。これは、UDPブロードキャストを許可し、LANまたはインターネット上のアドレスへのアクセスを必要としない任意のLANで機能するはずです。

import socket
def getNetworkIp():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    s.connect(('<broadcast>', 0))
    return s.getsockname()[0]

print (getNetworkIp())

待って、<broadcast>有効なホスト名はどうですか?!! これらの種類の口頭のホスト名のうちいくつが有効ですか?
Dev Aggarwal

これはUbuntu 20.04で私に有効です-127.0.0.1ではなく192.168.0.24を取得します
ルイスモリス

8

別のコンピューターに接続してIPアドレスを送信させる以外に、プラットフォームに依存しない適切な方法はありません。例: findmyipaddress。接続しているコンピューターもNATの背後にある場合を除き、NATの背後にあるIPアドレスが必要な場合、これは機能しないことに注意してください。

Linuxで機能するソリューションの1つ は、ネットワークインターフェースに関連付けられたIPアドレスを取得することです


8

コマンドラインユーティリティを使用して「クリーン」な出力を生成する簡単な方法の1つ:

import commands
ips = commands.getoutput("/sbin/ifconfig | grep -i \"inet\" | grep -iv \"inet6\" | " +
                         "awk {'print $2'} | sed -ne 's/addr\:/ /p'")
print ips

システム上のすべてのIPv4アドレスが表示されます。


1
ifconfigはプライマリアドレスのみを通知するため、すべてのIPv4アドレスは表示されません。すべてのアドレスを表示するには、iproute2の「ip」を使用する必要があります。
Helmut Grohne 2013

これは、標準ライブラリを求める質問に対する多くのシェルの地獄です…また、ifconfigの解析は移植性がなく、1台のマシンでさえも確実に機能しません。
ドミニクジョージ

7

参考までに、次の方法を確認できます。

import socket
addr = socket.gethostbyname(socket.gethostname())

OS X(10.6、10.5)、Windows XP、および適切に管理されたRHEL部門サーバーで動作します。カーネルハッキングを実行するだけの最小限のCentOS VMでは機能しませんでした。したがって、そのインスタンスでは、127.0.0.1アドレスを確認するだけでよく、その場合は次のようにします。

if addr == "127.0.0.1":
     import commands
     output = commands.getoutput("/sbin/ifconfig")
     addr = parseaddress(output)

次に、出力からIPアドレスを解析します。ifconfigはデフォルトでは通常のユーザーのPATHに含まれていないため、コマンドでフルパスを指定していることに注意してください。これがお役に立てば幸いです。


7

これはUnkwnTechの回答の変形です- get_local_addr()ホストのプライマリLAN IPアドレスを返す関数を提供します。これは、ipv6サポート、エラー処理、localhost / linklocal addrsの無視、およびTESTNET addr(rfc5737)を使用した接続に追加するため、投稿しています。

# imports
import errno
import socket
import logging

# localhost prefixes
_local_networks = ("127.", "0:0:0:0:0:0:0:1")

# ignore these prefixes -- localhost, unspecified, and link-local
_ignored_networks = _local_networks + ("0.", "0:0:0:0:0:0:0:0", "169.254.", "fe80:")

def detect_family(addr):
    if "." in addr:
        assert ":" not in addr
        return socket.AF_INET
    elif ":" in addr:
        return socket.AF_INET6
    else:
        raise ValueError("invalid ipv4/6 address: %r" % addr)

def expand_addr(addr):
    """convert address into canonical expanded form --
    no leading zeroes in groups, and for ipv6: lowercase hex, no collapsed groups.
    """
    family = detect_family(addr)
    addr = socket.inet_ntop(family, socket.inet_pton(family, addr))
    if "::" in addr:
        count = 8-addr.count(":")
        addr = addr.replace("::", (":0" * count) + ":")
        if addr.startswith(":"):
            addr = "0" + addr
    return addr

def _get_local_addr(family, remote):
    try:
        s = socket.socket(family, socket.SOCK_DGRAM)
        try:
            s.connect((remote, 9))
            return s.getsockname()[0]
        finally:
            s.close()
    except socket.error:
        # log.info("trapped error connecting to %r via %r", remote, family, exc_info=True)
        return None

def get_local_addr(remote=None, ipv6=True):
    """get LAN address of host

    :param remote:
        return  LAN address that host would use to access that specific remote address.
        by default, returns address it would use to access the public internet.

    :param ipv6:
        by default, attempts to find an ipv6 address first.
        if set to False, only checks ipv4.

    :returns:
        primary LAN address for host, or ``None`` if couldn't be determined.
    """
    if remote:
        family = detect_family(remote)
        local = _get_local_addr(family, remote)
        if not local:
            return None
        if family == socket.AF_INET6:
            # expand zero groups so the startswith() test works.
            local = expand_addr(local)
        if local.startswith(_local_networks):
            # border case where remote addr belongs to host
            return local
    else:
        # NOTE: the two addresses used here are TESTNET addresses,
        #       which should never exist in the real world.
        if ipv6:
            local = _get_local_addr(socket.AF_INET6, "2001:db8::1234")
            # expand zero groups so the startswith() test works.
            if local:
                local = expand_addr(local)
        else:
            local = None
        if not local:
            local = _get_local_addr(socket.AF_INET, "192.0.2.123")
            if not local:
                return None
    if local.startswith(_ignored_networks):
        return None
    return local

私はこれは本当に良い答えかもしれないと思った..しかしそれは常に戻るNone
ジェイミーリンジー

@JamieLindsey OS、ネットワーク構成について何か詳細はありますか?また、get_local_addr(remove="www.google.com")返品のようなものは何ですか?socket.error_get_local_addr()によってスローされたログを記録すると、診断に役立つ場合があります。
Eli Collins、

6
import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]

1
うーん... 2つのNICを備えたサーバーでは、これは割り当てられたIPアドレスの1つを与えますが、3回繰り返されます。私のラップトップでは '127.0.1.1'(3回繰り返されます...)...
bryn

['fe80::34e8:fe19:1459:2cde%22','fe80::d528:99fb:d572:e289%12', '192.168.56.1', '192.168.1.2']Windowsデスクトップで私を与えます。
ナキロン2014

5

これはほとんどのLinuxボックスで動作します:

import socket, subprocess, re
def get_ipv4_address():
    """
    Returns IP address(es) of current machine.
    :return:
    """
    p = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE)
    ifc_resp = p.communicate()
    patt = re.compile(r'inet\s*\w*\S*:\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
    resp = patt.findall(ifc_resp[0])
    print resp

get_ipv4_address()

5

この回答は、LAN IPを取得する問題を解決するための私の個人的な試みsocket.gethostbyname(socket.gethostname())です。これも127.0.0.1を返したためです。この方法では、LAN接続だけでインターネットは必要ありません。コードはPython 3.x用ですが、2.x用に簡単に変換できます。UDPブロードキャストの使用:

import select
import socket
import threading
from queue import Queue, Empty

def get_local_ip():
        def udp_listening_server():
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.bind(('<broadcast>', 8888))
            s.setblocking(0)
            while True:
                result = select.select([s],[],[])
                msg, address = result[0][0].recvfrom(1024)
                msg = str(msg, 'UTF-8')
                if msg == 'What is my LAN IP address?':
                    break
            queue.put(address)

        queue = Queue()
        thread = threading.Thread(target=udp_listening_server)
        thread.queue = queue
        thread.start()
        s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s2.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        waiting = True
        while waiting:
            s2.sendto(bytes('What is my LAN IP address?', 'UTF-8'), ('<broadcast>', 8888))
            try:
                address = queue.get(False)
            except Empty:
                pass
            else:
                waiting = False
        return address[0]

if __name__ == '__main__':
    print(get_local_ip())

1
これを同じネットワーク上の2つのマシンで同時に実行するとどうなりますか?ネットワーク上でメッセージをブロードキャストすると、すべてのマシンが「What is my LAN IP address。udp_listening_serverは、メッセージに「あなたのIPアドレスはxxxです」と返信できます。
Nicolas Defranoux、2015年

4

127.0.1.1 であるあなたの本当のIPアドレスが。より一般的に言えば、コンピューターは任意の数のIPアドレスを持つことができます。プライベートネットワーク(127.0.0.0/8、10.0.0.0/8、172.16.0.0/12、および192.168.0.0/16)をフィルターできます。

ただし、すべてのIPアドレスを取得するクロスプラットフォームの方法はありません。Linuxでは、SIOCGIFCONFioctl を使用できます。


2
彼は外部から見えるIPを意味します。127。*。*。*の範囲は通常、ローカルホストまたは内部ネットワークを指しますが、明らかに彼が望んでいるものではありません。
セリン

4

IPコマンドを使用し、IPv4アドレスとIPv6アドレスを返すコマンドバージョンのわずかな改良:

import commands,re,socket

#A generator that returns stripped lines of output from "ip address show"
iplines=(line.strip() for line in commands.getoutput("ip address show").split('\n'))

#Turn that into a list of IPv4 and IPv6 address/mask strings
addresses1=reduce(lambda a,v:a+v,(re.findall(r"inet ([\d.]+/\d+)",line)+re.findall(r"inet6 ([\:\da-f]+/\d+)",line) for line in iplines))
#addresses1 now looks like ['127.0.0.1/8', '::1/128', '10.160.114.60/23', 'fe80::1031:3fff:fe00:6dce/64']

#Get a list of IPv4 addresses as (IPstring,subnetsize) tuples
ipv4s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if '.' in addr)]
#ipv4s now looks like [('127.0.0.1', 8), ('10.160.114.60', 23)]

#Get IPv6 addresses
ipv6s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if ':' in addr)]

4

GNU / Linuxでコマンド「ip route」を使用して、現在のIPアドレスを知ることができます。

これは、ルーター/モデムで実行されているDHCPサーバーによってインターフェイスに与えられたIPを示しています。通常、「192.168.1.1/24」はローカルネットワークのIPです。「24」は、DHCPサーバーによってマスク範囲内で指定される可能なIPアドレスの範囲を意味します。

ここに例があります:PyNotifyは私のポイントをまっすぐにするための追加であり、まったく必要ないことに注意してください

#! /usr/bin/env python

import sys , pynotify

if sys.version_info[1] != 7:
   raise RuntimeError('Python 2.7 And Above Only')       

from subprocess import check_output # Available on Python 2.7+ | N/A 

IP = check_output(['ip', 'route'])
Split_Result = IP.split()

# print Split_Result[2] # Remove "#" to enable

pynotify.init("image")
notify = pynotify.Notification("Ip", "Server Running At:" + Split_Result[2] , "/home/User/wireless.png")    
notify.show()    

これの利点は、ネットワークインターフェイスを指定する必要がないことです。これは、ソケットサーバーを実行するときに非常に便利です。

easy_installまたはPipを使用してPyNotifyをインストールできます。

easy_install py-notify

または

pip install py-notify

またはpythonスクリプト/インタープリター内

from pip import main

main(['install', 'py-notify'])

4

localhostのIPアドレス127.0.0.1とは異なるIPV4アドレスを探している場合は、次のPythonコードを使用すると便利です。

import subprocess
address = subprocess.check_output(['hostname', '-s', '-I'])
address = address.decode('utf-8') 
address=address[:-1]

これも1行で記述できます。

address = subprocess.check_output(['hostname', '-s', '-I']).decode('utf-8')[:-1]

あなたが入れたとしてもlocalhost/etc/hostname、コードはまだあなたのローカルIPアドレスを与えます。


4

Linuxの場合、あなただけ使用することができますcheck_outputhostname -Iようにのようなシステムコマンド:

from subprocess import check_output
check_output(['hostname', '-I'])

グーグルにとって、問題はクロスプラットフォームソリューションに関するものでした
Kasper Skytte Andersen


3

netifacesは、pipとeasy_installを介して利用できます。(私は知っています、それはベースにはありませんが、インストールする価値があるかもしれません。)

netifacesには、プラットフォーム間でいくつかの奇妙な点があります。

  • localhost / loop-backインターフェースは常に含まれているとは限りません(Cygwin)。
  • アドレスはプロトコル(IPv4、IPv6など)ごとにリストされ、プロトコルはインターフェースごとにリストされます。一部のシステム(Linux)では、各プロトコルとインターフェースのペアに独自の関連インターフェース(interface_name:n表記を使用)がありますが、他のシステム(Windows)では、単一のインターフェースに各プロトコルのアドレスのリストがあります。どちらの場合もプロトコルリストがありますが、1つの要素しか含まれていない場合があります。

ここでいくつかのnetifacesコードを操作します:

import netifaces

PROTO = netifaces.AF_INET   # We want only IPv4, for now at least

# Get list of network interfaces
# Note: Can't filter for 'lo' here because Windows lacks it.
ifaces = netifaces.interfaces()

# Get all addresses (of all kinds) for each interface
if_addrs = [netifaces.ifaddresses(iface) for iface in ifaces]

# Filter for the desired address type
if_inet_addrs = [addr[PROTO] for addr in if_addrs if PROTO in addr]

iface_addrs = [s['addr'] for a in if_inet_addrs for s in a if 'addr' in s]
# Can filter for '127.0.0.1' here.

上記のコードは、アドレスをそのインターフェース名にマッピングしません(ebtables / iptablesルールをその場で生成するのに役立ちます)。したがって、上記の情報とタプルのインターフェイス名を保持するバージョンは次のとおりです。

import netifaces

PROTO = netifaces.AF_INET   # We want only IPv4, for now at least

# Get list of network interfaces
ifaces = netifaces.interfaces()

# Get addresses for each interface
if_addrs = [(netifaces.ifaddresses(iface), iface) for iface in ifaces]

# Filter for only IPv4 addresses
if_inet_addrs = [(tup[0][PROTO], tup[1]) for tup in if_addrs if PROTO in tup[0]]

iface_addrs = [(s['addr'], tup[1]) for tup in if_inet_addrs for s in tup[0] if 'addr' in s]

そして、いいえ、私はリスト内包表記に夢中です。最近の私の脳の働きです。

次のスニペットはそれをすべて出力します:

from __future__ import print_function  # For 2.x folks
from pprint import pprint as pp

print('\nifaces = ', end='')
pp(ifaces)

print('\nif_addrs = ', end='')
pp(if_addrs)

print('\nif_inet_addrs = ', end='')
pp(if_inet_addrs)

print('\niface_addrs = ', end='')
pp(iface_addrs)

楽しい!


netifacesは、この問題に対処している間、本当に生活をとても楽にします。
Drake Guan、

3

新しく導入されたasyncioパッケージを利用したPython 3.4バージョン。

async get_local_ip():
    loop = asyncio.get_event_loop()
    transport, protocol = await loop.create_datagram_endpoint(
        asyncio.DatagramProtocol,
        remote_addr=('8.8.8.8', 80))
    result = transport.get_extra_info('sockname')[0])
    transport.close()
    return result

これはUnkwnTechの優れた回答に基づいています


3

IPアドレスを取得するには、Pythonで直接シェルコマンドを使用できます。

import socket, subprocess

def getIpAndHostname():
    hostname =  socket.gethostname()

    shell_cmd = "ifconfig | awk '/inet addr/{print substr($2,6)}'"
    proc = subprocess.Popen([shell_cmd], stdout=subprocess.PIPE, shell=True)
    (out, err) = proc.communicate()

    ip_list = out.split('\n')
    ip = ip_list[0]

    for _ip in ip_list:
        try:
            if _ip != "127.0.0.1" and _ip.split(".")[3] != "1":
                ip = _ip
        except:
            pass
    return ip, hostname

ip_addr, hostname = getIpAndHostname()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.