Прокси для интернет-магазина: прайсы поставщиков, остатки и наполнение карточек
Интернет-магазин подключает прокси там, где надо каждый день читать чужие страницы пачками: прайсы поставщиков, остатки на их складах, ассортимент соседей по нише и собственные карточки глазами покупателя. Пул примерно из 12 000 адресов с автоматической ротацией внутри пула и безлимитным трафиком закрывает ежедневный прогон по каталогу любого размера, а число потоков считается от количества карточек и длины окна, которое отведено под обход.
Дальше по порядку: какие пять задач магазин закрывает через посредник, как посчитать нагрузку под свой каталог, как устроен суточный прогон с расписанием и повторами, как сверять полученные цифры между прогонами и вовремя ловить сбои разбора. Отдельно про площадки поставщиков с личными кабинетами и про обновление списка адресов перед стартом.
Что магазин собирает через посредник каждый день
Задач обычно пять, и все они сводятся к чтению большого числа чужих страниц с сохранением результата в свою базу.
Первая: прайсы поставщиков. Прайс лежит на сайте поставщика или внутри его личного кабинета, обновляется по своему графику, и магазину нужна свежая цифра к утру, до того как менеджеры начнут принимать заказы. Вторая: остатки. Позиция числится в наличии в вашем каталоге и отсутствует у поставщика, заказ уходит в отмену, поэтому сверка остатков идёт чаще, чем полный обход прайсов.
Третья: наблюдение за ассортиментом. Смотрим, какие позиции появились у поставщиков и соседей по нише, какие ушли из выдачи, где сменилась комплектация или упаковка. Четвёртая: проверка собственных карточек со стороны. Свой сайт открывается с адреса из пула, и картинка получается та же, что видит покупатель из другой сети: доступность страницы, отдача изображений, работа фильтров, поведение каталога при частых обращениях.
Пятая: выгрузка характеристик для наполнения. Карточка без параметров, габаритов и описания продаёт слабо, а вручную заполнить десятки тысяч позиций невозможно. Характеристики забираются со страниц производителя и сводятся в таблицу, откуда уже импортируются в свой каталог. Под все пять задач берём приватные серверные адреса под сбор данных: прогон идёт с адреса из общего пула, рабочая сеть офиса остаётся в стороне, нагрузка распределяется по разным подсетям автоматически.
Общее у пяти задач одно: объём. Один менеджер руками открывает сотню страниц за смену, прогон открывает столько же за минуту. Именно объём и превращает обычный сбор данных в отдельную инженерную задачу с расписанием, логами и повторами.
Считаем нагрузку под размер каталога
Расчёт держится на четырёх величинах: число карточек в обходе, частота обновления, длина окна прогона и среднее время ответа целевого сайта. Первые три задаёт бизнес, четвёртую измеряем сами.
Порядок счёта короткий. Число карточек умножаем на частоту за сутки, добавляем запас на повторы примерно в восемь процентов, делим на длину окна в секундах и получаем требуемую скорость в запросах за секунду. Скорость умножаем на среднее время ответа: столько соединений программа должна держать открытыми одновременно. К результату добавляем треть про запас, потому что часть соединений в каждый момент висит в ожидании ответа медленных хостов.
запросы = карточки * прогонов_в_сутки * 1.08
скорость = запросы / (часы_окна * 3600)
потоки = скорость * среднее_время_ответа * 1.33
| Каталог, карточек | Прогонов в сутки | Окно | Запросов в час | Потоки при ответе 3 секунды |
|---|---|---|---|---|
| до 5 000 | 1 | 2 часа | 2 700 | 3 |
| 20 000 | 1 | 4 часа | 5 400 | 6 |
| 60 000 | 1 | 6 часов | 10 800 | 12 |
| 150 000 | 2 | 8 часов | 40 500 | 45 |
| 400 000 | 1 | 10 часов | 43 200 | 48 |
| 400 000 | 3 | 10 часов | 129 600 | 144 |
Цифры в последней колонке многих удивляют своей скромностью. Потоков нужно куда меньше, чем кажется на старте, потому что скорость упирается в ответ чужого сайта. Стандартный пакет с лимитом до 1000 потоков перекрывает даже самый тяжёлый вариант из таблицы с большим запасом, а корпоративный с лимитом до 3000 берётся тогда, когда прогоны идут параллельно с нескольких серверов. Пакеты по потокам не складываются, поэтому рост нагрузки закрывается переходом на старший вариант.
Есть второй ограничитель, о котором забывают: число площадок. Сорок восемь потоков, разложенных по двенадцати сайтам поставщиков, дают по четыре одновременных обращения на каждый хост, и такая частота проходит спокойно. Те же сорок восемь потоков, направленные на один сайт, выглядят со стороны площадки совсем иначе. Раскладку по хостам задаём в настройках прогона отдельно от общего лимита. Подробный разбор счёта адресов и потоков под конкретную задачу собран в материале про то, сколько адресов нужно под задачу.
Безлимитный трафик и объём выгрузки
Каталожная страница весит немного, зато их много. Средняя карточка вместе со стилями, скриптами и превью изображений тянет от 300 килобайт до полутора мегабайт. Умножаем на 60 000 карточек и получаем от 18 до 90 гигабайт за один полный обход. Три обхода в сутки превращают это в цифру, от которой в любой схеме с оплатой за объём начинает болеть голова.
Трафик у нас безлимитный на всех пакетах. Отсюда следует практический вывод: планировать выгрузку по объёму не нужно совсем. Загрузка изображений для проверки превью, повторный обход после сбоя разбора, разовая выкачка всего каталога поставщика перед сезоном идут без оглядки на счётчики. Магазины с большим каталогом и частыми прогонами берут именно пакеты с безлимитным трафиком по этой причине.
Из этого вырастает и рабочая привычка: сохранять сырой ответ целиком. Разбор ломается регулярно, вёрстка у поставщиков меняется без предупреждения, и когда исходный HTML лежит на диске, повторный разбор делается локально за минуты. Без сохранённого сырья приходится заново идти по всем карточкам. Диск дешевле часа простоя.
# сохраняем сырьё до разбора, разбор идёт отдельным шагом
curl -s -x http://198.51.100.24:8000 \
-H "Accept-Language: ru-RU,ru;q=0.9" \
"https://supplier.example/catalog/item/${SKU}" \
-o "raw/${RUN_ID}/${SKU}.html"
Расписание суточного прогона и порядок обхода
Прогон разбивается на несколько заданий с разной частотой. Полный обход прайсов тяжёлый, его ставим один раз в сутки на ночное окно. Сверку остатков делаем короткой и частой, потому что именно она отвечает за отмены заказов. Проверку своих карточек ставим отдельно, ближе к утру.
# crontab на сервере прогонов
10 2 * * * /opt/run/suppliers.sh full # полный обход прайсов
0 */3 * * * /opt/run/suppliers.sh stock # сверка остатков
30 6 * * * /opt/run/selfcheck.sh # свои карточки со стороны
45 5 * * 1 /opt/run/assortment.sh # ассортимент, раз в неделю
Порядок обхода фиксируем. Сначала идут поставщики, от которых зависит витрина, потом второстепенные, потом наблюдение за нишей. При таком порядке сбой на третьем задании не оставляет магазин без цен, потому что главное уже загружено и записано.
Внутри задания порядок тоже имеет значение. Обход по списку разделов даёт равномерную нагрузку на площадку, обход по случайной перестановке карточек размазывает обращения по всему сайту. Первый вариант проще отлаживать, второй ровнее ложится на чужой сервер. Мы обычно перемешиваем очередь внутри раздела и держим паузу от 400 до 900 миллисекунд между обращениями к одному хосту.
Планировщик заданий удобнее держать внутри самого сборщика. У A-Parser с его планировщиком заданий расписание, список прокси и разбор живут в одном месте, а ссылка на выдачу подтягивается перед каждым запуском автоматически. Тогда обновление списка адресов перестаёт быть отдельным ручным шагом.
Ошибки, повторы и медленные площадки
Прогон без обработки ошибок бесполезен: любой сбой на середине обнуляет ночную работу. Рабочая схема простая. Ошибка сети и таймаут дают три повтора с растущей паузой: 5, 20 и 60 секунд. Код 429 и код 503 обрабатываем по заголовку Retry-After, если он пришёл, иначе ждём минуту. Код 403 отправляет карточку в отложенную очередь, которая прогоняется в конце задания с половинной частотой. Коды 404 и 410 повторов не требуют, позиция помечается как снятая с продажи.
| Что видно в логе | Причина | Что делаем |
|---|---|---|
| Код 403 на части карточек | Площадка отбивает частоту обращений | Снижаем потоки на этот хост, повтор в конце прогона |
Код 429 с заголовком Retry-After | Свой лимит частоты у площадки | Ждём указанное число секунд, продолжаем с той же позиции |
| Код 200, полей в разборе нет | Вёрстка карточки поменялась | Сверяем селекторы на трёх карточках руками, правим шаблон |
| Обрыв по таймауту на одном хосте | Медленный ответ площадки | Поднимаем таймаут, выносим хост в отдельное задание |
| Цена нулевая по всей выгрузке | Разбор поймал страницу-заглушку | Останавливаем запись в базу, прогоняем сверку |
| Ошибка 407 от посредника | Привязка адреса не совпала с адресом машины | Обновляем привязку в кабинете, перезапускаем задание |
| Редирект на страницу входа | Сессия личного кабинета поставщика истекла | Обновляем сохранённые куки, повторяем пачку |
Медленные площадки заслуживают отдельного слова. Один поставщик с ответом в двенадцать секунд способен растянуть окно прогона вдвое, пока остальные ждут своей очереди. Выносим такие хосты в отдельное задание с собственным расписанием и собственным числом потоков, и общее окно возвращается к нормальной длине. Разделение по заданиям здесь работает лучше, чем попытки ускорить чужой сервер.
Отказ по коду 403 у магазинов встречается чаще прочих, и причины у него бывают разные: частота, состав заголовков, отсутствие привычной пары Accept-Language и User-Agent, обращение к карточке в обход раздела. Разбор кодов и порядок действий по каждому собран в отдельном материале про ошибку 403 при работе через прокси.
# повтор с растущей паузой, три попытки
for delay in 5 20 60; do
code=$(curl -s -o "$OUT" -w "%{http_code}" --max-time 25 \
-x http://198.51.100.24:8000 "$URL")
[ "$code" = "200" ] && break
sleep "$delay"
done
echo "$SKU;$code" >> "log/${RUN_ID}.csv"
Сверка цифр между прогонами и ловля сбоев разбора
Самая опасная поломка в сборе прайсов тихая. Прогон отработал, ошибок в логе нет, база обновилась, только цены в ней теперь нулевые, потому что поставщик переставил блок с ценой и селектор поймал пустоту. Витрина показывает ноль, менеджеры узнают об этом от покупателей.
Ловится это сверкой между прогонами. Каждый прогон пишет результат в отдельный файл с меткой запуска, и перед записью в боевую базу новый файл сравнивается с предыдущим по трём величинам: доля позиций с пустой ценой, доля изменившихся цен, средний размер изменения. Проходят пороги, идёт запись. Не проходят, задание останавливается и уходит сообщение администратору.
# сверка выгрузки с прошлым прогоном по артикулу и цене
join -t';' -j1 <(sort prev.csv) <(sort today.csv) \
| awk -F';' '$2 != $4 { print $1";"$2";"$4 }' > diff.csv
empty=$(awk -F';' '$2 == "" || $2 == "0" { c++ } END { print c+0 }' today.csv)
total=$(wc -l < today.csv)
echo "пустых: $empty из $total, изменений: $(wc -l < diff.csv)"
| Величина | Нормальный суточный разброс | Порог остановки |
|---|---|---|
| Доля позиций с пустой ценой | до 2 процентов | выше 6 процентов |
| Доля изменившихся цен | от 3 до 12 процентов | выше 40 процентов |
| Среднее изменение цены | до 7 процентов | выше 25 процентов |
| Число собранных карточек | разброс до 3 процентов | падение больше 15 процентов |
| Доля ответов с кодом 200 | от 96 процентов | ниже 85 процентов |
Пороги подбираем по своим данным за первые две недели работы. Ниша с частым изменением цен даст более широкий коридор, ниша с редкими пересмотрами узкий. Держим правило: любой выход за коридор останавливает запись, разбирается человеком и только потом продолжается.
Отдельно смотрим на число собранных карточек. Резкое падение при отсутствии ошибок почти всегда указывает на изменение пагинации у поставщика: разделов стало больше, страниц меньше, обход прошёл по укороченному списку. Такое ловится сравнением количества, поскольку коды ответов остаются рабочими.
Личные кабинеты поставщиков: работа с сессией
Часть поставщиков отдаёт нормальный прайс лишь внутри личного кабинета. Тут прогон превращается в работу с сессией: логин, куки, срок жизни сессии, иногда одноразовый код. Схема рабочая, требует только аккуратности.
Первое правило: один кабинет поставщика ходит с одного адреса из списка. Строку IP:PORT под кабинет выбираем из выдачи и держим её в конфигурации этого задания, пока сессия жива. Перескок между адресами внутри одной сессии выглядит для площадки странно и заканчивается выходом из кабинета.
Второе правило: сессию продлеваем отдельным лёгким запросом. Раз в двадцать минут дёргаем страницу профиля, ответ 200 подтверждает, что куки живы. Ответ с редиректом на форму входа означает, что пора логиниться заново, и лучше узнать это заранее, чем посреди выгрузки на восьми тысячах позиций.
# продление сессии кабинета поставщика
curl -s -o /dev/null -w "%{http_code}\n" \
-x socks5h://198.51.100.24:1080 \
-b cookies/supplier7.txt -c cookies/supplier7.txt \
https://supplier7.example/account/profile
Третье правило касается протокола. Кабинеты часто отдают файлы выгрузки по нестандартным портам и через служебные адреса, поэтому под такие задания удобнее брать сокетный доступ. Схема socks5h в примере выше отправляет и резолвинг имени на сторону посредника, поэтому запрос уходит целиком через пул. Разбор форматов и строк подключения лежит на странице про прокси SOCKS5 для программ и скриптов.
Файлы прайсов из кабинетов приходят в разных форматах, и это отдельная работа. XLSX с объединёнными ячейками, CSV с точкой с запятой, YML с чужой кодировкой. Разбор каждого формата пишем один раз и складываем в общий каталог обработчиков, а задание выбирает нужный по имени поставщика.
Обновление списка адресов перед стартом
Список адресов обновляется в реальном времени, ротация внутри пула автоматическая. Отсюда практическое правило: список перечитывается перед каждым крупным прогоном. Файл, скачанный месяц назад и лежащий на сервере, к очередной ночи наберёт неотвечающих строк, и утро уйдёт на разбор ошибок, которые снимаются одним обновлением.
Проще всего снять этот шаг совсем. В кабинете берётся ссылка на выдачу, ссылка прописывается в сборщике, дальше программа тянет актуальные строки сама перед каждым запуском. Формат выбирается по способу доступа: IP:PORT при работе с привязанным адресом сервера и IP:PORT:LOGIN:PASS, когда прогоны идут с нескольких машин или из облака. Подробности по обоим вариантам разобраны в материале про формат выдачи списка адресов.
# обновление списка перед стартом задания
curl -s "$PROXY_LIST_URL" -o proxies.txt
lines=$(wc -l < proxies.txt)
[ "$lines" -lt 100 ] && { echo "список пустой, прогон отменён"; exit 1; }
echo "адресов в списке: $lines"
Проверку на количество строк ставим обязательно. Пустой ответ выдачи из-за сетевого сбоя приводит к прогону без посредника напрямую с адреса сервера, а это худший вариант из возможных: площадки видят один адрес с высокой частотой и перестают отвечать всему офису. Три строки в скрипте закрывают эту дыру навсегда.
Перед сезонным пиком делаем ещё один шаг: короткий прогон на 200 карточек за час до основного задания. Он показывает время ответа площадок, долю кодов 200 и работу разбора на текущей вёрстке. Если что-то поменялось, останется час на правку шаблона. Магазины, у которых сезон определяет годовой результат, эту репетицию не пропускают.
Проверка собственных карточек со стороны
Свой сайт полезно смотреть чужими глазами, и адрес из пула для этого подходит лучше офисного. Кэш браузера пуст, куки отсутствуют, внутренние правила доступа по адресу офиса не работают. Открывается ровно то, что получает покупатель.
Смотрим на четыре вещи. Доступность карточек по прямым адресам без перехода из каталога. Отдачу изображений и их размеры. Работу фильтров и сортировок при обращении со стороны. Поведение каталога при частых обращениях, потому что защита от нагрузки иногда настроена слишком строго и отбивает живых покупателей вместе с чужими сборщиками.
# суточный обход своих карточек со стороны
while read -r url; do
read -r code size time <<< "$(curl -s -o /dev/null \
-w '%{http_code} %{size_download} %{time_total}' \
-x http://198.51.100.24:8000 "$url")"
echo "$url;$code;$size;$time" >> selfcheck.csv
done < urls-top500.txt
Отдельный сюжет: проверка отдачи разным сетям. Магазин с кэшем на стороне поставщика инфраструктуры иногда отдаёт устаревшую версию карточки части посетителей, и заметить это изнутри офиса невозможно. Обход с адресов из пула, где адреса приходят из множества стран и разных подсетей, показывает картину шире. Пул устроен как микс со всего мира, выборка по отдельной стране не делается, и для такой проверки разнообразие подсетей идёт только на пользу.
Результаты обхода складываем в тот же формат, что и сверку прайсов, и прогоняем по тем же порогам. Выпал размер страницы, значит что-то пропало из вёрстки. Выросло время ответа, значит стоит смотреть на сервер. Сравнение с прошлым днём отвечает на оба вопроса за секунду.
С чего начать магазину на старте
Порядок запуска короткий. Считаем каталог и окно, получаем требуемые потоки по формуле из второго раздела. Берём бесплатный тест до 2 часов и прогоняем на нём одно реальное задание по трём поставщикам: видно время ответа, коды и работу разбора на живых страницах. Дальше оформляем пакет по сроку и включаем расписание.
Срок берём по режиму работы. Разовая выгрузка каталога поставщика перед запуском нового раздела закрывается сутками. Постоянная сверка остатков и суточный обход прайсов просят месяца, потому что продлевать доступ вручную каждую неделю утомительно и любой пропуск останавливает витрину. Пакет включается примерно за 5 минут после оплаты, и первое задание можно запускать сразу. Оформляется всё там, где берут прокси под ежедневный сбор прайсов.
Отдельно про потоки при двух привязанных адресах. В пакет входит одновременная привязка 2 адресов, и при двух привязках общий лимит потоков делится между ними пополам. Магазины часто держат сервер прогонов и рабочую машину администратора, и тогда расчёт нагрузки ведём от половины лимита. Если весь прогон идёт с одного сервера, вторую привязку разумнее оставить пустой. Состав пакета целиком описан там, где оформляют доступ к пулу IPv4 под каталог магазина.
Частые вопросы
Подойдут ли прокси под сбор прайсов моего каталога?
Заранее предугадать поведение каждой площадки поставщика нельзя, поэтому перед покупкой доступен бесплатный тест длительностью до 2 часов под ваш запрос. Тест проходит на вашем сборщике и ваших целевых сайтах, и по его итогам видны время ответа, коды и работа разбора на живой вёрстке.
Что входит в прокси-пул и хватит ли его под суточный прогон?
В пуле около 12 000 активных адресов IPv4 и SOCKS5, онлайн держится в этом же районе в сутки. Стандартные пакеты дают до 1000 потоков, корпоративный до 3000. Прогон на 400 000 карточек за десять часов требует порядка полусотни потоков, поэтому лимита стандартного пакета хватает с большим запасом.
Как часто обновляется список адресов?
Список адресов обновляется в режиме реального времени, ротация внутри пула автоматическая. Забрать его можно ссылкой или файлом. Для суточных прогонов удобнее ссылка: сборщик подтягивает актуальные строки перед каждым запуском без участия человека.
В каком формате выдаётся список и как подключить его к сборщику?
Форматов два: IP:PORT и IP:PORT:LOGIN:PASS. Первый работает при привязанном адресе сервера, второй когда прогоны идут с нескольких машин. В пакете доступны IPv4, HTTP, HTTPS, SOCKS4 и SOCKS5, поэтому строка подключения подбирается под тот софт, который уже стоит.
Соседние задачи разобраны отдельно: съём позиций и работа с выдачей для отслеживания своих карточек в поиске, несколько рабочих кабинетов одной компании для разведения панелей поставщиков и рекламных аккаунтов, а также сводка ответов в материале частые вопросы о прокси IPv4. Перед первым суточным прогоном полезно пройти первое подключение по шагам, чтобы доступ и привязка были настроены заранее.