Как определить IP-адрес сервера после соединения с urllib2?

Я загружаю данные с сервера, используя urllib2. Но мне нужно определить IP-адрес сервера, к которому я подключен.

import urllib2
STD_HEADERS = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,
                    */*;q=0.8',
                'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
                'Accept-Language': 'en-us,en;q=0.5',
                'User-Agent': 'Mozilla/5.0 (X11; U; Linux x86_64;en-US;rv:1.9.2.12)     
                           Gecko/20101028 Firefox/3.6.12'}
request = urllib2.Request(url, None, STD_HEADERS)
data =  urllib2.urlopen(request)

Пожалуйста, не просите меня найти IP-адрес, используя URL-адрес, так как это не гарантирует, что сервер, с которого загружаются данные, и запрос IP-адреса разрешаются на тот же IP-адрес в случае HTTPRedirects или сервера балансировки нагрузки.

4 ответа

Решение
import urllib2, socket, urlparse

# set up your request as before, then:
data = urllib2.urlopen(request)
addr = socket.gethostbyname(urlparse.urlparse(data.geturl()).hostname)

data.geturl() возвращает URL, который использовался для фактического получения ресурса, после любых перенаправлений. Имя хоста затем вылавливается urlparse и передал socket.gethostbyname получить IP-адрес.

Некоторые хосты могут иметь более одного IP-адреса для данного имени хоста, поэтому все еще возможно, что запрос был выполнен другим сервером, но это так близко, как вы собираетесь получить. gethostbyname сразу после того, как URL-запрос будет использовать ваш DNS-кэш в любом случае, и если вы не имеете дело с временем жизни, например, 1 секунду, вы получите тот же сервер, который вы только что использовали.

Если этого недостаточно, вы можете раскрутить поток и сделать lsof пока все еще подключен к удаленному серверу. Я уверен, что вы могли бы убедить urllib2 оставить соединение открытым на некоторое время, чтобы это было успешно. Похоже, это больше, чем стоит.

Вот что работает для меня на Python 2.7:

>>> from urllib2 import urlopen
>>> from socket import fromfd
>>> from socket import AF_INET
>>> from socket import SOCK_STREAM
>>> r = urlopen('http://stackru.com/')
>>> mysockno = r.fileno()
>>> mysock = fromfd( mysockno, AF_INET, SOCK_STREAM)
>>> (ip, port) = mysock.getpeername()
>>> print "got IP %s port %d" % (ip, port)
got IP 198.252.206.140 port 80

Я знаю, что это старый вопрос, но я обнаружил, что объект ответа, возвращаемый urllib2, содержит ip. Это немного похоже на взломать, но это работает.

import urllib2
STD_HEADERS = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,
                    */*;q=0.8',
                'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
                'Accept-Language': 'en-us,en;q=0.5',
                'User-Agent': 'Mozilla/5.0 (X11; U; Linux x86_64;en-US;rv:1.9.2.12)     
                           Gecko/20101028 Firefox/3.6.12'}
request = urllib2.Request(url, None, STD_HEADERS)
data =  urllib2.urlopen(request)

data.fp._sock.fp._sock.getpeername()

Престижность должна пойти в Гаври за его ответ. Однако я не хотел искажать его ответ моими дополнениями, которые, кажется, несколько длиннее, чем его полный ответ. Поэтому, пожалуйста, смотрите этот ответ как дополнение к его ответу.

Пусть покупатель будет бдителен

Это будет работать только на Python 2.x сurllib2 , Структура классов изменилась в Python 3.x, поэтому даже случайный прием совместимости:

try: импортировать urllib.request как urllib2, за исключением ImportError: импортировать urllib2

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

Вывод: следующий трюк ниже не работает на Python 3.x.

Извлечение IP: порт изHTTPResponse

Вот сокращенная версия его ответа:

import urllib2
r =  urllib2.urlopen("http://google.com")
peer = r.fp._sock.fp._sock.getpeername()
print("%s connected\n\tIP and port: %s:%d\n\tpeer = %r" % (r.geturl(), peer[0], peer[1], peer))

Вывод будет примерно такой (урезанныйeiпараметр по соображениям конфиденциальности):

http://www.google.co.jp/?gfe_rd=cr&ei=_... connected
        IP and port: 173.194.120.95:80
        peer = ('173.194.120.95', 80)

Если предположить,rвыше этоhttplib.HTTPResponseНапример, мы делаем следующие дополнительные предположения:

  • его атрибут fp(r.fp) является примером class sock._fileobject, созданный с помощьюsock.makefile()в центреhttplib.HTTPResponse
  • атрибут _sock(r.fp._sock) это экземпляр "сокета", переданныйclass socket._fileobjectctor, это будет типа
  • атрибут fp (r.fp._sock.fp) Другойsocket._filetypeкоторый оборачивает настоящую розетку
  • атрибут _sock(r.fp._sock.fp._sock) является реальным объектом сокета

грубо r.fp это socket._fileobject, в то время как r.fp._sock.fp._sock фактический экземпляр сокета (тип _socket.socket) завернутый в socket._fileobject обертывание другогоsocket._fileobject(два уровня глубиной). Вот почему у нас это несколько необычно.fp._sock.fp._sock.в середине.

Переменная, возвращаемаяgetpeername() выше кортеж для IPv4. Элемент 0 - это IP в виде строки, а элемент 1 - это порт, к которому было установлено соединение с этим IP. Примечание. В документации говорится, что этот формат зависит от фактического типа сокета.

Извлечение этой информации из HTTPError

С другой стороны, так как urllib2.HTTPError происходит от URLError так же как addinfourl и хранит fp в атрибуте с тем же именем, мы можем даже извлечь эту информацию из HTTPError исключение (не из URLErrorправда) добавив еще fp к смеси, как это:

import urllib2
try:
    r =  urllib2.urlopen("https://stackru.com/doesnotexist/url")
    peer = r.fp._sock.fp._sock.getpeername()
    print("%s connected\n\tIP and port: %s:%d\n\tpeer = %r" % (r.geturl(), peer[0], peer[1], peer))
except urllib2.HTTPError, e:
    if e.fp is not None:
        peer = e.fp.fp._sock.fp._sock.getpeername()
        print("%s: %s\n\tIP and port: %s:%d\n\tpeer = %r" % (str(e), e.geturl(), peer[0], peer[1], peer))
    else:
        print("%s: %s\n\tIP and port: <could not be retrieved>" % (str(e), e.geturl()))

Вывод будет примерно таким (если кто-то из Stackru не добавит этот URL;)):

HTTP Error 404: Not Found: https://stackru.com/doesnotexist/url
        IP and port: 198.252.206.16:80
        peer = ('198.252.206.16', 80)
Другие вопросы по тегам