Добавить в корзинуПозвонить
Найти в Дзене

Как быстро сделать парсер

Всем привет! На моем канале в тг CraftForge я написал пост о том, что каждый может написать парсер и без глубоких знаний в программировании, просто не все хотят тратить на это время. Дальше решил проверить сколько нужно потратить времени, чтобы получить приемлемый результат, а после голосования выбор пал на площадку Озон. Давайте попробуем. Используем ИИ, чтобы получить готовый парсер в котором мы указываем ссылку на категорию товара и количество товара нужного нам. Вернуть должен в формате json ссылку на товар, название товара, цену со скидкой и без, рейтинг и количество отзывов. Обращаюсь к ChatGPT с запросом:
“Привет, помоги мне написать парсер для маркетплейса Ozon, в конфиге указывается ссылка на категорию и количество товара, нужно получить ссылку на товар, название, цену со скидкой, цену без скидки, рейтинг и количество отзывов, используй python, предусмотри способы обхода блокировки парсеров и прокрутку страницы, чтобы получать больше карточек товара, давай добавим логирование,

Всем привет! На моем канале в тг CraftForge я написал пост о том, что каждый может написать парсер и без глубоких знаний в программировании, просто не все хотят тратить на это время. Дальше решил проверить сколько нужно потратить времени, чтобы получить приемлемый результат, а после голосования выбор пал на площадку Озон. Давайте попробуем. Используем ИИ, чтобы получить готовый парсер в котором мы указываем ссылку на категорию товара и количество товара нужного нам. Вернуть должен в формате json ссылку на товар, название товара, цену со скидкой и без, рейтинг и количество отзывов.

Обращаюсь к ChatGPT с запросом:
“Привет, помоги мне написать парсер для маркетплейса Ozon, в конфиге указывается ссылка на категорию и количество товара, нужно получить ссылку на товар, название, цену со скидкой, цену без скидки, рейтинг и количество отзывов, используй python, предусмотри способы обхода блокировки парсеров и прокрутку страницы, чтобы получать больше карточек товара, давай добавим логирование, чтобы отлавливать ошибки и сохранять полученные данные будем в файл JSON”

Он нам говорить про структуру файлов:

config.ini

[ozon]
category_url = https://www.ozon.ru/category/noutbuki-15600/
product_limit = 50

requirements.txt

selenium
webdriver-manager

и сам код:

import time
import json
import logging
import configparser

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By

# Настройка логирования
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler("parser.log", mode='w', encoding='utf-8'),
logging.StreamHandler()
]
)

config = configparser.ConfigParser()
config.read("config.ini")

CATEGORY_URL = config["ozon"]["category_url"]
PRODUCT_LIMIT = int(config["ozon"]["product_limit"])


def get_driver():
chrome_options = Options()
chrome_options.add_argument("--headless=new")
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--window-size=1920,1080")
chrome_options.add_argument("--lang=ru-RU")

chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option("useAutomationExtension", False)

driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""
})
return driver


def scroll_to_load(driver, limit):
SCROLL_PAUSE_TIME = 1.5
loaded = 0
last_height = driver.execute_script("return document.body.scrollHeight")

while loaded < limit:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(SCROLL_PAUSE_TIME)
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height

products = driver.find_elements(By.CSS_SELECTOR, "a.tile-hover-target")
loaded = len(products)
logging.info(f"Загружено товаров: {loaded}")


def parse_products(driver, limit):
results = []
product_cards = driver.find_elements(By.CSS_SELECTOR, "div[data-widget='searchResultsV2'] div[class*='tile']")

logging.info(f"Найдено карточек: {len(product_cards)}")

for i, card in enumerate(product_cards):
try:
link_tag = card.find_element(By.CSS_SELECTOR, "a.tile-hover-target")
link = link_tag.get_attribute("href")

name = card.find_element(By.CSS_SELECTOR, "span.tsBody500Medium").text.strip()

try:
price_discount = card.find_element(By.CSS_SELECTOR, "span.tsHeadline500Medium").text
price_discount = price_discount.replace("\u2009", "").replace("₽", "")
except Exception:
price_discount = ""

try:
price_old = card.find_element(By.CSS_SELECTOR, "span.tsBody400Strike").text
price_old = price_old.replace("\u2009", "").replace("₽", "")
except Exception:
price_old = ""

try:
rating = card.find_element(By.CSS_SELECTOR, "div.ui-rating__rating").text
except Exception:
rating = ""

try:
reviews = card.find_element(By.CSS_SELECTOR, "div.ui-rating__reviews").text
reviews = reviews.replace("(", "").replace(")", "")
except Exception:
reviews = ""

product = {
"link": link,
"name": name,
"price_discount": price_discount,
"price_old": price_old,
"rating": rating,
"reviews": reviews,
}

logging.info(f"[{i+1}] Собрано: {name[:40]}...")
results.append(product)

if len(results) >= limit:
break
except Exception as e:
logging.warning(f"Ошибка при обработке карточки: {e}")
continue

return results


def main():
logging.info("Запуск парсера Ozon")

try:
driver = get_driver()
logging.info("Открываю категорию...")
driver.get(CATEGORY_URL)
time.sleep(3)

logging.info("Прокручиваю страницу...")
scroll_to_load(driver, PRODUCT_LIMIT)

logging.info("Собираю карточки...")
products = parse_products(driver, PRODUCT_LIMIT)
driver.quit()

logging.info(f"Получено {len(products)} товаров.")

with open("results.json", "w", encoding="utf-8") as f:
json.dump(products, f, ensure_ascii=False, indent=2)

logging.info("Результаты сохранены в results.json")

except Exception as e:
logging.error(f"Критическая ошибка: {e}")


if __name__ == "__main__":
main()

Копируем в VSCode, редактируем конфиг:

category_url = https://www.ozon.ru/category/noutbuki-15692/
product_limit = 5

запускаем… и ничего нет(

Начинаем разбираться…

код запускается, принты пишутся, но результата нет, а нет его, потому что он ищет не те теги, теперь включаемся мы. Шаблон он нам дал, нужно определить правильные теги и искать уже по ним.

Открываем ссылку выбираем нужную карточку и нажимаем «Посмотреть код»

Видим что карточка идет в теге div с классом “tile-root”, а gpt ищет div[data-widget='searchResultsV2'] div[class*='tile'], сложно и ненужно, заменяем на (By.CLASS_NAME, "tile-root")

Смотрим дальше...

Ссылку он ищет вот так: (By.CSS_SELECTOR, "a.tile-hover-target")

Заменяем на (By.CSS_SELECTOR, "a")

Название и цену он сделал нормально

Для названия – "span.tsBody500Medium"

Для цены - "span.tsHeadline500Medium"

А вот цена без скидки он ищет через  "span.tsBody400Strike"

А на самом деле "span.tsBodyControl400Small"

-2

Рейтинг и отзывы он ищет через "div.ui-rating__rating"  и "div.ui-rating__reviews", что естественно не так

Ищем сами и получаем - div.tsBodyMBold ,в котором есть span`ы с значениями рейтинга и отзывов

-3

Редактируем:

spans = card.find_element(By.CSS_SELECTOR, "div.tsBodyMBold").find_elements(By.TAG_NAME, "span"))
rating = spans[0].text
reviews = spans[3].text

Запускаем и получаем адекватный результат

[
{
"link": "https://www.ozon.ru/product/lunnen-ground-15-noutbuk-15-6-amd-ryzen-5-7430u-ram-16-gb-ssd-512-gb-amd-radeon-graphics-2134285447/?at=WPtN1KjYztKk31xjHMNqw33TY2p7z5i1G1MOXF28KMnv",
"name": "Lunnen Ground 15 Ноутбук 15.6\", AMD Ryzen 5 7430U, RAM 16 ГБ, SSD 512 ГБ, AMD Radeon Graphics, Windows Home, (LL5FAWL03), голубой, Русская раскладка",
"price_discount": "36951",
"price_old": "82499",
"rating": "4.8",
"reviews": "176 отзывов"
},
...

Дальше можно дорабатывать как угодно, искать другие значения, бороться с защитой и ускорять обработку, но это уже другая история.

Из проделанной работы могу сделать вывод:
ИИ создает отличную основу - 90% кода уже рабочие
Но без человека не обойтись - в моем случае потребовалось только поправить теги, но в других ситуациях могут быть:

  • Антибот-системы
  • Динамическая подгрузка данных
  • Капчи

Цель была не в идеальном парсере, а в проверке:
Время от запроса до рабочего кода: ~20 минут (с учетом правок)
Уровень навыков: минимальный (достаточно понимать структуру HTML)

Можно углубляться:

  • Добавить обработку разных вариантов верстки
  • Настроить обход защиты
  • Сделать сохранение в Excel

Но главное - ИИ действительно сокращает путь от идеи до результата в разы.

P.S. ChatGPT  кстати не заточен под программирование, есть куда более специализированные нейронки