Методы защиты контента от автоматического копирования и парсинга
Эта статья написана Сычевым Игорем (@SychevIgor) с моими комментариями и уточнениями.
Есть несколько сотен сайтов с информацией о банкоматах и отделениях. Необходимо написать программу, с помощью которой можно создать собственную базу данных. Задача не настолько сложная по сравнению с задачей сбора этих данных вручную. Но иногда вашей задачей может стать защита данных от автоматического копирования (краулинга). Собственно об этом и поговорим в этой статье.
Работа с DOM деревом
Любой HTML документ формирует DOM дерево или объектную модель документа, например:
Если необходимо парсить веб-сайт и искать на нем определенную информацию (таблицы с банкоматами или списки сотрудников), то нужно анализировать не весь сайт, а определенные страницы или даже определенные части страницы.
Краулер — это программа, являющаяся составной частью поисковой системы и предназначенная для перебора страниц Интернета с целью занесения информации о них в базу данных поисковика. По принципу действия паук напоминает обычный браузер. Он анализирует содержимое страницы, сохраняет его в некотором специальном виде на сервере поисковой машины, которой принадлежит, и отправляется по ссылкам на следующие страницы. Владельцы поисковых машин нередко ограничивают глубину проникновения паука внутрь сайта и максимальный размер сканируемого текста, поэтому чересчур большие сайты могут оказаться не полностью проиндексированными поисковой машиной.
Вначале несколько слов о том, зачем вообще нужна защита данных:
- защита персональных данных (чаще всего электронных адресов и телефонов) от создания спамерских баз данных;
- базы данных электронных магазинов, каталогов и т.д., как правило, собираются не один день. Нежелательно отдавать конкурентам готовую базу данных, хоть и HTML виде;
- маркетинговый ход – чтобы люди заходили на сайт, а не использовали сторонние клиенты или приложения.
В самых простых случаях информацию на сайте можно скрыть от кроулеров и ботов (таких как Yandex, Google и др. - search robots list, user agent list) путем внесения этих страниц в файл robot.txt. Этот подход позволит избежать появления данных в индексе поисковых систем, но легко обходится с помощью изменения User Agent краулера. Для защиты от поисковиков также можно использовать тег noindex. Основная идея по защите данных в большинстве случаев - это манипуляции с html кодом, которые не заметны для пользователя, но критичны для краулера. Давайте рассмотрим основные ситуации.
Жесткий xpath
Полный абсолютный путь до нужного элемента, например:
html[1]/body[1]/table[1]/tr[1]/td[1]/table[1]/noindex[1]/tr[3]/td[1]/table[1]/tr[1]/td[3]/table[1]
Любое изменение порядка тегов или добавление промежуточного элемента (пустого div или table), не влияющего на визуальное представление, изменит данные, полученные парсером. Можно создать такую динамическую верстку, когда периодически в DOM дерево добавляется дополнительные элементы, либо время от времени меняется форма выдачи.
Мягкий xpath
Относительный путь до элемента или поиск элементы по атрибутам (например, по атрибуту class) td[@class='td_c']. По этому принципу работает большинство парсеров, например HtmlAgilityPack и библиотека jQuery.
Популярные атрибуты не могут служить в качестве отправной точки (например, weight=100px или <div>). Такими атрибутами могут служить значения стилей class, поэтому можно давать однотипные имена для стилей или не давать их вообще (использовать внешние css файлы). В таком случае выбор по тегу table выдаст все таблицы на странице, а не только нужные.
Второй вариант - убрать полностью class и использовать inline css в атрибуте style. Это, безусловно, увеличит размер кода, его читабельность, это не соответствует правилу, что css стили нужно отделять от html, но убрав css, мы уберем отправную точку для парсеров.
Несложно написать утилиту, которая занимается постобработкой html, чтобы на серверной стороне по-прежнему было все читабельно, но у пользователя уже было все inline.
Пример такой библиотеки: https://github.com/milkshakesoftware/PreMailer.Net/tree/master/PreMailer.Net/PreMailer.Net
Element ID и Name
Относительно id и name элементов очень хорошо позиционироваться, поэтому лучшее решение – не использовать их в верстке. Как еще один вариант – создавать несколько элементов с одинаковыми id (это сделает ваш код формально не валидным, но писателям парсера это осложнит жизнь). Как вариант, данные можно отдавать в хитром сплетении табличной и блочной верстке с использованием большего количества дополнительного ‘ мусорного’ html кода. Один из таких способов – выводить табличные данные в div, p, а сами данные с помощью абсолютного позиционирования раскидать по всей странице.
Компрессия и минимизации файлов
Компрессия и минимизация файлов – один из методов клиентской оптимизации. Чем меньше размер html и других ресурсов – тем быстрее происходит загрузка страницы. Кроме того, минимизированные файлы усложняет чтение кода программисту. Минимизации можно подвергнуть как html, css так и js, что в совокупности усложняет написание парсера.
Инструменты для компрессии:
Добавлю, что современные инструменты для разработчиков (firebug, developer tools в IE, Chrome) легко умеют получать форматированные файлы из минимизированных, что делает этот способ малоэффективным.
Использование JavaScript для отображения данных
Написать парсер, который интерпретирует JavaScript несколько сложнее, чем просто обработать html. Поэтому если у вас есть JavaScript код, который подтягивает данные из внешнего сервиса – то, это, пожалуй, самый сложный случай для программиста, пишущему парсер. Хорошая идея -использовать ajax-запросы, не перегружая страницы, что усложнит анализ работы веб-сервиса.
В .NET для обхода этого необходимо использовать компонент WebBrowser, который должен загрузить всю страницу целиком, прежде чем вы сможете начать парсинг данных. Это значительно увеличивает время работы парсера, так как необходимо иметь дело с COM объектами и каждый раз дожидаться полной загрузки веб-страницы вместе с ресурсами. Кроме того, работать с JavaScript интерпретаторами тоже достаточно непросто.
Этот подход хорошо работает для табличных данных с разбивкой на многочисленные страницы и подтягиванием данных с помощью ajax.
Также можно модифицировать JavaScript код, сделав его еще менее читабельным, используя оптимизацию, например, с помощью Closure Compiler: http://code.google.com/intl/ru-RU/closure/compiler/
Скрытие данных с помощью изображений
Мы можем использовать некоторый постпроцессор для страницы с данными. Некоторые данные можно поместить в картинки. Например, электронные адреса или телефоны. Но это может создать неудобства пользователям, т.к. они не смогут скопировать эти данные.
Сейчас часто используются JavaScript библиотеки, которые энкодируют строки (электронные адреса, к примеру) так, что пользователь видит нормальный текст, но html код содержит ряд непонятных символов + несколько JavaScript функций и библиотек, с которыми нужно долго разбираться. Капчи Доступ к данным можно ограничить с помощью капчи – пользователь должен ввести в формочку цифры или еще что-то, чтобы получить доступ. Эффективно для парсеров, но не для людей. Как вариант решения можно считать количество подключений с одного IP (или серии IP адресов) и выводить капчу, если запросов достаточно много. Опять таки, это решается с помощью нескольких IP адресов и прокси-серверов, изменения User Agent и настройкой частоты, с какой парсер будет дергать веб-сайт. Этот способ защиты используется многими компаниями, например Google, Yellow Pages, Hotline (это из личного опыта – Alex K.). Обходить удавалось, но время парсинга увеличивается в разы, что может обесценить процесс извлечения данных.
Выводы
Первый и главный вывод – универсального способа защиты данных от краулеров нет. Все перечисленные способы защиты с той или иной степенью сложности обходятся. Поэтому всегда необходимо использовать несколько способов одновременно. С другой стороны ваша задача – сделать так, чтобы время парсинга данных был как можно больше.