Как определить 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._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://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)