Чому скрапінг цін складніший, ніж здається
Один раз зіскрапити сайт — легко. Запустити скрапер, який працює щодня, адаптується до змін на сайті та не блокується — ось справжній виклик.
У цьому дописі розглянуто практичну сторону: інструменти, заходи захисту від ботів і як створити те, що можна реально запустити в продакшені.
Крок 1: Зрозумійте, що ви скрапите
Перш ніж писати жодного рядка коду, відкрийте DevTools (F12) → вкладка Network → перезавантажте сторінку.
Шукайте:
- XHR/Fetch запити — чи завантажується ціна через API-виклик? Якщо так, звертайтеся безпосередньо до API. Це набагато простіше, ніж парсити HTML.
- Статичний HTML — ціна є у вихідному коді сторінки (View Source)
- Відрендерено JavaScript — ціна з'являється лише після виконання JS (не видно у View Source)
# Швидкий тест: якщо це показує ціну, то це статичний HTML
curl -s "https://example.com/product" | grep -i "price"
Якщо curl показує ціну, ви можете використовувати простий HTTP-клієнт. Якщо ні — потрібен безголовий браузер.
Правильний інструмент для кожного випадку
| Тип сайту | Найкращий інструмент |
|---|---|
| Статичний HTML | Python requests + BeautifulSoup |
| REST API (JSON) | лише requests |
| Відрендерено JavaScript | Playwright або Puppeteer |
| Потужний антибот | Playwright + stealth-плагін + проксі |
Базовий статичний скрапер (Python)
import requests
from bs4 import BeautifulSoup
def get_price(url, selector):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
r = requests.get(url, headers=headers, timeout=10)
soup = BeautifulSoup(r.text, "html.parser")
el = soup.select_one(selector)
return el.get_text(strip=True) if el else None
price = get_price("https://example.com/product-123", ".price")
print(price)
Завжди встановлюйте User-Agent — голі запити без нього одразу блокуються більшістю сайтів.
Сайти з рендерингом JavaScript: використовуйте Playwright
from playwright.sync_api import sync_playwright
def get_price_js(url, selector):
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(url, wait_until="networkidle")
el = page.query_selector(selector)
price = el.inner_text() if el else None
browser.close()
return price
Playwright запускає справжній браузер — JavaScript виконується, з'являється ліниво завантажений контент, завантажуються динамічні ціни.
Чому сайти блокують скрапери (і як із цим справлятися)
Сайти виявляють скраперів за кількома сигналами:
1. Швидкість запитів — 100 запитів за 2 секунди — це очевидно не людина. Додайте затримки:
import time, random
time.sleep(random.uniform(1.5, 4.0)) # випадкова затримка між запитами
2. Відсутні заголовки браузера — справжні браузери надсилають Accept, Accept-Language, Referer тощо. Скопіюйте повний набір заголовків із DevTools.
3. Зняття відбитків (fingerprinting) — сайти перевіряють Canvas, WebGL, шрифти, роздільну здатність екрана. Playwright із плагіном stealth рандомізує ці параметри.
4. Репутація IP — IP-адреси дата-центрів часто позначаються. Вирішують проблему резидентні проксі, але вони коштують грошей ($10–50/міс).
5. CAPTCHA — якщо ви регулярно стикаєтеся з ними, потрібен сервіс розв'язання CAPTCHA (2captcha, AntiCaptcha) або розумніший підхід.
Запуск за розкладом
Для щоденного моніторингу цін використовуйте cron-завдання на VPS:
# Запуск щодня о 8:00
0 8 * * * /usr/bin/python3 /home/user/scraper/prices.py >> /home/user/scraper/prices.log 2>&1
Або використовуйте бібліотеку schedule в Python, якщо хочете, щоб скрипт працював безперервно:
import schedule, time
def job():
prices = scrape_all_products()
save_to_db(prices)
check_alerts(prices)
schedule.every().day.at("08:00").do(job)
while True:
schedule.run_pending()
time.sleep(60)
Збереження результатів і надсилання сповіщень
Для моніторингу цін потрібно відстежувати зміни в часі:
import sqlite3
from datetime import datetime
def save_price(product_id, price, source):
conn = sqlite3.connect("prices.db")
conn.execute(
"INSERT INTO prices (product_id, price, source, checked_at) VALUES (?, ?, ?, ?)",
(product_id, price, source, datetime.now().isoformat())
)
conn.commit()
conn.close()
def check_price_drop(product_id, threshold_pct=5):
conn = sqlite3.connect("prices.db")
rows = conn.execute(
"SELECT price FROM prices WHERE product_id = ? ORDER BY checked_at DESC LIMIT 2",
(product_id,)
).fetchall()
conn.close()
if len(rows) == 2:
current, previous = rows[0][0], rows[1][0]
drop = (previous - current) / previous * 100
if drop >= threshold_pct:
send_telegram_alert(f"Ціна впала на {drop:.1f}% на товар {product_id}")
Що я будую для клієнтів
Більшість проєктів моніторингу цін, над якими я працюю, мають однакову структуру:
- Python-скрапер (requests або Playwright залежно від сайту)
- SQLite або PostgreSQL для зберігання історії
- Telegram-бот для сповіщень про зниження ціни або відсутність товару в наявності
- Cron-завдання на VPS для щоденного запуску
На створення всього цього зазвичай іде 1–3 дні, а вартість становить $100–250 залежно від кількості сайтів і складності обходу антибот-систем.
Якщо вам потрібен моніторинг цін для вашого бізнесу, розкажіть, які сайти ви хочете відстежувати та як часто, і я зроблю вам пропозицію.