Установить httpx и селектолакс, отправьте один запрос GET с реалистичным заголовком User-Agent и выделите цену с помощью одного CSS-селектора. Вот и готовый скрейпер — всего около 15 строк кода. Добавьте прокси и механизм повторных попыток, как только вас начнут блокировать, что на реальных розничных сайтах происходит довольно быстро.
Как собирать данные о ценах с помощью Python: пошаговое руководство (2026)
Извлечение цен с помощью Python предполагает написание скрипта, который загружает страницу товара, находит цену в HTML-коде или в отображаемом результате и сохраняет её в виде структурированных данных, которые можно сравнивать или отслеживать с течением времени. Самая простая версия состоит из одного HTTP-запроса и парсера HTML. Сложности возникают при защите от ботов и при работе с ценами, отображаемыми с помощью JavaScript, и именно этим вопросам посвящена большая часть данного руководства.
Это техническое руководство является частью нашего более обширного руководства по мониторинг цен конкурентов. Если вас интересует обзор стратегии и инструментов, начните с этого раздела. Если вам нужен готовый к запуску код, продолжайте читать.
Основные выводы
- Простой скрейпер цен — это HTTP-клиент (
запросыилиhttpx) плюс парсер (селектолаксили BeautifulSoup), который обращается к одному CSS-селектору. - Самая уязвимая часть — это не синтаксический анализ, а доступ: ограничения по скорости, фильтрация по пользовательскому агенту, гео-маскировка и прямые блокировки IP-адресов.
- Использование сменяющихся прокси-серверов для частных пользователей имеет важное значение для страниц с ценами, поскольку отображаемая цена зависит от страны и репутации IP-адреса, с которого поступает запрос.
- Для отображения цен с помощью JavaScript требуется либо браузер без графического интерфейса, либо обратный инжиниринг вызова API, либо сервис преобразования в формат Markdown.
- Сохраняйте каждое наблюдение в виде строки с отметкой времени и указанием валюты, чтобы отслеживать изменения, а не просто фиксировать моментальные снимки. Соблюдайте Условия предоставления услуг и файл robots.txt каждого сайта.
Что такое сбор данных о ценах?
Сбор данных о ценах — это автоматизированное извлечение цен на товары (а также, как правило, сопутствующих полей, таких как название, валюта, наличие в наличии и артикул) с веб-страниц. Розничные продавцы используют эту практику для мониторинга конкурентов. Бренды — для обеспечения соблюдения минимальных рекламных цен. Агрегаторы — для обеспечения работы Сравнение цен на веб-парсинг сайты.
Цены представляют собой ценную цель, которая активно защищается. Согласно отчету «Imperva Bad Bot Report 2025» (компания Thales) было установлено, что в 2024 году объем автоматизированного трафика впервые за десятилетие превысил объем трафика, генерируемого людьми, составив 51 % всего веб-трафика, при этом доля вредоносных ботов составила 37 %. Сектор электронной коммерции входит в число наиболее уязвимых, поэтому страницы с ценами защищены теми же средствами, которые блокируют ботов, занимающихся «набивкой учетных данных» и «накоплением запасов». Ваш скрейпер должен выглядеть как обычный посетитель.
Шаг 1: Простой скрейпер цен на Python
Начнём с самого простого варианта, который может сработать: один запрос GET и один парсер. Мы используем httpx (современный запросы(совместимый клиент) и селектолакс (быстрый HTML-парсер, созданный на основе lexbor).
pip install httpx selectolax
import httpx
from selectolax.parser import HTMLParser
HEADERS = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/126.0.0.0 Safari/537.36"
),
"Accept-Language": "en-US,en;q=0.9",
}
def scrape_price(url: str, price_selector: str) -> str | None:
resp = httpx.get(url, headers=HEADERS, timeout=20.0, follow_redirects=True)
resp.raise_for_status()
tree = HTMLParser(resp.text)
node = tree.css_first(price_selector)
return node.text(strip=True) if node else None
if __name__ == "__main__":
price = scrape_price("https://example.com/product/123", "span.price")
print(price)
Единственная часть, зависящая от конкретного места, — это выбор_цены. Откройте страницу продукта в браузере, просмотрите элемент с ценой и скопируйте стабильный селектор (класс или data- атрибут, а не глубокий div > div > div цепочка, которая прерывается при следующем развертывании).
Цены возвращаются в виде неформатированных строк, например: «1 299,00 долларов» или «1 299,00 €». Перед сохранением выполните нормализацию:
import re
from decimal import Decimal
def parse_amount(raw: str) -> Decimal | None:
if not raw:
return None
# Удаление всего, кроме цифр и разделителей
cleaned = re.sub(r"[^\d.,]", "", raw)
# Эвристический подход: если запятая является десятичным разделителем (например, «1.299,00»)
if cleaned.count(",") == 1 and cleaned.rfind(",") > cleaned.rfind("."):
cleaned = cleaned.replace(".", "").replace(",", ".")
else:
cleaned = cleaned.replace(",", "")
try:
return Decimal(cleaned)
except Exception:
return None
Всегда указывайте исходный символ валюты отдельно. Не следует предполагать, что речь идет о долларах США (USD).
Шаг 2: Работа с средствами защиты от ботов
Приведенный выше пример работает на тестовом сайте, но не работает на сайтах большинства реальных розничных продавцов. Ниже описано, с какими проблемами вы можете столкнуться и как их решать.
Ограничения по частоте запросов и повторные попытки
Массированные запросы к сайту — это самый быстрый способ попасть в черный список и самое невежливое, что вы можете сделать. Добавьте к этому задержки, колебания и экспоненциальный откат в ответах, означающих «сбавьте темп» (429) или «временно недоступно» (503).
import random
import time
import httpx
def get_with_backoff(client: httpx.Client, url: str, max_tries: int = 4):
for attempt in range(max_tries):
resp = client.get(url, timeout=20.0)
if resp.status_code not in (429, 503):
return resp
wait = (2 ** attempt) + random.uniform(0, 1.0)
time.sleep(wait)
resp.raise_for_status()
return resp
Пользовательские агенты и заголовки
Запрос без заголовков явно указывает на то, что он выполнен скриптом. Отправьте реалистичный и актуальный User-Agent браузера, а также заголовки, которые отправляет настоящий браузер (Принять, Accept-Language, Accept-Encoding). Поочередное использование небольшого набора реальных, недавних строк UA помогает, однако даже правдоподобный UA в сочетании с IP-адресом, находящимся в списке блокировки, по-прежнему приводит к блокировке.
IP-блоки, гео-маскировка и почему прокси-серверы для частных пользователей имеют важное значение
Именно эту часть в большинстве руководств обычно пропускают. Два запроса на один и тот же URL товара могут возвращать разные цены, разные валюты или страницу с сообщением об ошибке, что полностью зависит от IP-адреса, с которого поступил запрос.
- IP-адреса центров обработки данных (диапазоны, которые используют большинство облачных серверов) легко определить, и на страницах с ценами они зачастую подвергаются ограничению пропускной способности или вовсе блокируются.
- Гео-маскировка Это означает, что сайт показывает посетителю из США цены в долларах США, а посетителю из Германии — цены в евро. Если вы собираете данные из одного региона дата-центра, вы всегда будете видеть цены только одного рынка, а иногда и сообщение «Недоступно в вашем регионе».
Вращающиеся прокси-серверы из частных сетей направляют запросы через реальные подключения пользователей, благодаря чему они имеют репутацию IP-адреса обычного посетителя и позволяют вам выбрать страну (а иногда и город), из которой, по-видимому, поступает запрос. Для сбора данных о ценах это означает, что вы видите реальные локализованные цены для каждого рынка и обходите блокировки по IP-блокам центров обработки данных, которые ограничивают доступ к этим страницам. Massive управляет сетью резидентных прокси в более чем 195 странах (HTTP/HTTPS/SOCKS5) с возможностью геотаргетинга по стране/городу и ротационными или фиксированными сессиями.
Для подключения прокси-сервера к клиенту достаточно внести изменение всего в одной строке:
import os
import httpx
# Massive прокси-серверы для частных пользователей. Учетные данные указываются в URL-адресе прокси в формате «имя пользователя:пароль».
PROXY = (
f"https://{os.environ['MASSIVE_PROXY_USERNAME']}:"
f"{os.environ['MASSIVE_API_KEY']}@network.joinmassive.com:65535"
)
with httpx.Client(proxy=PROXY, headers=HEADERS, timeout=20.0) as client:
resp = client.get("https://example.com/product/123")
print(resp.status_code)
Используйте вращающийся сессия, если вам требуется новый IP-адрес для каждого запроса (это полезно для распределения нагрузки), и закреплённый сессия, когда в рамках одного рабочего процесса требуется использовать один и тот же IP-адрес для нескольких запросов (например, для установки файла cookie с указанием региона, а затем для загрузки цены). Подробное руководство с учетом особенностей работы конкретного интернет-магазина см. собирать данные о ценах на Amazon, не попадая под блокировку.
Шаг 3: Обработка цен, отображаемых с помощью JavaScript
Многие интернет-магазины отправляют практически пустую HTML-оболочку и выводят цену на стороне клиента с помощью JavaScript. Если resp.text не содержит цену, то парсер на этапе 1 возвращает Нет независимо от того, насколько хорош ваш селектор. У вас есть три варианта.
Вариант А: Найдите соответствующий API. Откройте DevTools, перейдите на вкладку «Сеть», установите фильтр «XHR/Fetch» и перезагрузите страницу. Цена почти всегда поступает в ответе в формате JSON. Прямой вызов этого конечного пункта происходит быстрее и стабильнее, чем при рендеринге, если сам API не заблокирован.
Вариант B: Запустить браузер без графического интерфейса. Playwright отображает страницу в реальной среде Chromium, поэтому цена уже присутствует в DOM к моменту, когда вы её видите.
from playwright.sync_api import sync_playwright
def scrape_rendered_price(url: str, selector: str) -> str | None:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(url, wait_until="networkidle")
node = page.query_selector(selector)
value = node.inner_text() if node else None
browser.close()
return value
«Безголовые» браузеры являются ресурсоемкими: они потребляют гораздо больше ресурсов процессора и памяти, чем HTTP-запрос, и хуже масштабируются.
Вариант C: Преобразование в формат Markdown (простой способ). Это путь наименьшего сопротивления. Web Render API выполняет рендеринг в режиме «headless» на чужой инфраструктуре: реальные браузеры выполняют JavaScript-код страницы, а готовый результат преобразуется в чистый Markdown и передаётся обратно вашему коду. Web Render API от Massive имеет конечную точку «Browsing», которая делает именно это. Вы избегаете как накладных расходов, связанных с использованием браузера в режиме «headless», так и большей части работы по разбору HTML, поскольку ищете строку с ценой в читаемом тексте, а не просматриваете неустойчивый DOM, а формат Markdown попадает прямо в клиент ИИ или запрос LLM, если вы хотите извлечь цену таким образом.
import os
import re
import httpx
# Web Render API Massive, конечная точка просмотра: он отображает страницу в
# сети Massive и возвращает очищенный код Markdown.
def render_markdown(url: str, country: str = "US") -> str:
resp = httpx.get(
"https://render.joinmassive.com/browser",
params={"url": url, "format": "markdown", "country": country},
headers={"Authorization": f"Bearer {os.environ['MASSIVE_API_TOKEN']}"},
timeout=60.0, # рендеринг занимает больше времени, чем простой запрос GET, поэтому необходимо предусмотреть запас времени
)
resp.raise_for_status()
return resp.text
# Маркдаун гораздо проще анализировать, чем необработанный HTML. Передайте параметр country, чтобы прочитать
# цену так, как её видит местный покупатель (цена в долларах США, в евро и т. д.).
markdown = render_markdown("https://example.com/product/123")
match = re.search(r"\$[\d,]+\.\d{2}", markdown)
price = match.group(0) if match else None
Шаг 4: Структурирование и хранение данных
Цена имеет смысл только в виде временного ряда. Сохраняйте каждое значение в отдельной строке с отметкой времени, чтобы вы могли выявлять падения цен, отслеживать конкурентов и создавать система мониторинга цен сверху.
import sqlite3
from datetime import datetime, timezone
from decimal import Decimal
def init_db(path: str = "prices.db") -> sqlite3.Connection:
conn = sqlite3.connect(path)
conn.execute(
"""
CREATE TABLE IF NOT EXISTS observations (
id INTEGER PRIMARY KEY,
sku TEXT NOT NULL,
url TEXT NOT NULL,
amount TEXT NOT NULL, -- храните Decimal в виде текста, никогда не используйте float
currency TEXT NOT NULL,
country TEXT, -- с какого рынка взята данная цена
scraped_at TEXT NOT NULL
)
"""
)
return conn
def record(conn, sku: str, url: str, amount: Decimal, currency: str, country: str):
conn.execute(
"INSERT INTO observations (sku, url, amount, currency, country, scraped_at) "
"VALUES (?, ?, ?, ?, ?, ?)",
(sku, url, str(amount), currency, country,
datetime.now(timezone.utc).isoformat()),
)
conn.commit()
Два правила, которые пригодятся вам в будущем: сохраняйте сумму в виде текста или целого числа, обозначающего количество мелких единиц (ни в коем случае не в виде двоичного числа с плавающей запятой, при котором теряются центы), и всегда фиксируйте валюта и страна. Наличие значений «$50» и «50 EUR» в одном столбце без указания валюты является скрытой ошибкой в данных. Для CSV-файла или конвейера складских данных схема остается той же: значимой единицей является строка с отметкой времени и рыночной меткой. Если вы предпочитаете приобрести готовое решение, а не разрабатывать его самостоятельно, сравните инструменты для отслеживания цен конкурентов.
Примечание о правовых аспектах и условиях предоставления услуг
Это не является юридической консультацией, однако стоит ознакомиться с практической ситуацией. Сбор общедоступных данных неоднократно признавался законным в США в рамках Закона о компьютерном мошенничестве и злоупотреблении: в ходе длительного судебного разбирательства hiQ Labs против LinkedIn В рамках судебного разбирательства Девятый окружной апелляционный суд в 2022 году вновь подтвердил, что доступ к общедоступным данным веб-сайтов, вероятно, не является доступом «без разрешения» в понимании Закона о компьютерном мошенничестве и злоупотреблении (CFAA). Данное постановление касалось конкретно Закона CFAA и не являлось общим разрешением. По-прежнему могут применяться и другие правовые основания (нарушение Условий предоставления услуг сайта, авторское право, незаконное посягательство на движимое имущество, а также законодательство о защите частной жизни).
Практические меры предосторожности: ознакомьтесь с Условиями предоставления услуг каждого сайта и соблюдайте их, а также robots.txt, собирайте только общедоступные данные о ценах (ни в коем случае не собирайте информацию, доступ к которой ограничен авторизацией, и которую вы обязались не собирать), соблюдайте ограничения на частоту запросов, чтобы не ухудшать работу сайта, и избегайте сбора персональных данных. В случае сомнений проконсультируйтесь с юристом.
Создайте это на платформе, которая учитывает реальную цену
Сам код — это самая простая часть. Сложность заключается в обеспечении постоянного доступа к точным, локализованным ценам, и всё сводится к тому, откуда, по-видимому, исходят ваши запросы. Сеть Massive для частных пользователей (более 195 стран, геотаргетинг по стране/городу, ротационные или фиксированные сессии) и Web Render API (отрендеренные страницы в виде чистого Markdown) решают обе эти проблемы: репутация IP-адреса и геотаргетинг, которые позволяют обойти блокировки, а также рендеринг, благодаря которому вы получаете цены, загружаемые с помощью JavaScript, без необходимости самостоятельно запускать браузеры. Ознакомьтесь с Web Render API от Massive и прокси-серверами для частного использования.
Источники
- Imperva (компания, входящая в группу Thales), «Отчет Imperva о вредоносных ботах за 2025 год: как искусственный интеллект усиливает угрозу, исходящую от ботов», https://www.imperva.com/blog/2025-imperva-bad-bot-report-how-ai-is-supercharging-the-bot-threat/ (проверено 15 июня 2026 г.)
- Дело «hiQ Labs, Inc. против LinkedIn Corp.», 31 F.4th 1180 (9-й окружной апелляционный суд, 2022 г.) (после возвращения дела на повторное рассмотрение, в котором вновь подтверждено, что сбор данных с общедоступных веб-сайтов, вероятно, не представляет собой доступ «без разрешения» в понимании Закона о компьютерном мошенничестве и злоупотреблении (CFAA)).
- Jenner & Block LLP, «Сбор данных: в деле hiQ против LinkedIn Девятый окружной апелляционный суд вновь подтвердил узкое толкование Закона о компьютерных мошенничествах и злоупотреблениях (CFAA)», https://www.jenner.com/en/news-insights/publications/client-alert-data-scraping-in-hiq-v-linkedin-the-ninth-circuit-reaffirms-narrow-interpretation-of-cfaa (проверено 15 июня 2026 г.)
Часто задаваемые вопросы
Существует две распространенные причины. Во-первых, цена может формироваться с помощью JavaScript, поэтому она отсутствует в исходном HTML-коде, который получает ваш HTTP-клиент; вам понадобится браузер без графического интерфейса или сервис для преобразования в формат Markdown. Во-вторых, сайт может использовать гео-клокинг, отображая разные цены в зависимости от страны, или блокировать ваш IP-адрес. Сбор данных с использованием резидентного IP-адреса внутри страны позволяет не только узнать правильную локализованную цену, но и избежать блокировок по IP-адресам центров обработки данных.
Если речь идет о нескольких страницах — нет. При значительных объёмах — да. Страницы с ценами активно защищаются, и IP-адрес одного дата-центра, отправляющий повторяющиеся запросы, быстро подвергается ограничению скорости или блокировке. Смена прокси-серверов с частных IP-адресов распределяет запросы по реальным IP-адресам пользователей и позволяет нацеливаться на конкретные страны, что необходимо в случаях, когда цены варьируются в зависимости от рынка.
Три варианта в порядке предпочтения: найти JSON-API, к которому обращается страница (проверьте вкладку «Сеть» в DevTools), запустить браузер без пользовательского интерфейса, например Playwright, или воспользоваться Web Render API, который возвращает полностью отрендеренную страницу (вывод в формате Markdown проще всего анализировать). Простой запросы/httpx сам по себе не может выполнять JavaScript.
Сбор общедоступных данных о ценах выдержал судебные оспаривания на основании Закона США о компьютерном мошенничестве и злоупотреблении (CFAA) (в частности, hiQ против LinkedIn), однако это не распространяется на вопросы, связанные с Условиями предоставления услуг, авторским правом или нарушением конфиденциальности, а законодательство варьируется в зависимости от юрисдикции. Ограничивайтесь открытыми данными, соблюдайте robots.txt а также соблюдайте Условия предоставления услуг, вежливо ограничивайте частоту запросов и обращайтесь к юристу по любым коммерческим вопросам или в случае крупномасштабных проектов.
