Представьте: на сайте сотни страниц с внешними ссылками. Через месяц после последнего аудита одна из ссылок перестала работать — ресурс удалили. Вы теряете позиции в поиске из-за битых ссылок (404 ошибок), а пользователи уходят с неработающей страницы. По данным Moz, более 30% пользователей покидают сайт при встрече с неработающей ссылкой. Каждая 404-ошибка — сигнал о низком качестве сайта для поисковых систем. Мы решаем эту проблему: настраиваем автоматическое сканирование всех ссылок по расписанию с уведомлениями о найденных ошибках. Вы получаете отчёт до того, как проблема повлияет на SEO или UX.
Почему битые ссылки вредят SEO?
Поисковые системы Google и Яндекс учитывают наличие неработающих ссылок при ранжировании. Каждая 404-ошибка — сигнал о низком качестве сайта. Особенно критичны битые ссылки в меню, футере и на целевых страницах — они напрямую влияют на поведенческие факторы. Автоматический мониторинг позволяет выявить проблему за минуты, а не дни. Google Search Console фиксирует 404-ошибки с задержкой, наш подход даёт актуальные данные в реальном времени. По нашим данным, своевременное обнаружение битых ссылок снижает показатель отказов на 15%.
Как работает автоматическая проверка?
Мы используем асинхронный краулер на Python с библиотекой aiohttp. Он параллельно обрабатывает до 20 ссылок, проверяя HTTP-статус каждой. При обнаружении ошибки (4xx, 5xx, таймаут) ссылка фиксируется с указанием реферера. После завершения сканирования формируется отчёт с полным списком битых линков и отправляется в выбранный канал (Slack, Telegram, email). Мы настраиваем уведомления так, чтобы вы получали ежедневный отчёт с краткой сводкой и ссылкой на полный CSV. Для сайта из 5000 страниц полное сканирование занимает около часа.
Пошаговый процесс настройки:
- Устанавливаем Python-окружение и зависимости (aiohttp, BeautifulSoup, Celery).
- Конфигурируем краулер: задаём стартовый URL, ограничения по домену, таймауты.
- Настраиваем планировщик Celery Beat для ежедневного запуска.
- Интегрируем уведомления в Slack или Telegram.
- Тестируем сценарий на тестовом стенде.
Техническая реализация
# broken_link_checker.py
import asyncio
import aiohttp
from urllib.parse import urlparse, urljoin
from bs4 import BeautifulSoup
from collections import defaultdict
class BrokenLinkChecker:
def __init__(self, base_url: str, concurrency: int = 20):
self.base_url = base_url
self.domain = urlparse(base_url).netloc
self.semaphore = asyncio.Semaphore(concurrency)
self.visited: set[str] = set()
self.broken: list[dict] = []
async def check(self) -> list[dict]:
async with aiohttp.ClientSession(
timeout=aiohttp.ClientTimeout(total=15),
headers={'User-Agent': 'LinkChecker/1.0'},
) as session:
await self.crawl(session, self.base_url, referrer='root')
return self.broken
async def crawl(self, session: aiohttp.ClientSession, url: str, referrer: str):
if url in self.visited:
return
self.visited.add(url)
async with self.semaphore:
try:
async with session.get(url, allow_redirects=True) as resp:
status = resp.status
if status >= 400:
self.broken.append({'url': url, 'status': status, 'referrer': referrer})
return
# Парсим только HTML страницы своего домена
if urlparse(url).netloc == self.domain and 'text/html' in resp.headers.get('Content-Type', ''):
html = await resp.text()
links = self.extract_links(url, html)
tasks = [self.crawl(session, link, url) for link in links if link not in self.visited]
await asyncio.gather(*tasks, return_exceptions=True)
except asyncio.TimeoutError:
self.broken.append({'url': url, 'status': 'timeout', 'referrer': referrer})
except Exception as e:
self.broken.append({'url': url, 'status': str(e), 'referrer': referrer})
def extract_links(self, base: str, html: str) -> list[str]:
soup = BeautifulSoup(html, 'lxml')
links = []
for tag in soup.find_all(['a', 'link', 'img', 'script'], href=True):
href = tag.get('href') or tag.get('src')
if href:
absolute = urljoin(base, href)
parsed = urlparse(absolute)
if parsed.scheme in ('http', 'https'):
links.append(absolute.split('#')[0])
return list(set(links))
Планировщик и уведомления
# scheduler.py (Celery Beat)
from celery import Celery
from broken_link_checker import BrokenLinkChecker
import asyncio
import requests
app = Celery('tasks', broker='redis://localhost:6379/0')
@app.task
def check_broken_links():
checker = BrokenLinkChecker('https://example.com', concurrency=15)
broken = asyncio.run(checker.check())
if not broken:
return {'status': 'ok', 'checked': len(checker.visited)}
# Отправляем отчёт в Slack
message = f"🔗 Найдено {len(broken)} битых ссылок:\n"
for item in broken[:10]: # Первые 10
message += f"• `{item['status']}` {item['url']}\n ← {item['referrer']}\n"
if len(broken) > 10:
message += f"...и ещё {len(broken) - 10}. Полный отчёт в CSV.\n"
requests.post(os.env['SLACK_WEBHOOK'], json={'text': message})
# Сохраняем в БД для истории
BrokenLinkReport.objects.create(
checked_at = timezone.now(),
total_links = len(checker.visited),
broken_count = len(broken),
details = broken,
)
return {'broken': len(broken)}
# Расписание: каждый день в 6:00
app.conf.beat_schedule = {
'daily-link-check': {
'task': 'scheduler.check_broken_links',
'schedule': crontab(hour=6, minute=0),
},
}
Как избежать нагрузки на сервер?
Краулер работает на отдельном сервере, не нагружая ваш хостинг. Мы настраиваем задержки между запросами и уважаем директивы robots.txt. Если сайт большой (более 10 000 страниц), разбиваем сканирование на этапы и используем распределённые очереди через Celery. Это гарантирует, что проверка не повлияет на производительность вашего сайта для реальных пользователей. Свяжитесь с нами, чтобы мы подобрали оптимальную конфигурацию для вашего проекта.
Технические детали обработки редиректов
Краулер следует за редиректами (allow_redirects=True) и фиксирует конечный статус. Если редирект ведёт на 404, это также считается ошибкой. Для цепочек редиректов используется максимальное количество переходов (по умолчанию 10).
Сравнение способов проверки ссылок
| Метод | Трудоёмкость | Частота | Точность |
|---|---|---|---|
| Ручная проверка | Высокая (4 часа на 500 страниц) | Раз в месяц или реже | Субъективная, пропуски |
| Автоматическая (наш подход) | Низкая (5 минут на 500 страниц) | Ежедневно | 100% сканирование всех ссылок |
Автоматическая проверка в 50 раз быстрее ручного прогона и исключает человеческий фактор. Наша команда имеет многолетний опыт в SEO-аудите и разработке скриптов для веб-анализа, выполнив более 100 проектов по автоматизации мониторинга ссылок.
Типичные ошибки при самостоятельной настройке
| Ошибка | Последствие | Наше решение |
|---|---|---|
| Отсутствие таймаута | Зависание на медленных ресурсах | Устанавливаем таймаут 15 секунд |
| Пропуск JS-ссылок | Неполное сканирование | Парсим полный HTML, включая динамически подгружаемые ссылки |
| Игнорирование рефереров | Сложно найти страницу-источник | Сохраняем referrer для каждого найденного URL |
Какие инструменты мы используем?
Основной стек: Python 3.11, aiohttp для асинхронных запросов, BeautifulSoup для парсинга HTML, Celery для планирования задач и Redis как брокер сообщений. Все инструменты с открытым исходным кодом и хорошо документированы.
Что входит в настройку
- Анализ структуры сайта — определяем объём ссылок, приоритетные разделы.
- Конфигурация краулера — настраиваем глубину обхода, ограничения по домену, таймауты.
- Расписание сканирования — задаём частоту (ежедневно, еженедельно) и время запуска.
- Интеграция уведомлений — подключаем Slack, Telegram или email, настраиваем формат отчёта.
- Тестирование — проверяем корректность работы на тестовом сценарии.
- Документация и поддержка — передаём инструкцию по эксплуатации, предоставляем месяц поддержки.
Сроки и стоимость
Настройка занимает от 1 до 2 рабочих дней. Стоимость рассчитывается индивидуально в зависимости от сложности. Мы гарантируем работу краулера без нагрузки на ваш сервер. Получите консультацию по настройке мониторинга битых ссылок уже сегодня.







