Престижность должна пойти , чтобы узнать его ответ .Однако я не хотел искажать его ответ моими дополнениями, которые, кажется, несколько длиннее, чем его полный ответ.Поэтому, пожалуйста, смотрите этот ответ как дополнение к его ответу.
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)