Разработка краулера для проверки битых ссылок на сайте
Битые ссылки — 404-ошибки — вредят SEO и портят пользовательский опыт. Краулер автоматически проверяет все внутренние и внешние ссылки сайта, находит нерабочие и формирует отчёт с указанием, на каких страницах они находятся.
Что проверяет краулер
- Внутренние ссылки — страницы внутри домена
- Внешние ссылки — исходящие ссылки на другие сайты
- Изображения — src-атрибуты
- CSS/JS ресурсы — загрузка статики
- Редиректы — цепочки редиректов длиннее 2 переходов
Реализация
import asyncio
import httpx
from bs4 import BeautifulSoup
from urllib.parse import urljoin
class BrokenLinksChecker:
def __init__(self, base_url: str):
self.base_url = base_url
self.checked = {} # url → status_code
self.broken = [] # {url, found_on, status}
self.queue = asyncio.Queue()
async def check(self):
await self.queue.put((self.base_url, self.base_url))
async with httpx.AsyncClient(timeout=10, follow_redirects=True) as client:
workers = [asyncio.create_task(self._worker(client)) for _ in range(10)]
await self.queue.join()
for w in workers: w.cancel()
return self.broken
async def _worker(self, client):
while True:
url, found_on = await self.queue.get()
try:
if url in self.checked:
continue
resp = await client.head(url) # HEAD быстрее GET
self.checked[url] = resp.status_code
if resp.status_code >= 400:
self.broken.append({
'url': url,
'status': resp.status_code,
'found_on': found_on,
})
elif resp.status_code == 200 and url.startswith(self.base_url):
# Внутренняя страница — краулим её ссылки
full_resp = await client.get(url)
for link in self._extract_links(url, full_resp.text):
if link not in self.checked:
await self.queue.put((link, url))
finally:
self.queue.task_done()
def _extract_links(self, base, html):
soup = BeautifulSoup(html, 'lxml')
links = set()
for tag in soup.find_all(['a', 'img', 'link', 'script'], href=True):
href = tag.get('href') or tag.get('src', '')
if href and not href.startswith(('#', 'mailto:', 'tel:')):
links.add(urljoin(base, href))
return links
Формат отчёта
CSV с колонками: broken_url, http_status, found_on_page, link_text. Готов к импорту в Google Sheets или Notion.
Время реализации: 1–2 рабочих дня.







