СправочникПрактика › Прокси для Авито

Прокси для Авито: парсинг карточек, мониторинг цен и работа нескольких кабинетов

Приватный пул IPv4 и SOCKS5 для работы с досками объявлений

Прокси для доски объявлений это промежуточный порт, через который парсер или браузер обращается к площадке: запрос уходит с адреса пула, ответ возвращается вам. Площадка видит обращение от порта, рабочая машина остаётся за ним. Пул у меня приватный серверный, около 12 000 активных IPv4 и SOCKS5 в онлайне, перебор внутри пула автоматический, состав списка обновляется в реальном времени.

Сразу очерчу рамку заметки. Разговор идёт про сбор открытых данных с витрины и про обычную работу с кабинетами, которые принадлежат вам или вашим клиентам по договору. Всё остальное за пределами темы.

Задач на доске объявлений набирается четыре. Снять карточки целой категории. Следить за ценами в нише повторными срезами. Видеть место собственных объявлений в списке по запросу. Вести несколько кабинетов компании или агентства без пересечений между ними. У каждой задачи свой темп, своё число потоков и свои требования к раскладке обращений по адресам, и дальше я разбираю их по очереди.

Четыре сценария работы с доской объявлений и что нужно каждому

Четыре сценария и что каждому нужно от пула

Разница между сценариями видна по одному признаку: сколько страниц вы просите у площадки за единицу времени и насколько эти страницы похожи друг на друга. Обход каталога забирает много непохожих страниц подряд. Срез цен возвращается к одним и тем же карточкам по расписанию. Проверка позиции трогает всего несколько списков, зато аккуратно. Работа в кабинете обращений почти не создаёт, зато требует ровной сессии от входа до выхода.

Я держу эти четыре потока раздельно с первого дня проекта. Сбор карточек и вход в кабинет продавца никогда не идут через одну запись из списка одновременно: у них разный характер обращений, и смешивать их в одной сессии мне неудобно даже с точки зрения отладки логов. Когда в логах кабинета лежит только вход, отправка ответа клиенту и выгрузка статистики, любая аномалия видна сразу.

СценарийЧто забираюЧастотаПотокиФормат из выдачи
Обход каталогаСсылки и краткие поля карточекПолный проход раз в неделю8-12IP:PORT:LOGIN:PASS
Срез ценЦена, статус, дата подъёма3 захода в сутки4-6IP:PORT:LOGIN:PASS
Позиция своих объявленийНомер места в списке по запросу2 захода в сутки1-2IP:PORT:LOGIN:PASS
Работа в кабинетеЗаявки, сообщения, статистикаПо графику менеджера1IP:PORT с привязкой машины

Формат списка задаётся в кабинете сервиса, и я забираю обе формы сразу. Пара IP:PORT работает с привязанной машины, привязок в пакет входит две, менять их можно свободно. Форма IP:PORT:LOGIN:PASS ходит откуда угодно, поэтому именно она уезжает на удалённый сервер под парсер и в конфигурацию браузерных профилей. Забрать список IPv4 в двух форматах можно ссылкой или файлом, и ссылка при каждом обращении отдаёт актуальный состав.

Сбор карточек и цен списком: как устроен заход

Заход у меня двухступенчатый. Сначала снимаются списки категории постранично, из них выдёргиваются идентификаторы и ссылки. Потом отдельной очередью идут сами карточки. Разделение даёт две вещи. Первая: страницы списка тяжелее по разметке и меняются медленнее, их достаточно перечитывать раз в сутки. Вторая: очередь карточек легко резать по приоритету, потому что свежие объявления интересны сегодня, а карточка недельной давности подождёт до ночного окна.

Постраничный обход я ограничиваю по глубине. Смысла лезть на сотую страницу категории обычно нет: там лежат объявления, которые площадка сама показывает в конце. Мой предел 40 страниц на категорию за проход, дальше идёт добор через фильтры по цене, которые разбивают ту же категорию на узкие срезы. Такой приём даёт полноту без бесконечной пагинации.

Один запрос выглядит просто:

curl -x socks5h://LOGIN:PASS@IP:PORT \
     -H "Accept-Language: ru-RU,ru;q=0.9" \
     -H "Accept: text/html,application/xhtml+xml" \
     -s -o page.html -w "%{http_code} %{time_total}\n" \
     "https://www.avito.ru/all/telefony?p=3"

Схема socks5h тут важна: она отправляет разрешение имени на сторону порта. Если оставить обычный socks5, имя площадки разрешит ваша машина, и запрос уйдёт с одним адресом, а имя будет разобрано другим. Проверяю это на первом же запросе прогона.

Дедупликацию я веду по идентификатору объявления, он есть в ссылке. Для среза цен храню хеш от связки цены, статуса и даты подъёма. Если хеш совпал с прошлым заходом, запись в базу не идёт, обновляется только отметка времени проверки. На категории из 12 000 карточек это сокращает запись в базу примерно до 900 строк за срез, потому что за 8 часов меняется малая доля объявлений.

Отдельно про поля. Полную карточку я снимаю один раз при первом обнаружении объявления: заголовок, описание, параметры, имя продавца, дату публикации. Повторные заходы забирают короткий набор из четырёх полей. Такой съём в разы легче для приёмной стороны, и его можно держать чаще. Именно на этом различии строится весь мониторинг ниши: полный обход раз в неделю плюс короткие срезы по расписанию. Под этот режим я беру адреса для сбора данных с запасом по потокам, потому что недельный полный обход выедает квоту заметно сильнее ежедневных срезов.

Отслеживание позиции своих объявлений в списке

Позицию я снимаю так же, как её видит обычный посетитель: открываю список по нужному запросу с нужными фильтрами и ищу в разметке идентификатор своего объявления. Записываю номер места, номер страницы, число объявлений в списке и время съёма. Больше в этом сценарии ничего не происходит.

Тонкость тут одна и она про сессию. Проверять позицию из-под собственного кабинета бессмысленно: авторизованному продавцу площадка показывает свои объявления иначе, помечает их и подмешивает служебные блоки. Поэтому съём позиции у меня всегда идёт из отдельной сессии без входа, с пустыми куками и с записью из списка, которая в этот момент не занята кабинетами. Получается честный снимок витрины.

Второй момент про частоту. Два захода в сутки закрывают потребность целиком, потому что список пересобирается не поминутно и колебания внутри часа мало о чём говорят. Я снимаю утром и вечером, в одно и то же время, и веду ряд по дням. Когда объявление уезжает вниз на 15 мест за сутки, это видно по ряду сразу, и дальше уже разбираемся с содержанием карточки и с конкурентами в срезе.

Ряд позиций я сразу кладу рядом с рядом цен по той же категории. Две кривые на одном графике объясняют больше, чем каждая по отдельности: подъём средней цены по нише и одновременное сползание своего объявления вниз обычно означают, что рядом появились свежие карточки с более выгодными условиями. Такой вывод стоит одного запроса в 12 часов.

Лимиты на просмотр контактов и как под них подстроиться

Открытие телефона продавца это тяжёлое действие. Оно требует отдельного обращения, оно считается площадкой и оно ограничено. Ни одна доска объявлений не позволит смотреть контакты сотнями подряд с одной сессии, и это нормальное поведение витрины. Работать надо внутри разумного числа.

У меня норма 40 показов в сутки на одну запись из списка, разложенные неравномерно по 18 рабочим часам. Между показами пауза от 90 до 400 секунд, между сериями по 5 показов пауза до 20 минут. Такой ритм держится месяцами. Попытки поднять норму до 200 в сутки заканчивались тем, что счётчик упирался в предел уже к обеду, и остаток дня запись отдавала форму подтверждения на каждое обращение.

Действие на площадкеВес обращенияМой предел на одну записьЧто растёт при превышении
Страница списка категорииЛёгкое900 страниц в суткиВремя ответа
Карточка объявленияЛёгкое1400 страниц в суткиДоля кодов 429
Повторный срез ценыЛёгкое600 страниц в суткиДоля кодов 429
Открытие контактаТяжёлое40 показов в суткиФорма подтверждения
Вход в кабинетТяжёлое4 входа в суткиЗапрос кода на почту

Когда контактов нужно больше сорока, я увеличиваю число задействованных записей из выдачи, темп внутри каждой остаётся прежним. Список отдаёт тысячи вариантов, и разложить 200 показов на 5 записей по 40 штук куда спокойнее, чем выжимать одну. Каждая запись при этом ведёт свою собственную серию, со своими паузами и своим счётчиком, а планировщик просто выбирает следующую свободную.

Счётчик я держу в базе рядом с очередью, с обнулением по местному времени площадки. Если запись за сутки выбрала норму, планировщик её пропускает до следующего окна. Простая арифметика, которая избавляет от разбора отказов задним числом.

Несколько кабинетов у агентства: где начинаются пересечения

Агентство с шестью клиентами ведёт шесть кабинетов продавца. Все шесть менеджеров сидят в одном офисе, за одним выходом в сеть, часто на одинаковых машинах с одинаковыми браузерами. Для площадки это выглядит как одна группа кабинетов, потому что признаки совпадают по всем осям сразу: адрес обращения, отпечаток браузера, версия системы, набор шрифтов, разрешение экрана.

Проблема проявляется не в первый день. Кабинеты работают неделями, потом одному из них прилетает запрос подтверждения, и следом такие же запросы получают остальные пять. Разбирать это задним числом трудно, потому что связь между кабинетами уже зафиксирована.

Разводить кабинеты надо по двум осям одновременно. Первая ось это адрес обращения: каждый кабинет ходит через свою запись из списка, и записи не пересекаются между кабинетами в один момент времени. Вторая ось это окружение браузера: отдельный профиль на каждый кабинет, со своим хранилищем кук, своим набором заголовков и своим отпечатком. Я держу профили в антидетект-браузере по одному на кабинет и прописываю порт прямо в настройках профиля, чтобы менеджер физически не смог открыть чужой кабинет из своего окна.

Третья вещь касается людей. Менеджеру нужно объяснить, что кабинет открывается только из своего профиля, всегда. Один вход «просто посмотреть» из обычного браузера офиса связывает два кабинета намертво, и никакая последующая аккуратность этого уже не разберёт. У меня это записано в регламент отдельным пунктом, и новые сотрудники получают его в первый день.

Что площадка смотрит при входе в кабинет

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

Первое это адрес обращения и его история. Площадке интересно, приходил ли с него раньше этот аккаунт и приходили ли с него другие аккаунты. Второе это отпечаток браузера: движок, версия, набор шрифтов, параметры холста, размеры окна, часовой пояс, список языков. Третье это куки и локальное хранилище: свежая сессия против продолжения старой выглядят по-разному. Четвёртое это поведение внутри кабинета в первые секунды после входа.

Что сверяет площадкаЧто держу постояннымЧем проверяю перед запуском
Адрес обращения и его историяОдна запись на кабинет в пределах окнаЗапрос к сервису эха и сверка с логом профиля
Отпечаток браузераПрофиль без правок между сеансамиТестовая страница отпечатка, снимок в файл
Часовой пояс и языкСовпадают с настройками профиляЗаголовки запроса и вывод скрипта в консоли
Куки и локальное хранилищеОтдельный контейнер на кабинетРазмер каталога профиля и дата изменения
Разрешение имёнУходит на сторону портаСхема socks5h в строке подключения

Отдельно про разрешение имён, потому что здесь чаще всего пропускают ошибку. Браузер, настроенный на SOCKS5 без передачи имени, разбирает адрес площадки через системный преобразователь. В результате запрос приходит с порта, а запрос к службе имён уходит от вашего провайдера. Признак получается рассогласованный, и площадка это видит. В антидетект-браузере за это отвечает отдельная галочка в настройках порта, и я проверяю её на каждом новом профиле.

Ещё одна деталь про первые секунды. Профиль, который открывается ровно на странице кабинета и через две секунды запускает выгрузку статистики, для площадки выглядит машинным. Мои сценарии выгрузки всегда начинаются с обычной навигации: главная, раздел объявлений, потом уже отчёты. Разница в 20 секунд на старте окупается спокойной работой кабинета месяцами.

Как развести адреса и потоки по кабинетам

Раскладка строится вокруг простого правила: в один момент времени одна запись из списка обслуживает один кабинет. Список отдаёт тысячи вариантов, поэтому запас есть всегда. Я держу в базе таблицу соответствия кабинет и запись, а перед началом рабочего дня перечитываю выдачу по ссылке и обновляю таблицу. Состав пула меняется в реальном времени, и подтягивать актуальную выдачу перед стартом надёжнее, чем хранить прошлогодний файл.

Схема раскладки адресов и потоков по кабинетам агентства

Дальше идёт арифметика потоков, и она у пакета своя. Обычный пакет даёт 1000 одновременных потоков, корпоративный месячный до 3000. При двух привязанных машинах квота делится пополам, по 500 потоков на машину при обычном пакете. Пакеты между собой по потокам не складываются: два пакета на одном аккаунте живут как две независимые квоты со своими границами. Число пакетов на аккаунте при этом ничем не ограничено, и агентства этим пользуются охотно.

Что работаетСколько потоковОткуда берётсяКомментарий
6 кабинетов продавца6Браузерные профилиПо одному потоку на открытый профиль
Обход каталога12Парсер на сервере12 записей, по одному потоку на запись
Срезы цен6Тот же парсерРаботают в окнах между обходами
Позиции объявлений2Отдельный сценарийУтреннее и вечернее окно
Резерв под повторы24Очередь отложенныхПоднимается только в ночном окне

Сумма выходит скромная, и это правильно. Квота в 1000 потоков нужна как запас под пики, повседневная работа агентства укладывается в полсотни. Когда клиентов становится 20, схема просто растягивается: те же правила, больше строк в таблице соответствия. Именно поэтому я беру приватные адреса под кабинеты продавца сразу с расчётом на рост, чтобы через квартал не переделывать раскладку с нуля.

Разделение сбора и кабинетов держится жёстко. Парсер работает со своим набором записей, браузерные профили со своим, пересечений между наборами нет. Если запись сегодня обслуживала обход каталога, в таблицу кабинетов она попадёт не раньше следующей недели. Правило простое, соблюдать его помогает пометка в базе с датой последнего использования.

Какой темп сбора держать, чтобы прогон шёл сутками

Темп я считаю в окнах. Запросы в секунду для площадки такого размера мало о чём говорят, потому что суточная нагрузка складывается из коротких отрезков работы с длинными промежутками отдыха между ними. Окно это отрезок работы одной записи: пауза между запросами фиксированная, длительность окна фиксированная, после окна запись отдыхает. Такая нарезка даёт предсказуемые сутки и понятные цифры для планировщика.

Темп сбора на один адрес в сутки по типам страниц

Мои рабочие значения выглядят так. Карточка объявления: окно 25 минут, пауза 3-5 секунд, один поток на запись. За окно выходит около 375 карточек, четыре окна в сутки дают примерно 1400. Страница списка категории тяжелее по разметке и по нагрузке на приёмную сторону: окно 20 минут, пауза 5-7 секунд, около 200 страниц за окно, четыре с половиной окна дают 900. Повторный срез цены я держу ещё спокойнее, около 600 страниц в сутки, потому что он и так возвращается к знакомым карточкам.

Параллельность набирается числом записей. Двенадцать записей в одном окне дают 4500 карточек за 25 минут, и это уже серьёзная скорость для одного проекта. Полный обход категории на 12 000 объявлений закрывается за три окна подряд. Ночью я поднимаю число записей до 20 и удлиняю окна до 40 минут, потому что нагрузка на площадку в это время ниже и ответы приходят быстрее.

Пауза внутри окна у меня плавающая. Фиксированные 4 секунды ровным метрономом смотрятся неестественно в логах приёмной стороны, поэтому планировщик берёт случайное значение из диапазона на каждый запрос. Разброс небольшой, порядка 40 процентов от середины диапазона, и этого достаточно.

Метрика, за которой я слежу постоянно, одна: доля кодов 200 в окне. Пока она держится выше 94 процентов, темп остаётся прежним. Просадка до 88 процентов означает, что окно надо укоротить на треть и увеличить паузу на пару секунд. Проверяю я это по логу автоматически, и планировщик подстраивается сам. Ручного вмешательства такая схема требует раз в несколько недель, обычно после того как площадка меняет разметку.

Объём выгрузки я не считаю вообще, и это заметно упрощает планирование. У сервиса действует безлимитный трафик на всех пакетах, поэтому обсуждать остаётся только темп и число задействованных записей. Гигабайты за полный обход крупной категории набегают приличные, особенно если сохранять разметку страниц целиком под последующий разбор.

Повторный заход после отказа: как я веду очередь

Отказы будут всегда, и планировать надо с этой мыслью. У меня очередь устроена так: каждый элемент несёт ссылку, счётчик попыток, время следующей попытки и метку записи, с которой пробовали в прошлый раз. Планировщик берёт из очереди то, у чего время попытки уже наступило, и обязательно подбирает другую запись из списка, если прошлая попытка закончилась отказом.

Шаги задержки простые: 20 секунд, 40 секунд, 60 секунд. Три попытки подряд, и элемент уезжает в отложенную очередь до ночного окна. Ночью он получает ещё две попытки с более длинными паузами. Если и там глухо, ссылка помечается как проблемная и попадает в отчёт для ручного разбора.

for attempt in range(3):
    port = pool.next_free(exclude=item.last_port)
    code = fetch(item.url, proxy=port)
    item.last_port = port
    if code == 200:
        break
    sleep(20 * (attempt + 1))
else:
    deferred.push(item, at=night_window)

Коды я разбираю по-разному. Ответ 429 говорит про темп, и я укорачиваю текущее окно немедленно, не дожидаясь конца. Ответ 403 обычно приходит на конкретную запись, её я вывожу из окна и возвращаю через сутки. Пятисотые коды почти всегда временные, их достаточно повторить через минуту той же записью. Пустая страница с кодом 200 самая коварная: она проходит проверку кода, поэтому у меня стоит отдельная проверка на длину тела ответа и на присутствие опорного элемента разметки.

Форма подтверждения обрабатывается отдельной веткой. Запись, которая получила её дважды за окно, уходит на отдых до следующего дня, а её элементы переносятся на другие записи очереди. Доля таких случаев у меня держится в пределах 2 процентов от обращений, и растёт она только при попытке ускориться сверх нормы.

Отчёт по отказам я читаю раз в сутки. Смотрю на три цифры: доля отказов по окнам, число записей, ушедших на отдых, размер отложенной очереди к утру. Если отложенных к утру больше 5 процентов от суточной нормы, значит темп завышен и на следующие сутки я снижаю число окон. Такая обратная связь работает у меня без изменений на трёх проектах.

Как всё это складывается в рабочую раскладку

Соберу картину целиком, как она выглядит у меня на живом проекте с шестью клиентами. Один месячный пакет обслуживает сбор: обход каталогов по ночам, три среза цен в сутки, два снимка позиций утром и вечером. Второй месячный пакет обслуживает кабинеты: шесть браузерных профилей, по одному потоку на профиль, включаются по рабочему графику менеджеров. Наборы записей у пакетов разные, таблица соответствия обновляется каждое утро вместе с перечитыванием выдачи.

Планировщик у меня один на оба пакета, и он знает про все ограничения сразу: норму окон на запись, суточный предел показов контактов, время отдыха после отказа. За счёт этого сбор и кабинеты никогда не конкурируют за одну запись. Логи пишутся раздельно по сценариям, и разбор утреннего отчёта занимает минут десять.

Что даёт такая раскладка на дистанции. Доля кодов 200 на сборе держится около 96 процентов, кабинеты за полгода не запросили подтверждение ни разу, полный обход категории на 12 000 объявлений закрывается за одну ночь. Стоит эта аккуратность одного вечера настройки и десяти минут ежедневного внимания. Когда проект вырастет вдвое, менять придётся только цифры в таблицах, потому что приватный серверный пул на своём оборудовании отдаёт достаточно записей под любое число кабинетов, а квота потоков на обычном пакете покрывает нагрузку с большим запасом.

Соседние заметки вики продолжают тему с других сторон. Как снимать отзывы и следить за репутацией бренда теми же средствами, разобрано в материале сбор отзывов и репутации. Что означают обе формы выдачи и когда какую подключать, описано в заметке формат списка адресов. Арифметика потоков под размер пакета подробно посчитана в статье лимит потоков и расчёт нагрузки. Из раздела о сборе данных ближе всего страница про капчу при сборе, где формы подтверждения разобраны по типам и способам обработки.