Парсинг сайта с разной вложенностью категорий: как найти URL товаров
При парсинге интернет-магазинов часто встречается неоднородная структура: где-то товары лежат на 3-м уровне вложенности, а где-то - сразу в корневой категории. Разберём, как решить эту задачу на Python, используя requests и BeautifulSoup. Мы рассмотрим два подхода: обход sitemap и рекурсивный парсинг категорий.
Почему стандартный подход не работает?
Если сайт имеет структуру «Категория → Субкатегория → Субсубкатегория → Товар», но в некоторых разделах субкатегорий нет, то просто пройтись по всем ссылкам на странице - неэффективно. Вы либо пропустите товары, либо загрузите лишние страницы. Проблема усугубляется, если sitemap.xml содержит рекурсивные ссылки на страницы категорий, а не на конечные товары.
Как найти sitemap и проверить его содержимое
Для начала проверьте robots.txt по адресу https://example.com/robots.txt. Там может быть указан путь к sitemap. Однако, как в вашем случае, sitemap может содержать не прямые ссылки на товары, а ссылки на страницы категорий. Тогда нужно либо парсить каждую страницу из sitemap рекурсивно, либо использовать другой подход.
Рекурсивный обход категорий: пошаговая инструкция
Вот простой алгоритм на Python, который обходит все внутренние ссылки на странице и собирает только те, что ведут на товары (например, содержат /product/ или /item/):
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
def get_all_links(url):
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
links = []
for a in soup.find_all('a', href=True):
href = urljoin(url, a['href'])
if href.startswith('https://example.com'):
links.append(href)
return links
# Начинаем с главной страницы
start_url = 'https://spoilerstalenergo-96.ru'
to_visit = [start_url]
visited = set()
products = []
while to_visit:
current = to_visit.pop()
if current in visited:
continue
visited.add(current)
print(f'Обрабатываю: {current}')
try:
links = get_all_links(current)
for link in links:
if '/product/' in link: # замените на свой шаблон
products.append(link)
elif link not in visited:
to_visit.append(link)
except Exception as e:
print(f'Ошибка: {e}')
print(f'Найдено товаров: {len(products)}')
Этот код обходит все страницы в пределах домена, собирая ссылки на товары. Вы можете заменить /product/ на любой другой паттерн, характерный для товаров на вашем сайте.
Что делать, если sitemap содержит рекурсивные ссылки?
Если sitemap.xml ведёт на страницы категорий, а те, в свою очередь, снова ссылаются на sitemap, попробуйте проигнорировать sitemap и использовать прямой обход с ограничением глубины. Например, установите максимальную глубину рекурсии (скажем, 5 уровней) и проверяйте, не зацикливается ли обход.
Проверка на дубликаты
Добавьте проверку, чтобы не посещать одни и те же страницы дважды. Используйте set() для хранения посещённых URL.
Альтернативные методы: XPath и CSS-селекторы
Если структура HTML однотипна, можно сразу извлекать ссылки на товары по CSS-классу (например, .product-item a). Это быстрее рекурсивного обхода. Пример:
soup.select('.product-item a[href]')
Такой подход подходит, если на странице категории товары уже отображены списком.
Заключение
Парсинг сайтов с неоднородной структурой требует гибкого подхода. Начните с проверки sitemap, затем используйте рекурсивный обход с ограничением глубины и фильтрацией по паттерну URL. Если сайт динамический (JavaScript), добавьте Selenium или Playwright. Главное - не забывайте про robots.txt и соблюдайте этикет парсинга.