mirror of
https://github.com/Ground-Zerro/DomainMapper.git
synced 2025-12-10 01:47:18 +07:00
Многопоточность убрана. Сайт критически воспринимает множественные обращения от одного хоста и начинает выдавать страницы с пустыми субдоменами.
110 lines
5.1 KiB
Python
110 lines
5.1 KiB
Python
import random
|
||
import time
|
||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||
|
||
import requests
|
||
from bs4 import BeautifulSoup
|
||
|
||
|
||
def parse_page(url):
|
||
for attempt in range(5): # До 5 попыток для одной страницы
|
||
try:
|
||
response = requests.get(url)
|
||
if response.status_code == 404: # Проверка на несуществующую страницу
|
||
return None
|
||
response.raise_for_status()
|
||
|
||
soup = BeautifulSoup(response.text, 'html.parser')
|
||
data = set() # Используем множество для уникальных доменов
|
||
rows = soup.select('table tbody tr')
|
||
|
||
if not rows: # Если на странице нет строк, возвращаем None
|
||
return None
|
||
|
||
for row in rows:
|
||
columns = row.find_all('td')
|
||
if len(columns) > 3 and columns[2].text.strip() == 'A': # Проверка на тип записи 'A'
|
||
domain = columns[0].text.strip() # Извлечение столбца 'Domain'
|
||
data.add(domain) # Добавляем в множество
|
||
|
||
time.sleep(random.choice([2, 3, 4, 5])) # Случайная задержка между запросами
|
||
|
||
if attempt > 0:
|
||
print(f"Успешная загрузка {url} после {attempt}-й попытки.")
|
||
return data
|
||
|
||
except requests.exceptions.HTTPError as e:
|
||
if response.status_code == 429:
|
||
print(f"Ошибка загрузки {url}. Пробуем еще раз... (Попытка {attempt + 1})")
|
||
time.sleep(5) # Фиксированная задержка перед повторной попыткой
|
||
else:
|
||
raise e
|
||
|
||
|
||
def parse_all_pages(base_url):
|
||
all_domains = set() # Используем множество для уникальных доменов
|
||
page = 1 # Всегда начинаем с первой страницы
|
||
keep_parsing = True
|
||
|
||
empty_page_attempts = 0 # Счётчик пустых страниц
|
||
recent_pages_data = [] # Список для хранения данных последних страниц
|
||
|
||
while keep_parsing:
|
||
print(f"Парсим страницу {page}")
|
||
url = f"{base_url}?page={page}"
|
||
|
||
try:
|
||
result = parse_page(url)
|
||
if result is None: # Если страница пуста или не существует
|
||
print(f"Страница {page} не существует или пуста. Проверяем еще раз...")
|
||
empty_page_attempts += 1
|
||
time.sleep(5) # Ожидание перед повторной проверкой
|
||
if empty_page_attempts >= 3:
|
||
print(f"Страница {page} пуста после 3 попыток. Остановка.")
|
||
keep_parsing = False
|
||
break
|
||
else:
|
||
continue # Переходим к следующей попытке
|
||
else:
|
||
empty_page_attempts = 0 # Обнуляем счётчик, если нашли данные
|
||
all_domains.update(result) # Добавляем новые домены в множество
|
||
print(f"Разбор страницы {page} завершен.")
|
||
|
||
# Добавляем данные страницы в список для сравнения
|
||
recent_pages_data.append(result)
|
||
if len(recent_pages_data) > 3: # Храним данные только последних 3 страниц
|
||
recent_pages_data.pop(0)
|
||
|
||
# Проверяем, повторяются ли данные на последних трёх страницах
|
||
if len(recent_pages_data) == 3 and recent_pages_data[0] == recent_pages_data[1] == recent_pages_data[2]:
|
||
print(f"Данные на последних трёх страницах одинаковы. Остановка парсинга.")
|
||
keep_parsing = False
|
||
break
|
||
|
||
except Exception as e:
|
||
print(f"Ошибка парсинга страницы {page}: {e}")
|
||
raise e
|
||
|
||
page += 1 # Переход к следующей странице
|
||
|
||
return all_domains
|
||
|
||
|
||
def get_subdomain_url():
|
||
base_url = 'https://rapiddns.io/subdomain/{url}'
|
||
url = input("Введите URL: ")
|
||
full_url = base_url.format(url=url)
|
||
return full_url # Возвращаем полный URL
|
||
|
||
|
||
base_url = get_subdomain_url() # Вызов функции для получения полного URL
|
||
|
||
domains = parse_all_pages(base_url)
|
||
|
||
# Запись результата в файл
|
||
with open('result.txt', 'w') as file:
|
||
for domain in sorted(domains): # Сортируем домены перед записью
|
||
file.write(f"{domain}\n")
|
||
|
||
print(f"Найдено {len(domains)} A записей. \nРезультаты сохранены в result.txt.")
|