Основи Python и Django. / Практикум. Створюємо телеграм бота. / Перевіряємо домени, що закінчуються.

Перевіряємо домени з терміном, що закінчується.

Нещодавно від “насельника” мені надійшло таке завдання:

“Дімич скажи пож ось звідси - https://www.reg.ru/domain/deleted/? Чи можна пограбувати назви доменів?”

Я зайшов за посиланням, побачив список доменів, у яких закінчується термін, посторінкову навігацію та всі справи.

start page

Я подумав “Чому б і ні?” буду пробігати по сторінці, змінюючи параметр page=1,2,3 в урлі, парсить сторінки і зберігати домени.

Що може бути простішим?

Потім надійшло доповнення до завдання. Як виявилося, ці домени потрібно перевіряти на присутність на одному сайті, скажімо yandex.ru:

Наприклад, ось так:

https://yandex.ru/sabai.tv

Куди замість sabai.tv підставляти мої пограбовані доменчики.

З цим начебто проблем бути не повинно. Тим більше, що за відсутності домену в цьому інтернет-каталозі, він повертає 404 помилки.

start page

Прийдеться трохи заддосить напружити цей сайт.

Тож поїхали.

Мені знадобляться дві пітонівські бібліотеки:

requests - для створення HTTP GET запитів

beautifulsoup4 - для парсингу HTML та пошуку корисної інформації на сторінці.

Все це добро складемо у віртуальне оточення.

Створюю та активую його.

mkdir finedomain
cd finedomain
virtualenv venv
source ./venv/bin/activate

Ставлю пакунки.

pip install requests beautifulsoup4

Пишу код із запитом у файлі grabing.py.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Імпортуємо все що треба для роботи import requests from bs4 import BeautifulSoup import json import time import sys # початок програми print(‘Start’) # визначаю рядок з урлом # до неї з кінця приліплюватиму сторінки url = ‘https://www.reg.ru/domain/deleted/?&free_from=12.06.2019&free_to=12.06.2019&order=ASC&sort_field=dname_idn%20%20%20%20&page=’

# запит першої сторінки
r = requests.get(url+'0')
print(r.text)

Результат.

python requests

Непогано, HTML отримали, далі потрібно розпарити це все добро beautifulsoup-ом.

soup = BeautifulSoup(r.text, 'html.parser')

Тепер у змінній soup у нас не тільки весь код сторінки, але й інструменти для пошуку її елементів.

Відкидаємо інспектор браузера і дивимося, де у нас список.

python requests

Ага, таблиця з класом b-table__content. Немає нічого простішого її витягнути так.
table = soup.find(“table”,{“class”: “b-table__content”})

find() - шукає один елемент findAll() - знайде список

Далі отримаю tr-ки (рядки) з тега tbody.

tbody = table.find("tbody")
trs = tbody.findAll("tr")

Втечу за ними циклом, знайду td-шки (комірки таблиці) і виведу з першої за рахунком доменне ім’я.

soup = BeautifulSoup(r.text, 'html.parser')
table = soup.find("table",{"class": "b-table__content"})
tbody = table.find("tbody")
trs = tbody.findAll("tr")
for tr in trs:
    tds = tr.findAll("td")
    print(tds[0].text)

Спрацювало!

python requests

Тепер створимо список для зберігання доменів та дати закінчення, і в циклі заповню його.

Повний код вийшов таким.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Імпортуємо все що треба для роботи
import requests
from bs4 import BeautifulSoup
import json
import time
# початок програми
print('Start')
# визначаю рядок з урлом
 # до неї з кінця приліплюватиму сторінки
url = 'https://www.reg.ru/domain/deleted/?&free_from=12.06.2019&free_to=12.06.2019&order=ASC&sort_field=dname_idn%20%20%20%20&page='

# запит першої сторінки
 r = requests.get(url+'0')

 # тут зберігатиму домени
data = []

# парсим html
soup = BeautifulSoup(r.text, 'html.parser')

# знаходимо першу таблицю за тегом та css класом
 table = soup.find("table",{"class": "b-table__content"})

 # в ній блок tbody на ім'я тега
 tbody = table.find("tbody")

 # рядки
trs = tbody.findAll("tr")
for tr in trs:
    # осередки
     tds = tr.findAll("td")
     # додаємо домен та термін закінчення до списку
    data.append({"domain": tds[0].text, "date_expire": tds[2].text})

print(data)

python requests

Час перевірити ці домени на сайті.

Зроблю при цьому функцію, яка приймає доменне ім’я параметром.

def check_domain(domain):
    # формую url, адресу підставляючи домен у рядок
     url = 'https://yandex.ru/%s' %domain
     # пробую зробити запит
     try:
         # отримую сторінку
        r = requests.get(url)
        if r.status_code == 404: # перевіряю статус
             print('Domain %s result %s' % (domain, 'FAIL!'))
             return False
         else:
             print('Domain %s result %s' % (domain, 'SUCCESS'))
             # якщо пощастило і домен знайшли
             return True
     # це якщо запит обрушився з якоїсь причини       
    except:
        print('Request error %s' % url)
        return False

Залишилось викликати цю функцію у циклі.

for tr in trs:
    # ячейки
    tds = tr.findAll("td")
    # додаємо домен та термін закінчення до списку
     data.append({"domain": tds[0].text, "date_expire": tds[2].text})
     # перевіряю домен
    check_domain(tds[0].text)

python requests

Результат не втішає і попадань на першій сторінці немає, проте працює!

Тепер мені потрібно визначити кінець посторінкової “нафігації” та прогнати процес по всіх доменах на зазначену дату.

У найкращих традиціях функціонального програмування виконую функцію.

def check_end(soup):
'''Визначаю кінець сторінки '''
     try:
         # на кінцевій сторінці було помічено заголовок h1 з текстом
         '''
                 Доменів, що відповідають заданим критеріям фільтрації, не знайдено.
         '''
         h2 = soup.find("h2")
         # тут для пошуку сказало, що потрібно спочатку кодувати в UTF-8
         if h2.text.encode('utf-8').find('відповідають заданим критеріям')>0:
             return True
        else:
            return False
    except:
        return False

Мучу цикл while доки дійшло остаточно з лічильником сторінок.

is_end = False
page = 0
while not is_end:
    # визначаю рядок з урлом
     # до неї з кінця приліплюватиму сторінки
     url = 'https://www.reg.ru/domain/deleted/?&free_from=12.06.2019&free_to=12.06.2019&order=ASC&sort_field=dname_idn%20%20%20%20&page=%s' % page
     print("Роблю сторінку %s" % page)
     # додаємо лічильник сторінок
     page = page + 1

   запит першої сторінки
     r = requests.get(url)

     # тут зберігатиму домени
     data = []

    # парсим html
    soup = BeautifulSoup(r.text, 'html.parser')

   # Парсим html
     soup = BeautifulSoup(r.text, 'html.parser')

     # перевіримо кінець постранички
     if check_end(soup):
         is_end = True
         break # ламаємо цикл


    # знаходимо першу таблицю за тегом та css класом
     table = soup.find("table",{"class": "b-table__content"})

     # в ній блок tbody на ім'я тега
     tbody = table.find("tbody")

    # рядки
     trs = tbody.findAll("tr")
     for tr in trs:
         # осередки
         tds = tr.findAll("td")
         # додаємо домен та термін закінчення до списку
         data.append({"domain": tds[0].text, "date_expire": tds[2].text})
         # перевіряю домен 
        check_domain(tds[0].text)

python requests

Вирішив перервати процес ctrl+c, отримав такий облом

python requests

Довелося гасити термінал, образливе непорозуміння.

Сталося воно у цьому блоці під час перевірки домену:

except:
    print('Request error %s' % url)
    return False

А якщо я відпрацюю виняток KeyboardInterrupt?

 try:
     # отримую сторінку
     ...
 except KeyboardInterrupt: # вихід ctrl+c
     print("Ну поки що!")
     sys.exit() # нахабно вивалюється з проги
 # це якщо запит обрушився з якоїсь іншої причини        
except:
    print('Request error %s' % url)
    return False

python requests

Набагато краще!

Залишилося забрати дату у користувача десь на початку скрипту.

print("Введи дату типу 12.06.2019: ")
 user_date = raw_input() #
 print("Працюємо по {}".format(user_date))

Просто input() не канає! Використовуйте тільки raw_input.

І вставити її до урла запиту.

Наприкінці я вивантажу успішні домени у файл.

def save_success(domain):
    with open('success.txt', 'a+') as of: # открываем для добавления и создаем если нет
        of.write(domain+';')
        print('Domain %s result %s' % (domain, 'SUCCESS'))

Повний код програми..

#!/usr/bin/env python
# -*- coding: utf-8 -*-

Імпортуємо все що треба для роботи import requests from bs4 import BeautifulSoup import json import time import sys # початок програми print(‘Починаємо грабувати домени.’) print(“Вводь за яку дату? (типу 12.06.2019): “) user_date = raw_input() print(“Працюємо по {}”.format(user_date))

def save_success(domain):
    with open('success.txt', 'a+') as of: # відкриваємо для додавання і створюємо якщо ні
         of.write(domain+';')
         print('Domain %s result %s' % (domain, 'SUCCESS'))

def check_domain(domain):
    # формую url, адресу підставляючи домен у рядок
     url = 'https://yandex.ru/%s' %domain
     # пробую зробити запит
    try:
        # отримую сторінку
         r = requests.get(url)
         if r.status_code == 404: # перевіряю статус
            print('Domain %s result %s' % (domain, 'FAIL!'))
            return False
        else:
            print('Domain %s result %s' % (domain, 'SUCCESS'))
           # якщо пощастило і домен знайшли
             return True
     except KeyboardInterrupt: # вихід ctrl+c
         print("Ну поки що!")
        sys.exit() # нагло вываливаемся из проги
    # це якщо запит обрушився з якоїсь причини
     except:
         print('Request error %s' % url)
         return False

 def check_end(soup):
     ''' Визначаю кінець посторінки ''
    try:
       # на кінцевій сторінці було помічено заголовок h1 з текстом
         '''
                 Доменів, що відповідають заданим критеріям фільтрації, не знайдено.
         '''
         h2 = soup.find("h2")
         # тут для пошуку сказало, що потрібно спочатку кодувати в UTF-8
         if h2.text.encode('utf-8').find('відповідають заданим критеріям')>0:
             return True
        else:
            return False
    except:
        return False

is_end = False
page = 0
while not is_end:
    # визначаю рядок з урлом
     # до неї з кінця приліплюватиму сторінки
     url = 'https://www.reg.ru/domain/deleted/?&free_from=%s&free_to=%s&order=ASC&sort_field=dname_idn%20%20%20%20&page=%s' % (user_date,user_date,page)
     print("Роблю сторінку %s" % page)
     # додаємо лічильник сторінок
     page = page + 1

    # запит першої сторінки
     r = requests.get(url)

     # тут зберігатиму домени
     data = []

     # Парсим html
     soup = BeautifulSoup(r.text, 'html.parser')

     # перевіримо кінець постранички
     if check_end(soup):
         is_end = True
         break # ламаємо цикл


    знаходимо першу таблицю за тегом та css класом
     table = soup.find("table",{"class": "b-table__content"})

     # в ній блок tbody на ім'я тега
     tbody = table.find("tbody")

   # рядки
     trs = tbody.findAll("tr")
     for tr in trs:
         # осередки
         tds = tr.findAll("td")
         # додаємо домен та термін закінчення до списку
         data.append({"domain": tds[0].text, "date_expire": tds[2].text})
         # перевіряю домен
         if check_domain(tds[0].text):
             save_success(tds[0].text)

print('The end')

Висновки.

У статті висвітлено прийоми програмування мовою Python на прикладі реального, практичного завдання.

Викладено основні функції Python бібліотек requests та BeautifulSoup для отримання вмісту сторінки , пошуку та вилучення з неї корисної інформації зі збереженням у текстовий файл.GIT](https://github.com/zdimon/finedomain)