Как определить IP-адрес сервера после соединения с urllib2? - PullRequest
3 голосов
/ 19 января 2012

Я загружаю данные с сервера, используя 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 ]

5 голосов
/ 07 февраля 2015

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

>>> from urllib2 import urlopen
>>> from socket import fromfd
>>> from socket import AF_INET
>>> from socket import SOCK_STREAM
>>> r = urlopen('http://stackoverflow.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
3 голосов
/ 19 марта 2014

Я знаю, что это старый вопрос, но я обнаружил, что объект ответа, возвращаемый 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()
3 голосов
/ 19 января 2012
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 на некоторое время оставить соединение открытым, чтобы это удалось.Это, похоже, требует больше работы, чем стоит.

1 голос
/ 05 ноября 2014

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

Caveat emptor

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

try: import urllib.request as urllib2, за исключением ImportError: import 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() в ctor httplib.HTTPResponse
  • атрибут _sock (r.fp._sock) - это экземпляр "сокета" , переданный class socket._fileobject ctor, он будет иметь атрибут
  • 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://stackoverflow.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()))

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

HTTP Error 404: Not Found: https://stackoverflow.com/doesnotexist/url
        IP and port: 198.252.206.16:80
        peer = ('198.252.206.16', 80)
...