Web scraping вашего сайта: непрошеные гости и как их встречают

    На первом в истории полностью виртуальном мероприятии РИТ++, прошедшем в конце мая, инженер Qrator Labs — Георгий Тарасов, рассказал публике про веб-скрейпинг, он же парсинг, популярным языком. Мы решили предоставить вашему вниманию транскрипцию выступления. Видео в конце публикации.



    Всем привет! Наша компания достаточно давно занимается проблематикой защиты от DDoS-атак, и в процессе этой работы мне удалось достаточно подробно познакомиться со смежными сферами — изучить принципы создания ботов и способы их применения. В частности — web scraping, то есть массовый сбор публичных данных с веб-ресурсов с использованием ботов.

    В какой-то момент эта тема меня необычайно увлекла многообразием прикладных задач, в которых скрейпинг с успехом используется. Здесь надо отметить, что наибольший интерес для меня представляет «темная сторона» веб-скрейпинга, то есть вредные и плохие сценарии его использования и негативные эффекты, которые он может оказать на веб-ресурсы и бизнес, с ними связанный.

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



    Я буду рассказывать о следующем:

    • Зачем вообще люди друг друга скрейпят;
    • Какие есть виды и признаки такого скрейпинга;
    • Какое влияние он оказывает на целевые веб-сайты;
    • Какие средства и технические возможности используют создатели ботов, чтобы заниматься скрейпингом;
    • Как разные категории ботов можно попробовать обнаружить и распознать;
    • Как поступить и что делать, если скрейпер пришел в гости на ваш сайт (и нужно ли вообще что-то делать).

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

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

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

    Давайте подумаем — сделали ли вы кому-нибудь в процессе плохо? Ну, если только вы не парсили HTML регулярным выражением, то скорее всего никому плохо вы не сделали, а тем более сайтам, на которые вы таким образом сходили. Это однократная деятельность, ее можно назвать скромной и незаметной, и вряд ли кто-то пострадал от того, что вы пришли, быстро и незаметно схватили необходимый вам кусочек данных.

    С другой стороны — будете ли делать это снова, если все получилось в первый раз? Давайте признаемся — скорее всего, будете, потому что вы только что сэкономили кучу времени и ресурсов, получив, скорее всего, даже больше данных, чем изначально рассчитывали. И это не ограничивается только научными, академическими или общеобразовательными изысканиями.



    Потому что информация стоит денег, а вовремя собранная информация стоит еще больших денег. Именно поэтому скрейпинг является серьезной статьей заработка для большого количества людей. Это популярная тема на фрилансе: зайдите и увидите кучу заказов с просьбой собрать те или иные данные или написать скрейпинговый софт. Также есть коммерческие организации, занимающиеся скрейпингом на заказ или предоставляющие платформы для этой активности, так называемый scraping as a service. Такое многообразие и распространение возможно, в том числе и потому, что скрейпинг сам по себе чем-то нелегальным, предосудительным, не является. С правовой точки зрения к нему очень трудно придраться — особенно на текущий момент, мы скоро узнаем почему.



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



    С точки зрения правовых аспектов, ситуация, которую мы сейчас рассматриваем — с дозволенностью скрейпинга, не всегда была такой ранее. Если мы немного посмотрим на хронологию достаточно хорошо известных судебных исков, связанных со скрейпингом, то увидим, что еще на его заре первым иском была претензия компании eBay к скрейперу, который собирал данные с аукционов, и суд запретил ему заниматься этой деятельностью. Дальнейшие 15 лет статус-кво более-менее сохранялся — крупные компании выигрывали суды против скрейперов, когда обнаруживали их воздействие. Facebook и Craigslist, а также некоторые другие компании отметились исками, закончившимися в их пользу.

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

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

    Посмотрим на несколько знаковых примеров.



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

    Если мы немножечко здесь включим воображение и подумаем в соседнюю сторону — что если этим занимается не наш конкурент, а злоумышленник? Такая копия сайта может хорошо пригодиться чтобы, для примера, затребовать с посетителя предоплату, или просто предложить ввести данные платежной карты. Дальнейшее развитие событий вы можете представить самостоятельно.



    Другой интересный случай скрейпинга это скупка товаров ограниченной доступности. Производители спортивной обуви, такие, как Nike, Puma и Reebok, периодически запускают кроссовки лимитированных и т.н. сигнатурных серий — за ними охотятся коллекционеры, они находятся в продаже ограниченное время. Впереди покупателей на сайты обувных магазинов прибегают боты и сгребают весь тираж, после чего эти кроссовки всплывают на сером рынке с совершенно другим ценником. В свое время это взбесило вендоров и ритейл, который их распространяет. Уже 7 лет они борются со скрейперами и т.н. сникер-ботами с переменным успехом, как техническими, так и административными методами.



    Вы наверняка слышали истории, когда при онлайн покупке требовалось лично прийти в магазин кроссовок, или про honeypot с кроссовками за $100k, которые бот скупал не глядя, после чего его владелец хватался за голову — все эти истории находятся в этом тренде.



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

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



    Один из примеров из нашей практики у одного из клиентов. Скрейпер пришел на локацию с параметризованным поиском, который является одной из самых тяжелых операций в бэкенде рассматриваемой структуры. Скрейперу понадобилось перебрать достаточно много поисковых запросов, и он из 200 RPS к этой локации сделал почти 700. Это серьезно нагрузило часть инфраструктуры, из-за чего пошла деградация качества сервиса для остальных легитимных пользователей, взлетело время ответа, посыпались 502-е и 503-и ошибки. В общем, скрейпера это ничуть не волновало и он сидел и делал свое дело, пока все остальные судорожно обновляли страничку браузера.

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



    Но, помимо DDoSа, у скрейпинга есть еще интересные соседи из сферы киберпреступности. Например, перебор логинов-паролей использует похожую техническую базу, то есть с помощью тех же самых скриптов это можно делать с упором на скорость и производительность. Для credential stuffing используют наскрейпленные откуда-то пользовательские данные, которые засовываются в поля форм. Ну и тот пример с копированием контента и выкладыванием его на похожих сайтах — это серьезная подготовительная работа для того, чтобы подсовывать фишинговые ссылки и заманивать ничего не подозревающих покупателей.



    Для того чтобы понять как разные варианты скрейпинга могут с технической точки зрения повлиять на ресурс попробуем посчитать вклад отдельных факторов в эту задачу. Займемся некоторой арифметикой.



    Представим, что у нас справа куча данных, которые нам нужно собрать. У нас есть задача или заказ выгрести 10 000 000 строчек товарных позиций, ценники например или котировки. И в левой части у нас есть бюджет времени, так как завтра или через неделю эти данные заказчику будут уже не нужны — они устареют, придется собирать их снова. Поэтому нужно уложиться в некоторый таймфрейм и, используя собственные ресурсы, сделать это оптимальным образом. У нас есть некоторое количество серверов — машин и айпи-адресов, за которыми они находятся, с которых мы будем ходить на интересующий нас ресурс. У нас есть некоторое количество инстансов пользователей, которыми мы прикидываемся — есть задача убедить онлайн-магазин или некоторую публичную базу в том, что это разные люди или разные компьютеры ходят за какими-то данными, чтобы у тех, кто будет анализировать логи, не возникало подозрений. И у нас есть некоторая производительность, интенсивность запросов, с одного такого инстанса.

    Понятно, что в простом кейсе — одна хост-машина, студент с ноутбуком, перебирающий Washington Post, будет сделано большое количество запросов с одними и теми же признаками и параметрами. Это будет очень хорошо заметно в логах, если таких запросов будет достаточно много — а значит найти и забанить, в данном случае по айпи адресу, легко.

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

    Если мы продолжаем в эту же сторону, то у нас появляется возможность в рамках этого же уравнения уменьшать интенсивность запросов с каждого такого инстанса — делая их более редкими, более эффективно их ротируя, чтобы запросы от одних и тех же пользователей не попадали рядом в логи, не вызывая подозрений и будучи похожими на конечных (легитимных) пользователей.

    Ну и есть граничный случай — у нас в практике один раз был такой кейс, когда к заказчику пришел скрейпер с большого количества IP-адресов с совершенно разными признаками пользователей за этими адресами, и каждый такой инстанс сделал ровно по одному запросу за контентом. Сделал GET на нужную страничку товара, спарсил ее и ушел — и больше ни разу не появлялся. Такие кейсы довольно редки, так как для них нужно задействовать бóльшие ресурсы (которые стоят денег) за то же самое время. Но при этом отследить их и понять, что кто-то вообще приходил сюда и скрейпил, становится намного сложнее. Такие инструменты для исследования трафика, как поведенческий анализ — построение паттерна поведения конкретного пользователя, сильно усложняются. Ведь как можно делать поведенческий анализ, если нет никакого поведения? Нет истории действий пользователя, он ранее никогда не появлялся и, что интересно, больше с тех пор тоже ни разу не пришел. В таких условиях, если мы не пытаемся на первом же запросе что-то сделать, то он получит свои данные и уйдет, а мы останемся ни с чем — задачу по противодействию скрейпингу мы здесь не решили. Поэтому единственная возможность — это по первому же запросу догадаться, что пришел не тот, кого мы хотим видеть на сайте, и отдать ему ошибку или другим способом сделать так, чтобы он свои данные не получил.

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



    Первичная, самая простая категория, с которой большинство читателей знакомы — это скриптовый скрейпинг, использование достаточно простых скриптов для того, чтобы решать относительно сложные задачи.



    И данная категория является, пожалуй, самой популярной и подробно задокументированной. Даже сложно порекомендовать, что конкретно читать, потому что, реально, материала море. Куча книжек написана по этому методу, есть масса статей и публикаций — в принципе достаточно потратить 5 / 4 / 3 / 2 минуты (в зависимости от нахальства автора материала), чтобы спарсить свой первый сайт. Это логичный первый шаг для многих, кто начинает в веб-скрейпинге. “Starter pack” такой деятельности это чаще всего Python, плюс библиотека, которая умеет делать запросы гибко и менять их параметры, типа requests или urllib2. И какой-нибудь HTML-парсер, чаще всего это Beautiful Soup. Также есть вариант использовать либы, которые созданы специально для скрейпинга, такие, как scrapy, которая включает в себя все эти функциональности с удобным интерфейсом.

    С помощью нехитрых трюков можно прикидываться разными девайсами, разными пользователями, даже не имея возможности как-то масштабировать свою деятельность по машинам, по айпи адресам и по разным аппаратным платформам.



    Для того чтобы сбить нюх у того, кто инспектирует логи на стороне сервера, с которого собираются данные, достаточно подменять интересующие параметры — и делать это нетрудно и недолго. Посмотрим на пример кастомного лог-формата для nginx — мы записываем айпишник, TLS-информацию, интересующие нас хедеры. Здесь, конечно, не все, что обычно собирается, но данное ограничение необходимо нам для примера — посмотреть на подмножество, просто потому что все остальное еще проще «подкинуть».

    Для того, чтобы нас не банили по адресам, мы будем использовать residential proxy, как их называют за рубежом — то есть, прокси с арендованных (или взломанных) машин в домовых сетях провайдеров. Понятно, что забанив такой айпи адрес, есть шанс забанить какое-то количество пользователей, которые в этих домах живут — а там вполне могут оказаться посетители вашего сайта, так что иногда делать такое себе дороже.

    TLS-информацию также не сложно подменить — взять наборы шифров популярных браузеров и выбрать тот, который понравится — наиболее распространенный, или ротировать их периодически, для того чтобы представляться разными устройствами.

    Что касается заголовков — referer с помощью небольшого изучения можно выставлять такой, какой понравится скрейпленному сайту, а юзерагент мы берем от Chrome, или Firefox, чтобы он ничем не отличался от десятков тысяч других юзеров.

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



    Сравнение параметров запроса, заголовков, айпи адреса друг с другом и с публично известными позволяет отлавливать самых наглых скрейперов. Простой пример — к нам пришел поисковой бот, но только IP у него почему-то не из сети поисковика, а из какого-нибудь облачного провайдера. Даже сам Гугл на странице, описывающей Googlebot, рекомендует делать reverse lookup DNS-записи для того, чтобы убедиться, что данный бот реально пришел с google.com или других валидных ресурсов Гугла.

    Таких проверок бывает много, чаще всего они рассчитаны на тех скрейперов, которые не заморачиваются фаззингом, какой-то подменой. Для более сложных кейсов есть более надежные и более тяжеловесные методы, например подсунуть этому боту Javascript. Понятно, что в таких условиях борьба уже неравная — ваш питоновский скриптик не сможет выполнить и интерпретировать JS-код. Но это может сделать автор скрипта — если у автора бота есть достаточно времени, желания, ресурсов и навыка, чтобы пойти посмотреть в браузере, что делает ваш Javascript.

    Суть проверок в том, что вы интегрируете скрипт в вашу страницу, и вам важно не только то, чтобы он выполнился — а еще чтобы он продемонстрировал какой-то результат, который обычно POST’ом отправляется обратно на сервер перед тем, как на клиента высыпется контент, и сама страничка загрузится. Поэтому, если автор бота решил вашу загадку и захардкодит правильные ответы в свой питоновский скрипт, либо, к примеру, поймет, где ему нужно парсить сами строки скрипта в поисках нужных параметров и вызываемых методов, и будет вычислять ответ у себя — он сможет обвести вас вокруг пальца. Вот, в качестве примера.



    Я думаю, что некоторые слушатели узнают этот кусочек javascript'a — это проверка, которая раньше была у одного из самых крупных облачных провайдеров в мире перед доступом к запрашиваемой странице, компактная и очень простая, и в то же время без ее изучения так просто на сайт не пробиться. При этом, применив чуть-чуть усилий, мы можем попросить страницу в поисках интересующих нас JS-методов, которые будут вызываться, от них, отсчитав, найти интересующие нас значения, которые должны быть вычислены, и всунуть себе в код вычисления. После не забыть несколько секунд поспать из-за задержки, и вуаля.



    Мы попали на страницу и дальше можем парсить то, что нам нужно, потратив не больше ресурсов, чем на создание самого нашего скрейпера. То есть с точки зрения использования ресурсов нам ничего дополнительного для решения таких задач не нужно. Понятно, что гонка вооружений в этом ключе — написание JS-челленджей и их парсинг и обход сторонними средствами — ограничивается только временем, желанием и навыками автора ботов и автора проверок. Эта гонка может длиться довольно долго, но в какой-то момент большинству скрейперов это становится неинтересно, ведь есть более интересные варианты с этим справиться. Зачем сидеть и парсить JS-код у себя в Python, если можно просто взять и запустить браузер?



    Да, я говорю в первую очередь о headless-браузерах, потому что этот инструмент, изначально создававшийся для тестирования и Q&A, оказался идеально подходящим для задач веб-скрейпинга на текущий момент.



    Не будем вдаваться в подробности по headless-браузерам, я думаю, что большинство слушателей о них и так знает. Оркестраторы, которые автоматизируют работу headless-браузеров, претерпели довольно бодрую эволюцию за последние 10 лет. Сначала, в момент возникновения PhantomJS и первых версий Selenium 2.0 и Selenium WebDriver, работающий под автоматом headless-браузер было совсем не трудно отличить от живого пользователя. Но, с течением времени и появлением таких инструментов, как Puppeteer для headless Chrome и, сейчас, творение господ из Microsoft — Playwright, которое делает то же, что и Puppeteer но не только для Хрома, а для всех версий популярных браузеров, они все больше и больше приближают «безголовые» браузеры к настоящим с точки зрения того, насколько их можно сделать с помощью оркестрации похожими по поведению и по разным признакам и свойствам на браузер здорового человека.



    Для того чтобы заниматься распознаванием headless’ов на фоне обычных браузеров, за которыми сидят люди, как правило, используются те же самые javascript’овые проверки, но более глубокие, подробные, собирающие тучу параметров. Результат этого сбора отправляют обратно либо в средство защиты, либо на сайт, с которого скрейпер хотел забрать данные. Эту технологию называют fingerprinting, потому что собирается настоящий цифровой отпечаток браузера и девайса, на котором он запущен.

    Вещей, на которые смотрят JS-проверки при фингерпринтинге, довольно много — их можно разделить на некоторые условные блоки, в каждом из которых копание может продолжаться до плюс бесконечности. Свойств действительно очень много, какие-то из них легко спрятать, какие-то менее легко. И здесь, как и в предыдущем примере, очень многое зависит от того, насколько дотошно скрейпер подошел к задаче сокрытия торчащих «хвостов» безголовости. Есть свойства объектов в браузере, которые подменяет по умолчанию оркестратор, есть та самая property (navigator.webdriver), которая выставляется в headless’ах, но при этом ее нет в обычных браузерах. Ее можно спрятать, попытку спрятать можно задетектировать, проверив определенные методы — то что проверяет эти проверки, тоже можно спрятать и подсовывать фальшивый output функциям, которые распечатывают методы, например, и до бесконечности это может длиться.

    Другой блок проверок, как правило, отвечает за изучение параметров окна и экрана, которых у headless-браузеров по определению нет: проверка координат, проверка размеров, какой размер у битой картинки, которая не отрисовалась. Есть масса нюансов, которые человек, хорошо знающий устройство браузеров, может предусмотреть и на каждый из них подсунуть правдоподобный (но ненастоящий) вывод, который улетит в проверки fingerprint’а на сервер, который будет его анализировать. Например, в случае отрисовки средствами WebGL и Canvas каких-то картинок, 2D и 3D, можно полностью весь вывод взять готовый, подделать, выдать в методе и заставить кого-то поверить в то, что что-то действительно нарисовалось.

    Есть более хитрые проверки, которые происходят не одномоментно, а допустим, JS-код покрутится какое-то количество секунд на странице, или будет вообще постоянно висеть и передавать какую-то информацию на сервер с браузера. К примеру, отслеживание положения и скорости движения курсора — если бот «кликает» только в нужные ему места и переходит по ссылкам со скоростью света, то это можно отследить по движению курсора, если автор бота не додумается в оркестраторе прописать какое-то человекоподобное, плавное, смещение.

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

    Это кропотливая, достаточно сложная работа — такими вещами обычно занимаются компании, которые предоставляют bot detection как услугу, и заниматься таким самостоятельно на своем ресурсе — это не очень выгодное вложение времени и средств.

    Но, что поделать — нам очень нужно поскрейпить сайт, обвешанный тучей таких проверок на безголовость и вычисляющий наш какой-нибудь headless-chrome с puppeteer’ом несмотря на все, как бы сильно мы ни старались.

    Маленькое лирическое отступление — кому интересно поподробнее почитать про историю и эволюцию проверок, например на безголовость Chrome, есть забавная эпистолярная дуэль двух авторов. Про одного автора я знаю не очень много, а второго зовут Antoine Vastel — это молодой человек из Франции, который ведет свой блог о ботах и об их обнаружении, об обфускации проверок и многих других занятных вещах. И вот они со своим визави на протяжении двух лет спорили о том, можно ли задетектить headless Chrome.

    А мы двинемся дальше и поймем, что же делать, если не получается headless’ом пробиться через проверки.



    Значит, мы не будем использовать headless, а будем использовать большие настоящие браузеры, которые рисуют нам окошки и всякие визуальные элементы. Инструменты, такие как Puppeteer и Playwright позволяют вместо headless’а запускать браузеры с отрисованным экраном, считывать user input оттуда, снимать скриншоты и делать многое другое, что недоступно браузерам без визуальной составляющей.



    Помимо обхода проверок на безголовость в этом случае также можно справится со следующей проблемой — когда у нас какие-то элементы хитрые сайтоделы, прячут из текста в картинки, делают невидимыми без совершения дополнительных кликов или каких-то других действий и движений. Прячут какие-то элементы, которые должны быть hidden, и на которые попадаются headless’ы: они-то не знают, что этот элемент сейчас не должен отображаться на экране, и попадаются на этом. Мы можем просто отрисовать в браузере эту картинку, скормить скриншот OCR’у, получить на выходе текст и использовать его. Да, это сложнее, дороже с точки зрения разработки дольше и ест больше ресурсов. Но есть скрейперы, которые работают именно так, и в ущерб скорости и производительности собирают данные таким образом.



    «А как же CAPTCHA?» — спросите вы. Ведь OCR’ом (продвинутую) капчу не решишь без каких-то более сложных вещей. На это есть простой ответ — если у нас не получается решать капчу автоматом, почему бы не задействовать человеческий труд? Зачем разделять бота и человека, если можно комбинировать их труд для достижения цели?

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

    Понятно, что это тоже стоит копеечку — решение капчи закупается оптом. Но если наши данные стоят дороже, чем составят затраты на все эти ухищрения, то, в конце концов, почему бы и нет?

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



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



    Поэтому сначала нужно понять, что нас скрейпят — посмотреть на те значения, которые обычно аффектятся при этой деятельности. Мы говорим сейчас про технические параметры и про бизнес-метрики. Те вещи, которые можно увидеть у себя в Grafana, на протяжении времени отсматривая нагрузку и трафик, всякого рода всплески и аномалии. Это можно делать и вручную, если вы не используете средство защиты, но это более надежно делают те, кто умеет фильтровать трафик, обнаруживать разного рода инциденты и матчить их с какими-то событиями. Потому что помимо анализа логов постфактум и помимо анализа каждого отдельного запроса здесь может работать и использование какой-то накопленной средством защиты базы знаний, которая уже видела действия скрейперов на этом ресурсе или на похожих ресурсах, и можно как-то сравнить одно с другим — речь о корреляционном анализе.

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



    Что касается средств защиты, которые применяются против агрессивного скрейпинга, то большинство методов мы уже рассмотрели, говоря про разные категории ботов. Анализ трафика нам поможет от самых простых кейсов, поведенческий анализ поможет отследить такие вещи, как фаззинг (подмена identity) и мультиинстансинг на скриптах. Против более сложных вещей мы будем собирать цифровые отпечатки. И, конечно же, у нас есть CAPTCHA как последний довод королей — если мы не смогли хитрого бота как-то поймать на предыдущих вопросах, то, наверное, он споткнется на капче, не правда ли?



    Ну, здесь все немножко сложнее. Дело в том, что по мере увеличения сложности и хитрости проверок они становятся все дороже в основном для клиентской стороны. Если анализ трафика и последующее сравнение параметров с какими-то историческими значениями можно делать абсолютно неинвазивно, без влияния на время загрузки страницы и на скорость работы онлайн ресурса в принципе, то fingerprinting, если он достаточно массивный и делает сотни разных проверок на стороне браузера, может серьезно повлиять на скорость загрузки. А странички с проверками тоже мало кто любит наблюдать в процессе перехода по ссылкам.

    Что касается CAPTCHA — это самый грубый и самый инвазивный метод. Это штука, которая реально может отпугнуть пользователей или покупателей от ресурса. Капчу никто не любит, и к ней не от хорошей жизни обращаются — к ней прибегают тогда, когда все остальные варианты не сработали. Здесь есть и еще один забавный парадокс, некоторая проблема с таким применением этих методов. Дело в том, что большинство средств защиты в той или иной суперпозиции применяют все эти возможности в зависимости от того, с насколько сложным сценарием бот активности они столкнулись. Если у нас пользователь сумел пройти анализаторы трафика, если его поведение не отличается от поведения пользователей, если отпечаток его похож на валидный браузер, он преодолел все эти проверки, и тут в конце мы показываем ему капчу — и это оказывается человек… это бывает очень грустно. В итоге капча начинает показываться не злобным ботам, которых мы хотим отсечь, а довольно серьезной доле пользователей — людей, которые могут на это разозлиться и могут в следующий раз не прийти, не купить что-то на ресурсе, не поучаствовать в его дальнейшем развитии.



    Учитывая все эти факторы — что же нам в итоге делать, если скрейпинг пришел к нам, мы на него посмотрели и смогли как-то оценить его влияние на наши бизнес- и технические показатели? С одной стороны, бороться со скрейпингом по определению как со сбором публичных данных, машинами или людьми смысла не имеет — вы сами согласились с тем, что эти данные доступны любому пользователю пришедшему из интернета. И решать задачу по ограничению скрейпинга «из принципа» — то есть из-за того что к вам приходят продвинутые и талантливые ботоводы, вы стараетесь их всех забанить — значит потратить очень много ресурсов на защиту, либо собственных, либо использовать дорогостоящее и очень сложное решение, self-hosted или облачное в «режиме максимальной защищенности» и в погоне за каждым отдельным ботом рисковать отпугнуть долю валидных пользователей такими вещами, как тяжелые javascript-проверки, как капча, которая выскакивает на каждом третьем переходе. Все это может ваш сайт до неузнаваемости изменить не в пользу ваших посетителей.

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

    Ну и еще очень важно использовать то, что называется «правильный mindset» в изучении всей этой проблематики на своих или чужих примерах. Нужно помнить, что в защите нуждаются не сами публичные данные — их все равно рано или поздно увидят все люди, которые этого хотят. В защите нуждается пользовательский опыт: UX ваших клиентов, покупателей и пользователей, которые, в отличие от скрейперов, приносят вам доход. Вы сможете его сохранить и повысить, если будете лучше разбираться в этой очень интересной сфере.

    Большое спасибо за внимание!



    Qrator Labs
    DDoS Attacks Mitigation & Continuous Availability

    Комментарии 59

    • НЛО прилетело и опубликовало эту надпись здесь
        +1
        Спасибо всё так довольно интересный обзор с той стороны. =)

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

        Посоветовать могу как не странно самые простые js проверки не смотря на возможности headless браузеров но они на порядок медленней обычных http запросов и их масштабирование на порядок сложнее(точнее дороже) чем у обычных скриптов. Так же многие из тех кто пишет парсеры не лезут в js смотреть всю цепочку вызовов. Касательно капчи 3-я версия google ReCapcha неплохо ловит парсеры, но так же часто срабатывает на обычных пользователей, так что советую остановиться на второй в текущей момент.

        Так же не самой плохой стратегией следует принять создание API для получения данных. Некоторые сервисы предлагают платный API к данным тем самым снижая на порядок объём ботов которые к ним лезут.
          +5
          tldr: защита от скрейпинга — дело ресурсоемкое и обычно крайне малоэффективное

          За 6 лет активной работы по всевозможными проектам, связанным с питоновской библиотекой Scrapy и более 5000 лично написанных скрейперов, всего 1 раз столкнулся с тем, что не смог справиться с задачей извлечения контента без каких-либо вебдрайверов. Это был какой-то сайт с котировками, у них стояла защита от сервиса Incapsula (к которой, кстати, время от времени появляются способы обхода, но потом быстро выкатывается новая версия и приходится искать новые). На верхушку хит-парада защиты контента я бы поставил всякие каптчи (как сторонние, так и самодельные). На втором месте попытки шифровки запросов. Но поскольку эти шифровки делаются на клиенте, ничего не мешает прочитать сорс и сделать аналогичную шифровку у себя. Сложнее ли написать скрейпер к такому сайту? Несомненно. Сильно сложнее? Думаю, минут на 30 дольше. На 3-ем месте изощренное кунг-фу вроде того, каким владеет LinkedIn. Не представляю, сколько ресурсов эти ребята тратят на свои шаманские практики, но работают эти практики, признаюсь, очень хорошо, сделать стабильный и быстрый скрейпер их площадки — задача невероятной сложности.
            0
            Обожэ. Одна Инкапсула на 5000 спайдеров? Серьезно?

            Ну вот прям навскидку, что за пару секунд на ум пришло:

            Залогиньтесь Scrapy сюда: secure.tesco.com/account/en-GB/login
            Поскрапьте Scrapy это: www.tmdn.org/tmview/welcome

            Количество это не всегда показатель опыта. Можно за 6 лет вырыть 5000 типовых индивидуальных окопов, но это не сделает инженером фортификационных систем.
              0
              попробуй поскрапить вот это kad.arbitr.ru
              +4
              Поначалу хотел покритиковать. Но оказалась очень качественная и продуманная статья. Особенно порадовал последний параграф!

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

              Если продавец не может сделать нормальный бэкордер или захочет поиграть с покупателями в странные ценовые игры, то к нему придут скрейперы )) И лучшая защита от них — улучшать user experience реальных пользователей.
                0
                Хотелось бы узнать как все ваши javascript-хаки работают на RESTApi? Логично что никак, а вот мне как создателю скриптов для парсинга REST на сайте очень даже помогает в работе
                  0
                  Скорее всего имелось ввиду использование токенов совместно с RESTApi. Однако это обходится использованием headless браузеров.
                    0

                    Тот же акамаи, к примеру, может проверять порядок в котором присылаются header'ы и соответствие user-agent'у. При неправильном порядке запрос блокируется. Это конечно обходится, но тем не менее, как пример fingerprintg'a без js.

                      0

                      Если там REST API, в которое можно сходить чем угодно помимо браузера по задумке, то речь об обычной js инъекции не идет. Однако если там доступ токенизирован с ограничением предметной области — например, конкретное моб.приложение и браузеры — то все веселее. Для браузера уже понятно, как токен сгенерировать, а вот в моб.приложении модифицируется клиентская часть, для этого антиботчики дают свои SDK. У одного из решений можно вообще так капчу себе встроить в клиент (звучит дико, как по мне)

                      +1
                      Я человек не азартный, но как-то, на слабо, написал бота для ставок на БК Олимп по заданной стратегии. Эх, времена… писал на… Delphi )
                        0
                        Спасибо за статью, интересно. Но я никак не могу понять в чем проблема обхода FingerprintJS? Какие бы проверки в браузере не выполнялись, в итоге библиотека отправляет на сервер всего одно значение, которое является хешем (вроде lIGIMAWYZCjkGbjSMx1c), а хеш можно самому отправить любой. Или я что-то не до конца понимаю? Поясните, пожалуйста, этот момент.
                          0
                          Вы путаете FingerprintJS и фингерпринтинг как метод в принципе. Хэш не любой, фингерпринт это результат всевозможных проверок и только один из параметров, проверяемых антиботом, он должен коррелировать с остальными. Например, типичная фишка — запрос к антиботу через WebRTC в браузере и добавление ответа в фингерпринт. Ну плюс еще обычно фингерпринт вычисляется и шифруется обфусцированным динамически изменяющимся скриптом, поэтому вы в принципе не можете быть уверены даже в формате фингерпринта в текущей сессии.
                            0

                            Эксплуатировать WebRTC leak это ходовой вариант, но и защититься от него несложно.


                            А вот обфускация и динамические перестановки действительно заставят повозиться тех, кто глазами и парсером смотрит JS и крафтит ответы. Однако динамика встречается нечасто по моим наблюдениям.

                              0
                              Да, конечно, то, что один человек сделал, другой завсегда сломать может, это всего лишь был пример, почему нельзя взять любой хэш.

                              Однако динамика встречается нечасто по моим наблюдениям.

                              У F5 встречается (встречалось?). А китайцы прям обожают такое.
                                0

                                Про js fingerprinting у BIG-IP ASM мне известно, но так получилось, что ни один ресурс с полностью настроенной защитой от F5 пока не прошел через очумелые ручки. Попадётся — с интересом загляну под капот.

                              0

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


                              P.S. Кстати говоря, буквально сегодня у меня был похожий случай. Несколько месяцев назад у меня почему-то перестал работать поиск на prom.ua (а-ля украинский амазон) — точнее, из результатов поиска не открывалась страница с товаром (выдавала 404). Из-за этого я раз 5 отказался от покупки, найдя товары через обычный поисковик на других сайтах. Но сегодня было "очень надо" купить именно через prom.ua, и я таки разобрался, в чём проблема. Отключение uBlock Origin, uMatrix и HTTPS Everywhere не помогло, что меня несколько озадачило — обычно дело в ком-то из них. Пришлось запускать Vivaldi (в котором всё работает) и сравнивать открывающиеся из результатов поиска url: оказалось, что файрфокс выкидывал из параметров запроса campaignId — работа плагина Neat URL. Пришлось добавить в Neat URL исключение специально для этого параметра на prom.ua, и всё снова заработало. Но дело в том, что я абсолютно уверен — этот параметр не является необходимым для открывания страницы товара из результатов поиска, так что виноватым в проблеме является вовсе не Neat URL, а жадность владельцев сайта к сбору посторонних данных о пользователях — что лишило их дохода от нескольких продаж в данном случае.

                            0
                            Кстати, а что насчет Google Аналитики? Ее как-то можно использовать против скраперов?
                              0

                              Метрики из Google Analytics могут помочь обнаружить скрейпинг, если он производится топорно, без попыток мимикрировать под человека. Во-первых, надо почистить метрики фильтрами (Exclude all hits from known bots and spiders), а затем можно искать аномалии в репортах: например, юзеры, которые открывают ровно 1 URL (не корень) и уходят, высокая скорость переходов и т.д. — по совокупности факторов неладное заметить можно невооружённым глазом.


                              Так что предотвратить — нет, обнаружить — чаще да, чем нет.

                              +5
                              Что делать, если приехал скрейпер

                              А где вариант "расслабиться и получить удовольствие"?


                              Если кому-то сильно надо, он, не смотря на все Ваши супермегафингерпринты тупо посадит на задачу Amazon Mechanical Turk и будет иметь то, что "надо", за копейки так или иначе. Так зачем мучиться самому и мучить других?


                              Скрейперу понадобилось перебрать достаточно много поисковых запросов, и он из 200 RPS к этой локации сделал почти 700.

                              А если бы у вас был нормальный роботоориентированный API, то никто не пришёл бы к Вам скрейпить страницы (и зря тратить процессорное время на их рендеринг), ибо нафига? Обращались бы к API.


                              приходящие боты сгребают в корзину

                              Поэтому "сгребание в корзину" в нормальных магазинах на состояние остатков на складе никак не влияет — остатки уменьшаются только когда реально прошла оплата. А до тех пор — "кто не успел, тот опоздал" ©

                                0
                                Знаете, бывает по-разному, например я, работал на одной галере(по-моему не особо известной) и там прилетел заказ парсить перелеты с сайта перелетов соответственно. Всех этих направлений было много, плюс «эффективные менеджеры» решили(ввиду того, что там была цепочка в несколько звеньев перепродажи этих данных), что парсить нужно каждый час свежие данные. В итоге получилось около миллиона запросов в час, пусть и по API. С учетом того, что у сайта была посещаемость около 3 миллионов в день, представьте, что им еще сверху прилетает 24 миллиона запросов в день. Я думаю «расслабиться и получать удовольствие» тут не получится.
                                  +1
                                  С учетом того, что у сайта была посещаемость около 3 миллионов в день, представьте, что им еще сверху прилетает 24 миллиона запросов в день.

                                  Ну вот смотрите, у них этого сайта есть выбор: либо эти 24 миллиона прилетают через стандартный web — то есть мало того, что выполнятся те же самые запросы, но сверх того ещё и фронтенд работает, оборачивая результаты в HTML, который на другом конце будет выкинут нафиг — либо 24 миллиона запросов прилетает через API (то есть с минимальной обработкой). Что Вы выбираете?


                                  А на самом деле можно пойти ещё дальше. Что является целью "эффективных менеджеров"? Уж никак не нагружение Ваших серверов (они ведь тем самым и свои нагружают — парсингом улова) — им просто нужны самые свежие данные. Так дайте им то, что они хотят: просто добавьте в API поле "дать мне только то, что изменилось после такого-то таймстемпа" — и всё, передаются только диффы, миллионы резко испаряются. Кроме того, эффективным менеджерами можно доступ к этому API за, скажем, сотку баксов в месяц продавать — им это явно выгоднее, чем им платить эту же сумму производителям средств обхода защиты от скрейпинга (плюс ещё можно парочку своих программистов сократить), а Вам — лишняя прибыль.


                                  Подумайте сами ещё раз: вот поняли Вы, что Вас скрейпят, пошли к программистам и поставили задачу — "схватить и не пущать". Программисты пожужжали и сделали. Знаете, что это означает? Что где-то далеко какой-то начальник пришёл к своим программистам и сказал: "У нас только что скрейпинг чего-то накрылся. Почините." Goto начало параграфа. В результате у программистов (то одних, то других, попеременно) мозги плавятся, у серверов процессоры дымятся, приближая глобальное потепление, и кулеры гудят, а пользы — никому и никакой от слова "совсем".

                                    +2
                                    Ну вот смотрите, у них этого сайта есть выбор: либо эти 24 миллиона прилетают через стандартный web — то есть мало того, что выполнятся те же самые запросы, но сверх того ещё и фронтенд работает, оборачивая результаты в HTML, который на другом конце будет выкинут нафиг — либо 24 миллиона запросов прилетает через API (то есть с минимальной обработкой). Что Вы выбираете?


                                    В моем случае уже было API.

                                    А на самом деле можно пойти ещё дальше. Что целью «эффективных менеджеров»? Уж никак не нагружение Ваших серверов (они ведь тем самым и свои нагружают — парсингом улова) — им просто нужны свежие данные. Так дайте им то, что они хотят: просто добавьте в API поле «дать мне только то, что изменилось после такого-то таймстемпа» — и всё, передаются только диффы, миллионы резко испаряются. Кроме того, эффективным менеджерами можно доступ к этому API за, скажем, сотку баксов в месяц продавать — это явно выгоднее, чем им платить эту же сумму производителям средств обхода защиты от скрейпинга.


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

                                      Работа разработчиков стоит денег, и довольно больших. Обеим сторонам! Поэтому и у владельца сайта и заказчика парсинга есть отличная финансовая мотивация найти такой баланс цены на API, который устроит всех — потому что это сэкономит деньги и тем и другим.


                                      По моим наблюдениям, причиной этого не делать обычно является либо то, что владелец сайта наивно полагает, что любые парсеры возможно и не очень сложно заблокировать (и поэтому успевает вложить ресурсы в попытку это сделать, которые потом жалко выкидывать и он продолжает двигаться по этому пути уже из принципа), либо сайт вообще не имеет API и разрабатывать его чисто "ради чужих парсеров" выглядит для владельца дикой идеей.

                                  0
                                  и будет иметь то, что «надо», за копейки так или иначе

                                  Такое обобщение не берет в расчет бизнес-модель коммерческих скрейперов. А она работает, когда в асимптотическом приближении (инструмент уже написан/куплен, стоимость модификации околонулевая, а кол-во заказов большое и растет) стоимость данных с одной обработанной странички в продаваемом датасете выше, чем накладные расходы: виртуалки, трафик, стоимость решения капчи, стоимость ручного труда + еще ряд менее очевидных параметров.
                                  ибо нафига? Обращались бы к API.

                                  Идея public API благородна, я бы хотел жить в мире, где у каждого ресурса с полезными данными было бы оно. К сожалению, что с коммерческим, что с бесплатным роботоориентированным интерфейсом бывает так, что ресурс начинают скрейпить и со страничек, и с API — каких-то данных не хватает, медиа и тд. Из того, что вы уважаете потребности своих юзеров, не следует, что они станут уважать ваши.
                                  А до тех пор — «кто не успел, тот опоздал»

                                  Здесь согласен. Однако пока не у всех ритейлеров работает такая модель, эти сценарии как были, так и продолжатся.
                                    +1
                                    Такое обобщение не берет в расчет бизнес-модель коммерческих скрейперов.
                                    Что-то я этого параграфа не понял — сдаётся мне, Вы слишком витиевато изъяснились.
                                    стоимость данных с одной обработанной странички в продаваемом датасете выше, чем накладные расходы:
                                    Это чисто проблема Вашего (владельца данных) ценообразования: хозяин скрейпера нашёл способ скрейпить их дешевле, чем Вы их ему продаёте. Снижайте цену — это рынок: «я хочу, чтобы эти данные стоили $XXXX» — он так не работает, вы должны предоставлять некое конкурентное преимущество (на выбор — цена, удобство, маски-шоу для нарушителей и т.п.) — иначе не купят.
                                    Идея public API благородна, я бы хотел жить в мире, где у каждого ресурса с полезными данными было бы оно. К сожалению, что с коммерческим, что с бесплатным роботоориентированным интерфейсом бывает так, что ресурс начинают скрейпить и со страничек, и с API — каких-то данных не хватает, медиа и тд. Из того, что вы уважаете потребности своих юзеров, не следует, что они станут уважать ваши.
                                    Я что-то говорил про благородство, уважение, потребности и проч.? Здесь совершенно тупое взаимодействие двух акторов: владельца данных и скрейпера, далее чистая
                                    теория игр
                                    Вводные:
                                    • Владелец данных вынужден предоставлять их любому желающему (иначе пользователи ничего не смогут у него купить);
                                    • Обычный (индивидуальный) пользователь хочет получить веб-страничку (с оформлением, рюшечками, UI и проч.) поодиночке и редко — но их (сравнительно) много;
                                    • Скрейпер хочет получить голые данные (без оформления, рюшечек, UI и проч.) массово и часто — но их (сравнительно) мало;
                                    • Отличить обычного пользователя от скрейпера в момент получаения (самого первого) HTTP-запроса невозможно (особенно с учётом того, что последний изо всех сил старается маскироваться).

                                    Предполагаем, что количество доходящих до хозяину скрейперов при наличии защиты n меньше, чем без наличия защиты N (количество «пытающихся» при этом всё равно N, просто (N-n) не проходят сквозь защиту)

                                    Хозяин имеет расходы:
                                    • на сервера только с обычными пользователями — {$обслуживание обычных пользователей} (не детализируем, ибо оно одинаковое во всех случаях)
                                    • на сервера со «скрейперной» нагрузкой — ({$обслуживание обычных пользователей} + {$обращений к БД для (x) скрейперных пользователей})
                                    • на сервера со «скрейперной» нагрузкой и противоскрейперной защитой — ({$обслуживание обычных пользователей} + {$обращений к БД для n скрейперных пользователей} + {$UI для n скрейперных пользователей} + {$противоскрейперной защиты})

                                    Скрейпер имеет расходы:
                                    • противодействуя защите: {$аренду серверов обработки данных}(N) + {$вырезания UI}(N) + {$з/п разработчиков обхода защиты}
                                    • не противодействуя защите: {$аренду серверов обработки данных}(n)

                                    Таблица стратегий:
                                    • Хозяин — защищаться, скрейпер — противодействовать:
                                      • расходы хозяина: ({$обслуживание обычных пользователей} + {$обращений к БД для n скрейперных пользователей} + {$UI для n скрейперных пользователей} + {$противоскрейперной защиты})
                                      • расходы скрейпера: {$аренду серверов обработки данных}(N) + {$вырезания UI}(N) + {$з/п разработчиков обхода защиты} — {$убыток от неполноты данных}

                                    • Хозяин — защищаться, скрейпер — не противодействовать:
                                      • расходы хозяина: ({$обслуживание обычных пользователей} + {$обращений к БД для n скрейперных пользователей} + {$UI для n скрейперных пользователей} + {$противоскрейперной защиты})
                                      • расходы скрейпера: {$аренду серверов обработки данных}(n) + {$убыток от неполноты данных}

                                    • Хозяин — не защищаться, скрейпер — (всё равно пытаться) противодействовать:
                                      • расходы хозяина: {$обслуживание обычных пользователей} + {$обращений к БД для n скрейперных пользователей} + {$UI для n скрейперных пользователей}
                                      • расходы скрейпера: {$аренду серверов обработки данных}(n) + {$вырезания UI}(n) + {$з/п разработчиков обхода защиты}

                                    • Хозяин — не защищаться, скрейпер — не противодействовать:
                                      • расходы хозяина: {$обслуживание обычных пользователей} + {$обращений к БД для n скрейперных пользователей}
                                      • расходы скрейпера: {$аренду серверов обработки данных}(n)

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

                                      0
                                      то-то я этого параграфа не понял — сдаётся мне, Вы слишком витиевато изъяснились.

                                      Постараюсь проще. Расходы на продвинутый скрейпинг могут быть совсем не копеечными, если данные нужно собирать помногу и регулярно, а не один раз из одного места для исследования или развлечения. Внезапно, миллион капч оборачивается порядка $700, аренда residential proxy — от $100/m и выше сообразно качеству. А это те инструменты, на которые скрейпера заставляет тратиться защита. А вы этого не учитываете.

                                      Здесь совершенно тупое взаимодействие двух акторов: владельца данных и скрейпера, далее чистая теория игр

                                      Не могу согласиться насчет «тупое». Есть масса факторов, которые находятся за пределами вашей платежной матрицы и могут заставить (и в реальной жизни заставляют) скрейпера не ходить в API или ходить не только в него:
                                      • интерфейсы коммерческих ресурсов, что платные, что бесплатные (как Walmart Open API) имеют либо рейтлимит, либо лимит на общее число запросов с одного токена, и собрать датасет нужного размера не выходит. При этом такого рода ограничения на вебсайте (особенно рейтлимит) вводить опасно, его же еще и люди смотрят.
                                      • В API может не оказаться данных нужного типа. Или они преобразовываются как надо на фронте, и под них нужно писать аналогичную трансформацию, что дольше, чем лишний раз бахнуть по сайту.
                                      • Открыли API? А я собираю с десятков подобных сайтов, где API нет, у меня уже потрачено на инфраструктуру и техстек, теперь я могу скрейпить ваш сайт из обоих мест параллельно! :).
                                      • Банальная лень и нежелание трогать то, что уже работает.

                                      Этот список можно продолжить.
                                        +1
                                        А это те инструменты, на которые скрейпера заставляет тратиться защита. А вы этого не учитываете.

                                        Учитываю. Видите ли, эта тема мне крайне близка, и я с ней как бы не понаслышке. Если данные доступны человеку — они будут доступны роботу (пусть даже с применением "механических турков").


                                        миллион капч оборачивается порядка $700,

                                        … вот только Вы забываете, что, ставя капчу, вы сильно снижают конверсию реальных покупателей. Замечательный способ выстрелить себе в ногу.


                                        имеют либо рейтлимит, либо лимит на общее число запросов с одного токена,

                                        Повторюсь: если Вы со скрейпером не пришли ко взаимовыгодному решению — значит, Вы что-то делаете неправильно. Дайте мне конкретную проблему — я Вам дам конкретное решение. Часто скрейпят? Дайте возможность API отдавать только изменения. Всё равно скрейпят веб даже при наличии API? Узнайте, чего им не хватает в API и добавьте. И т.п. У скрейпа веба есть не нужный ни Вам, ни — главное — скрейперу, оверхед — следовательно, если они согласны на него тратиться, значит, они получают с него какое-то преимущество; дайте им это преимущество, но без оверхеда ни для них, ни для Вас — и все будут довольны.


                                        В API может не оказаться данных нужного типа.

                                        "А сейчас мы проезжаем мимо публичного дома." — "А ПОЧЕМУ???". Сделайте, чтобы оказались! Это значительно проще, чем ваять веб-страницу и наклёпывать на неё работающий антискрейпер (а там ещё false positives подтянутся, с соответствующими результатами для конверсии)


                                        заставляют скрейпера не ходить в API или ходить не только в него

                                        Эта проблема решается включением в API "того, чего не хватало". Что, повторюсь, проще, чем ваять веб-страницу для пользователя.


                                        теперь я могу скрейпить ваш сайт из обоих мест параллельно! :).

                                        "БуханкаТроллейбус.жпг" — НО ЗАЧЕМ??? Держать лишние инстансы, деньги на них тратить? Я что, идиот? Лучше очередной мерс куплю.


                                        Банальная лень и нежелание трогать то, что уже работает.

                                        Вы недооцениваете банальное бабло, которое побеждает зло — и даже лень.

                                          0
                                          Вы отчего-то упорно игнорируете такие факты, как:
                                          • основной бизнес-задачей рассматриваемых в рамках доклада веб-ресурсов является не продажа публичных данных скрейперам, с которыми вы предлагаете «прийти к взаимовыгодному решению»;
                                          • оценка действий скрейпера с позиции логики не всегда соотносится с реальностью. Как и договороспособность.

                                          Приведу 2 примера из практики, которые иллюстрируют это:
                                          1. Скрейпер приходит на страницу сайта с авиабилетами и собирает перелеты, делая несколько млн запросов за час. При этом он собирает столько же уникальных данных, сколько бы он получил, делая порядка 20000 запросов за тот же час: частота обновления на ресурсе заведомо ниже частоты запросов к одной и той же позиции, и большинство ответов ему просто не нужны. Зачем он это делает? «Держать лишние инстансы, деньги на них тратить? Я что, идиот?» Нет, ему просто наплевать, пока не возникло защиты в этом месте, создание такой нагрузки была для него столь же дешевым.
                                          2. Сайт открыл свой API для поиска и листинга цен, там появился трафик, но нагрузка от скрейперов не снизилась. Причины: 1) скрейперам забыли позвонить и сообщить :) 2) в API пришла часть тех, кто раньше покупал у скрейперов собранные данные, сузив рынок сбыта, но не ликвидировав его 3) снова, скрейпить без защиты просто и дешево, поэтому отказываться от него ради API нелогично, наоборот, можно совместить одно с другим.


                                          Оверхед на скрейпинг с веб-страниц, о котором вы говорите, существует в основном из-за наличия уже внедренных мер защиты. И на него согласны тратиться лишь оттого, что других вариантов собрать данные с такой же скоростью не предоставлено. API скорее помогает не скрейперам, а тем, кто от них больше всего страдает — юзерам, аффилиатам или партнерам, которым нужна интеграция функций одного сервиса в другой.
                                            +1
                                            частота обновления на ресурсе заведомо ниже частоты запросов

                                            Это известно Вам, но не тому, кто писал скрейпер. Он перестраховывается, так как не хочет пропустить изменения. Сообщите владельцу, что это бессмыссленно, сделайте endpoint с "номером версии данных", который будет инкрементироваться при обновлении — и лишние скрейпы уйдут.


                                            скрейперам забыли позвонить и сообщить

                                            и… чей это недостаток? Если лень звонить — измените немножко код страницы (что заставит разработчика скрейпера, выматерившись, пойти разбираться, чего это скрейпер перестал работать), вставив в него большой коментарий вида "Эй, разработчик скрейпера, не морочься, вот тут есть API" — и будет ЩАСТЬЕ


                                            в API пришла часть тех, кто раньше покупал у скрейперов собранные данные, сузив рынок сбыта

                                            … и теперь эти покупатели будут нести деньги не хозяину скрейперов, а напрямую Вам, чем это плохо?


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

                                            если скрейпят "и так и так" — значит, в API нет чего-то, что есть на странице; добавьте.


                                            P.S. Если Вы ещё не поняли — это я Вам как этот самый разработчик скрейперов говорю. Правда, по счастью для Вас, мы работаем с американской индустрией. ;)

                                  0
                                  Всегда считал, что если данные доступны человеку, то и спарсить это можно в любом случае. Больше время, больше затрат, но главное придти к результату. А чем сложней задача, тем интересней.
                                    0
                                    А чем сложней задача, тем интересней.
                                    И тем дороже. После какого-то предела, преодолевать зашиту от скрейпинга выйдет так дорого, что данные того уже не стоят.
                                    0

                                    А как на счет сайт через OCR прогонять? Или ресурсоемко?

                                      0
                                      есть «бюджетный» вариант — делать headless-браузером скриншоты (они умеют это делать уже достаточно давно) и распознавать нужное на них. Если это телефон/цена картинкой прямо на странице — можно справиться и так. Однако если элемент, к примеру, скрыт и требует интерактива (hover, click, drag etc), халява не прокатит, придется работать в окне headful-браузера. А headful-браузер тащит за собой еще и много лишних для этой задачи компонентов, которые тоже едят ресурсы.
                                      +1

                                      Хорошая статья. Но мне интересно как должен быть организован корректный, нежный и бережный скрейпинг?)

                                        +2
                                        Как можно меньше запросов в единицу времени, собственно всё. Просто представьте себя на месте владельца сайта.
                                          0
                                          Меньше rps, меньше любых действий что вынуждают в холостую работать бэкенд сайта. Вообщем стараетесь что бы на той стороне никто даже не тревожился. А так конечно скачок на 1000-5000 rps ясное дело заметят, да и для многих сайтов 500 rps, это уже равно падение сервиса. Правда надо ещё понимать с кем вы общаетесь если нужные данные может вернуть веб-сервер сам без задействования скриптов и базы бэка то общайтесь с ним они как правило спокойно поддерживают большой RPS и не мешают самому сайту работать.
                                          +1
                                          В практике был единственный сайт, где не удалось пробить появление капчи, ему «помогал» CloudFlare и еще какой-то сервис. И если CloudFlare был «обманут», то второй сервис блокировал быстро (3-5 запросов на каждый прокси) и надолго.

                                          Пробовал даже через селениум — не спасло ситуацию. Даже вручную в браузере ходил вводить капчу (найти все велосипеды или зонты), сервис мне не верил :)

                                          А путь с платным разгадыванием капчи не пригодился :)

                                          P.S. Еще сталкивался когда нельзя было внутреннюю страницу посмотреть без родительской. Правильный реферер не помогал, видимо пользователя «вели» по сайту и логгировали все его запросы, создавая тем самым недопустимые для него переходы. Наверное
                                            +2
                                            самая клевая защита которую видел — это когда сайт начинает подмешивать фейковые данные. подстава в том что не ясен момент когда тебя спалили
                                              +1
                                              Вот это реально крутая защита! Правда не всегда можно это делать гарантированно для бота…
                                                +1
                                                Это интересная игра, в которую можно играть очень долго. Проблема в том, что анализ собранных данных позволяет достаточно точно определить, как и когда сайт выдает неверные данные в сравнении с имеющимися настоящими. Дальше можно вычислить, какое поведение триггерит выдачу фейковых данных, и скорректировать его. Развитие событий будет вынуждать защитника отдавать фейк на все большее количество обращений, что неизбежно повышает риск ложных срабатываний — для нормального юзера получить фейковые данные (он может не знать, что они таковые) еще опаснее, чем просто 403-ю ошибку или редирект.

                                                В примитивном варианте это поможет от скрейперов «запустил и забыл», которые, видимо, не собираются продавать свою работу, и на ее качество им плевать.
                                                  +2

                                                  Угу, замечательный способ выстрелить себе в ногу — теперь вместо 20 миллионов запросов от скрейпера Вам будет приходить 120 (а потом скрейпящий будет сравнивать полученные копии одной и той же страницы, чтобы понять, какие из них истинные).

                                                  +1
                                                  Любая защита приводит к деградации UX, например постоянные каптчи или задержка 5с при валидации CF. Всякие фильтры по IP/прокси/VPN приводят к отвалу сразу большого % легитимных юзеров, например множество сайтов блокируют доступ с серверных IP, при этом такое же множество клиентов использует VPN на своих серверах

                                                  Не вижу смысла защищаться от парсинга, только от такого, который создает нагрузку(правильной настройкой rate-limit например)

                                                    0

                                                    Не до конца понимаю почему никто никогда не вспоминает о таких вещах как browsermob+selenium. Как детектить такие атаки? Обфускация css и js-ловушки уже не помогут.

                                                      0

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

                                                        0
                                                        Не так уж и много ресурсов они требуют, даже полноценный хромиум, так что нагрузку могут создать весьма приличную даже с одной машины, особенно при тяжелых сценариях на сайте. Но такие боты чаще продуманы со стороны «как минимизировать нагрузку на сайт» и разработчики у таких решений чаще более опытные, так что значительно реже являются источником проблем.
                                                          0
                                                          Что вы имеете в виду под тяжелыми сценариями на сайте? Какое отношение они имеют к нагрузке на сайт, они выполняются на стороне клиента. Важно лишь только то, сколько ваш хромиум сделает запросов к бекенду сайта во время выполнения этих сценариев.
                                                          Насчет ресурсов, поделюсь опытом, сделать миллион запросов в час, используя только голые http-запросы и одно ядро процессора i5 — не проблема. А сколько ресурсов потребуется headless-браузеру, чтобы организовать такое количество запросов? А учитывая, что там тяжелые сценарии, которые будут кушать вашу память и цпу на 1 запрос, а вам надо миллион?
                                                            0
                                                            Я имею ввиду тяжелые сценарии на бэке, пп. сложный неоптимизированный поиск по большой базе с постформатированием данных, сложная генерация документов и т.п. Все это обычные явления в кровавом энтерпрайзе. Там не то, что миллион запросов, там сотня одновременных запросов в минуту ложит сервер наглухо.
                                                            Задача браузерных парсеров либо обходить сложные системы защиты, либо делать свою работу аккуратно и незаметно, в ущерб скорости. Для копитыринга и ему подобных задач, такие парсеры конечно используются крайне редко, из-за описанных вами минусов, но в условиях корпоративной автоматизации при отсутствии внешнего API — очень и очень часто. Особенно когда надо взаимодействовать со всякими госпорталами, у которых клиентская часть сгенерирована непонятно чем и работает непонятно как, где скорость в 2-4 задачи парсинга в минуту — это уже хороший результат, а когда пытаешься быстрее, то моментально руководство получает звонок с требованием больше так не делать, а то отвесят бан. Но, при этом, публичное API делать отказываются.
                                                        +1
                                                        В статье это было: фингерпринт, метрики мыши и скорость переходов.
                                                        Сложно, дорого, в большинстве случаев решается введением платного API на доступ к тем же данным.
                                                        +1
                                                        представим, что вы студент, завтра утром у вас защита курсовой работы, у вас по материалам «конь не валялся», не хватает ни цифр, ни выдержек, ни цитат — и вы понимаете, что за оставшуюся часть ночи перелопатить всю эту базу знаний вручную у вас нет ни времени, ни сил, ни желания.

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

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

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

                                                          0
                                                          Не очень понимаю, отчего вы решили, что речь идет о «тупой копипасте». Любая исследовательская работа, включая студенческие, требует поиска и изучения prior art/prior works, событий, упоминаний в медиапространстве и их значимости для выбранной сферы.

                                                          Так, если человек делает исследование эволюции систем предупреждения столкновений воздушных судов и уже успел изучить их устройство, ключевые параметры и сделать нужные выводы, этого будет недостаточно без информации о самих инцидентах столкновений и их последствий, т.е. контекста, в котором работа по этому направлению ведется последние 50-60 лет. Как минимум, стоило бы раздобыть описание всех инцидентов за этот срок, категоризировать их и показать, какие из них были ключевыми для внедрения изучаемых технологий (как катастрофа в Гранд-Каньоне в 1956). Без такого анализа работа на эту тему будет, вероятно, воспринята в лучшем случае как проведенная небрежно, а в худшем — как откровенная халтура.

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

                                                          Что касается оценок — по моему опыту, если кафедра принимала решение устраивать именно защиту курсовых работ (а не как обычно, сдача текста -> письмо на кафедру от н/р с рекомендованной оценкой -> проставление оценки), то оценки оглашались в тот же день.
                                                            0
                                                            Любая исследовательская работа, включая студенческие, требует поиска и изучения prior art/prior works, событий, упоминаний в медиапространстве и их значимости для выбранной сферы.
                                                            Ещё раз повторю вопрос про специальность вашего гипотетического студента :) На курсовых технических специальностей нет слов «prior art/prior works, событий, упоминаний в медиапространстве».

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

                                                            по моему опыту, если кафедра принимала решение устраивать именно защиту курсовых работ (а не как обычно, сдача текста -> письмо на кафедру от н/р с рекомендованной оценкой -> проставление оценки), то оценки оглашались в тот же день
                                                            Научный руководитель у простой курсовой? Это где так?
                                                            По помему опыту (с обеих сторон, кстати) курсовые сдавались на проверку, а через несколько дней была их «защита» в виде собеседования.
                                                              0
                                                              Ещё раз повторю вопрос про специальность вашего гипотетического студента :)

                                                              Пусть будет — сугубо гипотетически — 051311, математическое и программное обеспечение вычислительных машин, комплексов, и компьютерных сетей. Но с тем же успехом может быть и 010107, вычислительная математика, и какая-нибудь другая, где студентами ведется научная работа, и решаются задачи с использованием компьютера :)
                                                              На курсовых технических специальностей нет слов «prior art/prior works, событий, упоминаний в медиапространстве».

                                                              Это очень строгое отрицание, и оно, как мне кажется, неверно. Понятие prior art в контексте алгоритмов и исходного кода общеупотребимо. Поэтому, если вы, например, делаете работу об алгоритме собственной разработки, который решает какую-то задачу, без изучения prior art по своей тематике, упоминания релевантных разработок в обзорной части доклада и анализа их преимуществ/недостатков относительно этой задачи вряд ли ее воспримут всерьез. Я не берусь говорить, что «везде так» или «везде не так», однако вот выписка из одного из вузовских пособий по оформлению учебно-научных текстов:
                                                              «Назначение этой главы – дать более детальное и систематическое представление о существующих решениях рассматриваемой проблемы, чем это сделано во введении. <...> В идеале в обзорной главе должен быть дан сравнительный анализ известных подходов и вариантов решения проблемы...»
                                                              На моем опыте, учитывая, что первая курсовая у студента чаще не несет больших и важных научных инноваций, научное руководство повышенное внимание обращало на то, насколько тщательно студент изучил свою тему и собрал данные для обзорной части, особенно если он планировал в этой теме работать и дальше.
                                                              При том, что специальность не программирование?

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

                                                              Как минимум, в МГТУ, МФТИ, МГУ это так, наверняка во многих других ВУЗах тоже, но я не берусь безоговорочно судить.
                                                          0
                                                          Можно ли посмотреть видео этого доклада?
                                                            0

                                                            Сорри за проволочку — линк на видео как раз доехал в статью.

                                                            0
                                                            А ещё для защиты можно данные фальсифицировать — если можно достаточно достоверно сказать, что это скраппер, выдавать, например, случайные цены и в описания товаров писать плохие слова.
                                                              0

                                                              Угу, как я уже писал — замечательный способ сделать хуже самому себе. Или напроситься под роскомнадзор, если защита ошибётся (а ведь никто не застрахован!) и случайно покажет "плохие слова" обычному пользователю. Как говорится, "у каждой задачи есть простое, лёгкое, неправильное решение".

                                                              +1
                                                              Я бы еще рекомендовал для владельцев сайтов которым например нет дела скачают их данные или нет, но есть дело до нагрузки:
                                                              вывести публичное api по которому у вас смогут легко и безболезненно забирать данные в формате json, с постраничным выводом и описанием.
                                                                0
                                                                Выше в комментах есть ветка, посвященная варианту с публичным API. Как говорила дочь офицера, «не все так однозначно».

                                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                              Самое читаемое