Привет всякому входящему! Сегодня хочу рассказать о том, как сложно спрогнозировать вроде бы простые задачи, на которые по словам «экспертов с интернета» уходит пару дней. Я поделюсь примерами из жизни, когда клиент просит сделать быстренько на коленке, а ты погрязаешь в рутине переделок.
У нас с командой есть такой проект, как homecrm.ru Мы долгое время работаем над автоматизацией бизнеса и уже получили много опыта, на основе которого можно проводить хоть какую-то экспертизу и прогнозирование плюс минус паровоз. За 7 лет разработки можем поделиться накопившемся багажом знаний, кучей получившихся проблем и путями их решений на основе этого стартапа.
С чего начинается идея
5 лет назад к нам приходит клиент и говорит: "Парни, я хочу собирать объявления с сайтов в один клик. Вот у меня список сайтов, на которые рекламируются все, кому не лень. Соберите мне всю информацию в реальном времени. Я готов заплатить за это 30 тысяч рублей."
Ну мы люди не гордые, провинциальные, можем и посмотреть. Заходим в интернет, видим статьи про парсинг на php, радуемся как ужаленные. ТЗ никакого нет, заказчик не составит его, так как сам ничего в этом не понимает. Для него есть конечная цель и ему совершенно фиолетово, какие мы технологии используем, и как оно будет работать. Лишь бы был достигнут результат. В принципе, это типичный клиент, ему и не нужно ни в чём разбираться. Это сейчас я понимаю, что надо было писать тех задание, а тогда был зеленый, неопытный.
Так вот. Мы, одурманенные чувством простой прибыли, на коленке за 5 дней сделали парсер. Простой скрипт, который проходит и собирает список объявлений с сайта (с ави*о. ру, никому не скажем об этом). Ставим на сервер, по крону запускаем раз в час — всё работает. Получаем деньги и идем пить пиво.
Проходит 3 дня. Клиент позвонил и говорит: "Парни, а там больше не работает ничего. Я же деньги дал, а вы чего пытаетесь кинуть меня чтоли." Лезем в код — поменялась вёрстка на сайте. Следовательно и скрипт перестал работать. Мы переделали и запустили заново. Ну вот сейчас то точно ничего не произойдёт (-нет).
Прошла еще неделя. Снова звонок и снова доработки. И так по кругу в течение полугода. Нам повезло, что клиент разорился и уехал жить в Краснодар. Иначе бы мы никогда с ним не закончили.
Вообще, мы читали в интернете и на всяких интернет-курсах, что парсинг — это просто. Там вообще не надо ни с чём долбаться. Просто собирай огромный объем данных и продавай их. Нюансов то вообще нет, а клиентов просто тьма тьмущая. Сейчас точно могу сказать — ЭТО НЕ ТАК.
Мы решили, что в нашу crm’ку тоже нужно добавить парсер недвижимости, а то 2 из 3 людей просят парсер. Вроде бы и опыт есть уже, и скрипт писали. Провели опрос среди наших клиентов, собрали список самых приоритетных задач (это же бизнес нам сказал, что важно и полезно, как можно бизнесу то не верить), погнали разрабатывать. По срокам реализации посчитали около 1 месяца кропотливой работы.
Далее я постараюсь описать таймлапс, по которому можно будет понять этапы разработки. Сразу говорю — точного ТЗ у нас нет, мы сами придумываем процесс и пытаемся его автоматизировать. Ни один клиент не смог нам рассказать все нюансы своей работы, т. к описать процесс в хоть сколь-нибудь адекватном виде является невозможной мукой.
1-я стадия MVP
Мы спарсили 3 сайта. На крон навесили задание, которое каждый день собирает инфу в одну большую базу для нашего города. Проработало 3 дня.
Список полученных проблем:
Забанили IP, по которому мы парсили. Пришлось купить прокси. Добавили просто массив в код с логинами паролями. (Да да, мы как неумелые люди взялись парсить напрямую с сервера, не плюйте только)
Скрипт может оборваться и перестать работать. Нужно понимать что мы спарсили, а что нет для его возобновления. Стали складывать в базу по урлам со статусами Успех, Не успех, Успех с ошибками.
Надо распарсить строку с адресом и положить к нам в систему. У нас под капотом кладр, который четко вписан в общую концепцию. А на сайтах просто строка. Долго искали адекватное решение, решили использовать сторонний сервис для распознавания строк.
Параметры не бьются на сайтах с нашими. У нас в системе определенные списки с параметрами, например с ремонтами. А тут с какого-то сайта вылазит ремонт с типом Хороший, Красивый, Нежный, Мягкий. Куда его присоединять? Пришлось извращаться и писать алгоритм соединения для каждой площадки отдельно.
2-я стадия полной переработки
Вроде бы работает MVP. Но тут видим, что 80% запросов отдаёт ошибку. Оказывается, что все сайты внедрили систему для распознавания ботов и парсинга. Полезли в интернет и на то время нашли Selenium. Пришла пора полного переписывания проекта.
Мы ставим 3 месяца проект на новые лыжи, с php на python. Прошли десятки бессонных ночей, но мы не могли добиться адекватного сбора данных. Все сайты постоянно банили запросы, а сам селениум из себя представлял один огромный костыль, который переписывается всеми, кому не лень. На гите можно найти тысячи форков, которые сверху реализации набрасывают свои костыли. На этой стадии мы хотели бросить проект т. к отказоустойчивости не было никакой. и мы не могли обещать качественный сервис своим клиентам.
Через 2 месяца всевозможных тестов у нас получился вроде бы рабочий парсер. Но снова возникли проблемы.
Список новых проблем:
Кривая архитектура синхронных запросов. Никогда не делайте синхронные запросы для таких больших проектов! Нам пришлось поднять RabbitMQ для разграничения по очередям запросов. Отдельно для каждой площадки, для каждой категории недвижимости. Это было очень сложная задача, за 2 месяца плюс минус управились. Но теперь у нас много воркеров, которые могут параллельно смотреть новые объекты по каждой категории.
Нам нужно обновлять старые объекты. Несколько клиентов одновременно начали просить архив за прошлые месяцы. Они хотели видеть все изменения по цене и параметрам. Объявление удалилось с сайта — должно пропасть и у нас. Решили отдельно создать очередь для таких объектов. Даже выставили приоритетность обновления. Пример: скачали объект, после через час проверили его на актуальность, далее через день, далее через 3 дня и там уже раз в неделю.
Из 2 проблемы пришла другая — постоянное накопление архива и увеличение количества объектов для парсинга. Архив копится, лавэха не мутится, ресурсы утилизируются, терпение кончается. Это самое узкое место на сегодняшний день, т. к мы не смогли найти решения, кроме как увеличить количество серверов, проксей и т. д
3-я стадия разработки
Один за одним сайты начали банить прокси. Мы начали анализировать и пришли к следующему списку проблем и решений.
Новые проблемы:
Бан одновременных прокси. Нельзя было обращаться в одно и то же время с одной прокси разными воркерами. Т. е мы не можем загружать 5 страниц с разных браузеров с одного ip одновременно, это распознается как парсер страницы сторонними средствами. Пришлось внедрять ротацию проксей, чтобы она занималась и отдавалась по времени.
Воркеры могли зависнуть. Можно было попасть в тот в момент недоступности прокси, либо браузер просто зависал и т. д Проблем с этим куча и они решились только перезапуском воркеров по таймауту. Грязное, но рабочее решение.
Прокси стали банить на долгое время. У нас кончилось 150 проксей. Просто все было заблочено на некоторых сайтах на неделю. Решение было найдено благодаря Максиму Кульгину, за что ему огромное спасибо. Мы стали использовать мобильные прокси. Да, это дорого. Но это того стоит. Получилось побороть полный бан по ip.
С увеличением количества площадок и сайтов стали кончаться ресурсы. Представьте запускать 30 гугл хромов одновременно. Процессоры не вывезут, память кончится и всё станет колом. Решение простое — увеличение серверов. На данный момент мы тратим около 50 тысяч на сервера в месяц. Но это мы только в начале этого сложного пути.
На данный момент мы решаем такие нюансы, как:
Парсер сайтов Казахстана. Нашли там коллег и выходим на их рынок. Там просто огромная проблема с адресами и отсутствием стандартизации всего и вся.
Увеличение доступных площадок и городов. Все упирается в серверные ресурсы и деньги.
Несколько месяцев назад к нам пришёл клиент, который попросил дать ему парсер, который будет в режиме реального времени собирать объявления с 20 сайтов и выводить в онлайн-форму. Он подключит колл-центр и будет обзванивать продавцов. Главное правило — объявление должно появиться в системе не более, чем через 5 секунд после публикации на сайте. Вы вообще представляете объёмы работы? На опыте я могу сказать, что это либо невозможно, либо очень дорого. Ну и заплатить он был готов не более 50 тысяч рублей т.к "на том же кворке такое же делают за 5к парочка студентов". До сих пор видимо никого не нашёл.
Технические дополнения
Отвечаю на комментарий по технической реализации.
Что делали после Selenium? - Selenium мы убрали из своей разработки полностью. Перешли на Playwright из-за его скорости и хорошей доки. Есть хороший сайт https://bot.sannysoft.com/ - можно проанализировать, как распознается ваш браузер. Если что-то горит красным - значит это автоматический браузер, который будет забанен после нескольких запросов к сайту. На Selenium мы не смогли добиться всех успешных тестов, а Playwright с некоторой долей магии смог успешно справиться с этим (на него надо ставить патчи, на гите лежат в отрытом доступе).
Как боролись с Cloudflare? - Ответ всё тот же - использовали браузер. Если правильно написать логику переходов, то система будет ждать полной загрузки страницы и после попытается собрать инфу.
Сталкивались ли с банами по подсетям? - По подсетям не сталкивались, т.к пытаемся не дудосить сайты огромным количеством запросов с одного ip. Для этого и придумали ротацию проксей + большое количество покупных проксей. Очень выручают мобильные прокси, для этого мы даже собрали свою мобильную ферму. Постараюсь техническую реализацию написать позже в отдельную статью.
А бан по геолокации? - После начала СВО очень много российских сайтов не открываются из под зарубежных проксей. Аналогично сайты в Казахстане часто банят прокси из России. Здесь помогает только покупка проксей с нужной гео. Мы берем пачками с разных сервисов со всех уголков страны.
Что делали с телефонами под авторизацией? - В начале пытались регистрировать десятки аккаунтов, запоминать куки и т.д. Но сейчас все сайты ввели IP-Телефонию и мы отказались от парсинга номеров в принципе. Временный номер постоянно меняется и смысла собирать архив с номерами нет. Запоминаем ссылку на страницу - пользователь сам перейдёт и позвонит куда надо. Вообще хороший вариант, чтобы клиенты сами обзванивали и писали в базу настоящие номера. Но мы таким не занимаемся.
Как парсим? - BeautifulSoup на Python. Каждый сайт является своей небольшой загадкой. Где-то приходится лезть в нутро библиотек и заниматься реверс-инжинирингом, а где-то всё лежит на поверхности. Так что нельзя сказать про один конкретный подход, всё полностью индивидуально. Но весь парсинг мы стараемся делать на Playwright. Зато мы столько кеков и мемов увидели в коде, что можно поэму написать. Очень понравились ребята с Домклика, они отдают данные в методах очень классно, аля 'Упс, а как ты сюда попал? Приходи к нам на работу, писать вот на эту почту'.
Заключение
Вроде бы есть понятная задача бизнеса, которая по статьям из интернета решается за пару дней. Но она имеет такой огромный айсберг проблем, о котором без опыта ты даже не сможешь догадаться.
Проблемы не кончаются никогда. Это закон бизнеса. Мы стараемся сделать продукт таким, чтобы он был удобным, быстрым и безотказным. У меня просто совести не хватит продавать то, от чего ты не получишь душевного экстаза.
Буду рад любой обратной связи. Мы умеем парсить всё, до чего дойдут руки. Пишите , поболтаем :-)
P.S. Никакого парсинга персоналки, данных под авторизацией и незаконной инфы. Я ещё молод, чтобы сидеть.
Пока писал текст - нашёл багу.
https://t.me/itpriton — я тут пишу периодически о бизнесе и всяком интересном. Заходите, поболтаем.
Комментарии (47)
9982th
18.12.2023 02:56Самое интересное и не рассказали: что вы делали когда Selenium закончился?
Как боролись с Cloudflare и прочей рекапчей? Сталкивались ли с банами по принадлежности подсети к датацентру? А по геолокации? Что делали с данными вроде телефона продавца, которые отображаются только для залогиненных пользователей? Что парсите, html или какое-то представление DOM? Чем парсите, lxml, суп или что-то еще? Как парсите, CSS-селекторы, xpath, регулярки?cry_san
18.12.2023 02:56А как может Selenium закончиться? Используем фермы с распределением по серверам. Для примера https://www.selenium.dev/documentation/grid/getting_started/
9982th
18.12.2023 02:56Selenium заканчивается когда защита начинает его детектировать и отказывается пропускать дальше. Начиная с проверки
navigator.webdriver
и далее кто на что горазд.
Robastik
18.12.2023 02:56Речь скорее всего о том, что Selenium стал детектиться на том сайте, который парсит автор вопроса. Или вообще современный антибот поставили, который на одном Selenium не объедешь.
Robastik
18.12.2023 02:56Как боролись с Cloudflare
Нет универсальных решений. Cloudflare - это 100500 настроек.
Что делали с данными вроде телефона продавца, которые отображаются только для залогиненных пользователей?
Если про упомянутый автором Авито, то это не так. Нужно просто кликнуть "Показать телефон", логин не нужен.
Как парсите, CSS-селекторы, xpath, регулярки?
Конкретно на Авито все данные лежат в json в переменной initialData. На блюдечке с голубой каемочкой.
zergon321
18.12.2023 02:56Вы по факту вступили в гонку вооружений с теми сайтами, которые пытались парсить. Гонка вооружений - это всегда беспредельное пожирание денег, времени и т.д. Гонка вооружений стала одним из факторов развала СССР. У вас точно нет для этой гонки такого количества ресурсов, как у тех, кого вы парсите. Либо у вас/заказчика такая гонка попросту не окупится
Sector911 Автор
18.12.2023 02:56Да вы правы, мы будем постоянно не успевать за новыми средствами защиты. Как борьба с мельницами.
Robastik
18.12.2023 02:56Очень дискуссионное заявление. Арсенал защиты от парсинга крайне мал.
zergon321
18.12.2023 02:56Я как-то хотел накачать материалов с e-hentai. Там, чтобы качать самому беспрепятственно, надо донатить или самому что-то заливать. Я написал парсер. В итоге меня начали банить по IP. Я начал раздумывать о том, как мне 100% обойти их защиту. В итоге пришёл к тому, что ради этого мне придётся арендовать несколько виртуалок и распределять по ним все запросы по скачиванию отдельных картинок, а потом все их вместе собирать как-то обратно в сеты. В общем, я понял, что оно того не стоит. Арсенал, быть может, и мал, но его хватает
cry_san
18.12.2023 02:56Посмотрите в сторону открытого проекта
https://github.com/KurtBestor/Hitomi-Downloader
ваш сайт там тоже есть
shornikov
18.12.2023 02:56Достаточно слегка менять структуру странички, чтобы коэффициент затрат времени был 10 к 1 не в пользу парсера.
потратить 2-3 дня, сделать с пяток шаблонов, стили, id поставить переменными и выбирать рандомный шаблон при отдаче клиенту. В таком случае - если ты только сел парсить сайт - быстренько сойдешь с ума и плюнешь на это дело, ибо закономерностей не видно.
А уж специализированные средства... (Robastik
18.12.2023 02:56SSR сайтов совсем не много и данные получать очень просто. Посмотрите мои парсеры - там так много второстепенной информации как раз потому, что отфильтровать лишнее сложно и просто выкатываю весь доступный джейсон.
А в случае SSR структура меняется довольно редко и если не стрелять себе регулярками по ногам, то селекторы работают вполне надёжно.
Robastik
18.12.2023 02:56пришлось поднять RabbitMQ для разграничения по очередям запросов. Отдельно для каждой площадки, для каждой категории недвижимости. Это было очень сложная задача
Для названных вами объемов может подойти Firebase RTDB. Для каждой категории писать очередь в свой /тред, читать первый по sort by timestamp. Вряд ли дороже аренды сервера, а выглядит проще некуда.
Oceanshiver
18.12.2023 02:562023 год. Продуктовая команда разработчиков ВДРУГ узнала, что парсинг сайтов - это сложно. Ясно-понятно.
zloddey
18.12.2023 02:56Да, и что между одноразовой задачей и долговременной поддержкой/развитием продукта есть такая мааааленькая разница.
Rumantic
18.12.2023 02:56В демо-версии в списке агентств я насчитал 40 агентств, это у вас столько клиентов?
Если посчитать по тарифам, то затраты 50 к на сервер окупаются?
И насколько пользуются спросом другие функции системы? Воронки, сделки и прочее.
Сам давно занимаюсь автоматизацией агентств недвижимости и сложилось впечатление, что риэлторам плевать на автоматизацию и прочие ништяки, им главное дозвониться до клиента быстрее конкурента, а дальше включать харизму.
nlog
18.12.2023 02:56Если представить эту задачу как этап собеседования в виде system design в крупную IT-компанию, то асинхронная архитектура, распределение задач по воркерам и учёт URL были бы ожидаемы для миддл разработчика. В течение 45-минутного собеса.
SirHole
18.12.2023 02:56Adspower антик позволяет управлять браузером через puppeteer, при этом каждый раз создавать браузер с уникальным фингерпринтом. Для тестов там даже бесплатного тарифа за глаза хватит.
SSukharev
18.12.2023 02:56С опытом "простых" задач будет асе меньше, а "сложных" все больше. И желание браться за подобное будет отбито напрочь.
kochetovdv
18.12.2023 02:56Мы в свое время, еще до gpt-бума, пошли через ml и конкретно nlp. Проще натренировать нейронку на извлечение данных и понимание сути спарсенного, чем постоянно гнаться за различными переделками каталогов у множества ресурсов.
Как пример - электротехническая и кабельная продукция. Один и тот же кабель может называться абсолютно по-разному у разных поставщиков, хотя по характеристикам схож.
Нейронка это понимает и складирует куда надо сама. После реализовали даже вывод в 1С поставщиков для их категорийных менеджеров, чтобы им было удобнее сравнивать себя с конкурентами и подаваться в тендеры.
Таким образом, часть задачи решаема просто иным путем.
Но на счет банов, прокси и прочего - проблемы схожие, хотя сложности обходяться, как выше в комментариях указали.
eugenk
Привет ребят. Постараюсь немного помочь, я сам когда-то решал подобную задачу. Хотя и не для объявлений, а для скачивания данных с сайта избиркома, ради статистического исследования результатов выборов. Проблема была в том, что УИКов(участковых избирательных комиссий) в России чуть меньше 100 тысяч, и на каждую из них уходит по меньшей мере 3 http-запроса. Вот и посчитайте, сколько всё это будет работать, если каждый запрос занимает 2 секунды (и это ещё хорошо !). А сайт пускает только два запроса с одного ip-адреса.
Во-первых я пошел немного другим путём, чем вы. Не стал покупать прокси. Дело в том, что в сети полно сайтов, публикующих списки свободных прокси. У них есть API, разумеется платный. Но есть и html-странички. Разумеется защищенные, распарсить их надо ещё суметь. Зато это даёт ТЫСЯЧИ и ДЕСЯТКИ ТЫСЯЧ прокси. На халяву. Против ваших 150 за деньги.
Во-вторых не понял, зачем вам сервера ??? Всё прекрасно работает на локальной машине. Наверно вы начинали с php, и оно замылило вам глаза. Я начинал с экспериментов на питоне, а боевой код писал на java. Весь сайт избиркома в итоге качался в базу данных sqlite за 3 часа. Можно было бы и быстрее, но начинал слегка подтормаживать ноутбук.
В третьих по организации кода. Код ОБЯЗАТЕЛЬНО (!!!) должен быть модульным. С выделенным модулем парсинга. Который получает выкачанный html и выдирает из него нужную информацию, которую куда-то в свою очередь отправляет (в базу данных например). Дело в том что ад любого парсера - это изменения в верстке. И должна быть заранее предусмотрена возможность достаточно безболезненно эту проблему решать, затрагивая как можно меньше кода. Кроме того должна быть предусмотрена возможность раздельной работы на разных компьютерах, со слиянием полученных баз данных в одну. У меня это тоже было предусмотрено, хотя и не использовалось. Этим решается проблема масштабирования.
Вот примерно так. Надеюсь был вам полезен. Ну и наконец можете почитать пару моих живых статей (в формате ipynb) на эту тему https://github.com/Karabass-Barabass/FreeProxy/tree/master . Они несколько не окончены и в конце там какое-то количество мусора. Но читать это не мешает. Хотел опубликовать на хабре, да не решился. Ибо тема довольно скользкая.
Sector911 Автор
Спасибо, обязательно ознакомлюсь.
Sector911 Автор
Если вы хотите продуктовый подход - одна машина явно не подойдёт, тем более личный ноут. Вы видимо не понимаете нагрузку и сложность парсинга в принципе.
Давным давно все бесплатные прокси попадают в бан у нормальных систем борьбы с парсингом. Тут главное же безотказность и скорость работы. Мы можем парсить около 100 тысяч сообщений в день, при этом нагрузка очень большая, чаще всего на cpu. В лоб уже давно никто не парсит, обычным запросом с какого-нибудь php. Все через браузер, имитацию работы настоящего юзера и т.д.
eugenk
Не понял, чем с точки зрения сервера браузер отличается от какого-то левого скрипта ??? Если скрипт отправляет разумные заголовки, имитирующие браузер, выполняет тестовые задания на джаваскрипте, и т.п, отличить его от браузера невозможно. А ресурсов он занимает несравненно меньше чем тот же хром. Насчет того что все бесплатные прокси давно уже в бане - не знаю. Надо смотреть. Однако на первый взгляд сомнительно. Ибо бесплатные прокси много где используются. И их бан может резко ограничить трафик на сайт. Однако ещё раз, надо смотреть. Ну и с производительностью - 100 тысяч, это смешно. Мой парсер сайта избиркома парсил 300 тысяч часа за три. На обычном ноутбуке, даже не сильно навороченном.
P.S. Если хотите, могу поискать тот свой код на java. Правда писалось это в 18-м году под президентские выборы, причем писалось второпях и довольно грязно. Но работало отлично.
Sector911 Автор
Под капотом у системы распознавания как раз много алгоритмов, которые понимают бот ты или человек. Нужна имитация настоящего поведения. Не запросы. Просто попробуйте спарсить для примера озон (только ради науки) и посмотрите список возникающих проблем.
eugenk
Я и не говорю что всё просто ! Но уверен, что всё решаемо. Разумеется гляну на озон, спасибо за интересную наводку !
cry_san
Чаще всего, данные на странице формируются через JavaScript. Простыми запросами вы эти данные не увидите, - только через браузер.
eugenk
Не думаю чтобы это представляло собой совсем уж неразрешимую проблему. Есть node.js. Прикрутить к нему нечто, имитирующее работу библиотеки dom, задача хоть и большая, но думаю вполне решаемая. Впрочем с джаваскриптом я сталкивался лишь однажды. Да и то не с dom, а с небольшим арифметическим примером, который надо было выполнить. Что легко делалось с помощью node.js
cry_san
Я и не говорил, что это большая проблема )
Все зависит от технологий, которые вы используете. Можно даже и не имитировать поведение пользователя как такового. Брать хеш реального пользователя с его браузером и скармливать его голому селениуму.
calculator212
Но зачем это делать, когда есть уже куча готовых инструментов с готовыми примерами, туториалами, документацией? Если для поупражняться для себя, то нормально, но если брать случай из статьи, то в разы надежнее и дешевле взять готовые либы, которых сейчас много и которые будут поддерживаться.
eugenk
Да наверняка есть. Я просто не особо в курсе, ибо постоянно этим не занимался, и рассуждаю для худшего случая. А так безусловно готовые либы рулят :))))
cry_san
Можно пару примеров?
aamonster
На ноде вам для начала придётся написать DOM – хотя бы для того, чтобы получить со страницы скрипты, которые надо выполнять. А потом будете натыкаться на несоответствия с поведением браузера и писать костыли для их обхода. В то время как есть headless браузеры – которые ведут себя, как браузеры, просто не рендерят картинку.
cry_san
Собираю продавцов на Озон. Конечно, данные собираю через браузер, но не через открытие страницы товара. Нужные данные идут по API через GET. Просто открываю эти ссылки в браузере. Проблем нет.
Sector911 Автор
Я просто пример привёл, каждую площадку можно смотреть индивидуально. Порой апи намного проще использовать.