WHOIS представляет собой сетевой протокол прикладного уровня, базирующийся на протоколе TCP (и использующий порт 43). По бо́льшей части применяется для получения регистрационных данных о доменных именах: дате регистрации домена, информации о владельце, регистраторе и прочем.
В unix-like системах есть одноимённая утилита, позволяющая быстро получить искомые сведения. В частности для пользователей gentoo linux процесс её установки будет выглядеть следующим образом:
$ eix whois
* net-misc/whois
Available versions: 5.0.11^t {iconv idn nls}
Homepage: http://www.linux.it/~md/software/
Description: improved Whois Client
# emerge -pav net-misc/whois
Тем, кому любопытно сделать свой вариант клиента whois, посвящается этот пост. Для написания подобной вещи предлагается использовать python3.
Для начала нужно импортировать необходимые модули и сделать проверку установленной версии python, поскольку во второй и третьей версии различаются некоторые типы данных:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket, sys
# если версия python ниже 3
# вывести сообщение и закрыть программу
if sys.version < '3.0':
print("You need install python3")
sys.exit()
Дальше следует функция, которая будет отправлять запрос на сервер и принимать ответ. Здесь используется модуль socket. Он предоставляет доступ к стандартному интерфейсу сокетов BSD (изначально разрабатывался для UNIX).
Модуль socket является низкоуровневым и в ряде случаев проще использовать функции из пакета urllib.
При работе с socket часто требуется указать семейство адресов и тип сокета. Для нашей небольшой программы важен протокол IPv4 (AF_INET). Типы сокетов представлены в таблице:
константа | описание |
---|---|
SOCK_STREAM | поток байтов, обеспечивающий надёжность передачи данных (TCP) |
SOCK_DGRAM | дейтаграммы (UDP) |
SOCK_RAW | простой сокет |
SOCK_RDM | дейтаграммы с надёжной доставкой |
Для интернет-приложений, использующих IPv4, адреса определяются в виде кортежа (host, port):
('www.yandex.ru', 80)
В блоке кода, представленном ниже, мы воспользуе мся этим, чтобы соединиться с сервером. Для создания нового сокета понадобится употребить одну из функций модуля socket с таким же названием: socket.
socket(family, type [, proto])
где
- family — определяет семейство адресов;
- type — тип сокета;
- proto — аргумент с именем протокола (обычно не передаётся).
Сокеты представлены экземплярами класса SocketType и обладают следующими методами:
метод | описание |
---|---|
connect | устанавливает соединение с удалённым узлом |
recv | принимает данные из сокета (макс. объём данных определяется аргументом bufsize) |
send | посылает данные через сетевое соединение, возвращает кол-во отправленных данных |
close | закрывает соединение |
Исходя из сказанного выше, читателю должен быть понятен следующий блок кода:
def run_whois(server, query):
# создать TCP-socket (IPv4)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# соединиться с сервером ('host', port)
s.connect((server , 43))
# отправить запрос на сервер
# s.send(query + '\r\n') # для python2
s.send((bytes(query, 'utf-8')) + b'\r\n')
msg = ''
while len(msg) < 10000:
# получить данные от сервера
# receive_data = s.recv(100) # для python2
receive_data = str((s.recv(100)), encoding='utf-8')
if (receive_data == ''):
break;
msg = msg + receive_data
return msg
Следующая функция позволит получить данные от сервера whois-регистратора и обработать их.
def get_data(domain): # получить объект(имя домена)
# если введено http или www
# перед именем домена, убрать их
domain = domain.replace('http://', '')
domain = domain.replace('www.', '')
# получить доменную зону
ext = domain[-3:].split('.')[-1]
# обращаться к соответствующему whois-серверу зоны
if (ext == 'org'):
whois = 'whois.pir.org'
elif (ext == 'ru' or ext == 'su'):
whois = 'whois.tcinet.ru'
else:
whois = 'whois.iana.org' # сообщение для иных доменных зон
# получить ответ от регистратора
# (whois-server, имя домена)
msg = run_whois(whois, domain)
lines = msg.splitlines() # разбиваем текст на сроки
for line in lines: # итерация по строкам
if ':' in line: # если есть знак :
words = line.split(':') # разделить по нему строку
return msg
И последнее: имя домена будет получено из агрумента командной строки при запуске программы. Оно передаётся функции get_data, и данные выводятся на экран.
try:
domain_name = sys.argv[1] # получить доменное имя из аргумента командной строки
print(get_data(domain_name)) # передать доменное имя функции get_data
except IndexError: # если программа запущена без аргумента
print("enter domain name as a value!")
Данная программка не претендует на многое, но цели своей достигает; заодно знакомит потенциального читателя с частью такой огромной темы как работа с сетью и сокетами, а автору служит главным образом примером и напоминанием о различиях в обработке данных в разных версиях python'а.