Собственно автоматическое скачивание файла с Web сервера не представляет никакой проблемы – серьезную проблему представляет определение его адреса.
Предположим, некий сайт регулярно публикует в виде файла важную для нас и периодически меняющуюся информацию, которую мы бы хотели автоматически загружать в нашу информационную систему для последующей обработки. Если адрес такого файла постоянен, а меняется только его содержимое, то создание робота для регулярной доставки этого файла и проверки факта изменения его содержимого проблемой не является. Но в ряде случаев сам адрес файла, его имя меняется непредсказуемым образом. Оказывается, задачу автоматического слежения за переменным именем файла на удаленном Web сайте можно решить с высокой вероятностью успеха.
Неудачный подход подбора дат
Исторически такая задача возникла для файлов, содержащих в своем имени дату публикации, например
http://www.site.com/download/timetable_10-08-2021.xls
Вычленение даты из имени файла при многообразии форматов является не очень простой, но все же вполне разрешимой задачей. В случае, если старый файл при ежедневном наблюдении за ним вдруг оказался недоступным, робот может обоснованно предположить, что дата поменялась недавно. Тогда, зная старую дату и ее формат, робот может, двигаясь от текущей даты в прошлое, подобрать новую дату в имени файла за конечное – и весьма ограниченное – число итераций.
На практике такой подход столкнулся с рядом обстоятельств, показавших его несостоятельность.
Во-первых, метод подбора в принципе порочен, поскольку оставляет в логах наблюдаемого сайта сигнатуры, однозначно свидетельствующие об автоматизированном исследовании сайта; если подбор долгий, то это мало отличается от атаки на сервер, и большинство администраторов с этим мириться не будут.
Во-вторых, отмечены случаи включения в имя файла дат с точностью до секунды, что требует для подбора тысяч и миллионов обращений к сайту.
В-третьих, некоторые сайты включают в переменное имя файла не только дату, но и номер; соответственно, подбор такого имени файла потребует произведения ограниченного числа итераций подбора даты на, вообще говоря, неограниченное число номеров.
В-четвертых, часто интересующий нас файл на сервере не заменяется новым, что дало бы нам событие недоступности старого имени файла и запустило бы механизм подбора, а выкладывается параллельно старому с новой ссылкой на него на родительской Web странице. Соответственно, в отсутствие события обновления имени файла мы вынуждены проводить выше описанные действия ежедневно.
Четыре выше перечисленные обстоятельства представляют серьезную проблему, но теоретически оставляют минимальные шансы на решение задачи методом подбора. Но…
В-пятых, в некоторых случаях авторы сайта кодируют имя интересующего нас файла, например, применив к нему хэш-функцию. Такой ход делает решение задачи методом подбора невозможным.
Подход с имитацией действий пользователя
Если мы не можем решить задачу методом подбора частей нового имени интересующего нас файла, то попробуем поступить так, как это делает пользователь-человек, на восприятие которого сайт и рассчитан.
Пользователь заходит на домашнюю (корневую) страницу сайта и ищет интересующую его информацию, переходя по ссылкам, пока не увидит текст, указывающий ему на интересующий файл. Этот текст он находит на Web странице, являющейся для искомого файла родительской. Альтернативно, пользователь может выйти на родительскую страницу непосредственно из поисковой машины. В любом случае перед скачиванием необходимого файла пользователь находится на родительской странице и видит ссылку на файл.
Соответственно, если бы наш робот в момент получения задания на слежение за интересующим файлом мог определить его родительскую страницу, а затем, уже после изменения имени файла смог бы найти на родительской странице необходимую ссылку, то задача поиска файла с изменившимся именем была бы решена.
Наша совокупная задача делится на две разнесенные во времени части, а наш робот, соответственно, на два компонента:
- спайдер (паук) будет искать родительскую страницу,
- скаут (разведчик) – изменившуюся ссылку, расположенную на родительской странице.
Спайдер
Первая часть робота – спайдер – запускается однократно в момент получения задания на слежение за файлом в предположении, что адрес интересующего файла в этот момент верен.
Спайдер определяет по полученному адресу файла корень сайта и начинает методично выявлять ссылки, переходить по ним, вновь определять ссылки – пока не найдет указанный ему в задании адрес. В этот момент он остановит свое путешествие по сайту и отметит в своей базе данных адрес родительской страницы наблюдаемого файла, а также важные параметры ссылки на наблюдаемый файл: его имя, текст ссылки, ее положение на родительской странице и т.п.
На этом спайдер завершит свой однократный «вертикальный» проход по сайту и передаст дела скауту – второй части робота, действующей «горизонтально».
Скаут
Вторая часть робота – скаут – запускается регулярно в предположении, что адрес интересующего файла может измениться в любой момент без предупреждения и извещения.
Скаут получает у спайдера адрес родительской страницы наблюдаемого файла, скачивает ее и анализирует на предмет выявления ссылок и в предположении, что одна из них и есть изменившаяся ссылка на наблюдаемый файл. Его задача по собранным спайдером данным о – старой! – ссылке на файл с максимальной вероятностью найти – новую! – ссылку на файл.
Эта часть задачи является самой сложной: мы предполагаем, что на родительской странице присутствует ссылка на интересующий нас файл, но она изменилась. Мы должны реализовать понятие сходства: новая ссылка, которую мы ищем, должна быть похожей на старую. Вопрос сходства является весьма нетривиальным. Если бы у нас были только имена файлов с переменной датой стабильного формата, мы могли бы оперировать понятием маски, могли бы попытаться применить механизм регулярных выражений. Но, во-первых, дата в формате d.mm.yy и дата в формате dd.mm.yy – это уже большая проблема, поскольку формат разный, во-вторых, для Oracle эти два формата означают разное: dd – это номер дня в месяце, а d – номер дня в неделе, причем отсчитываемый в зависимости от национальных установок от разного наименования дня недели. Сложности добавляет возможное наличие номера в имени файла, небольшие искажения формата и содержания постоянной части. И напрочь закрывает вопрос о применении маски хэширование имени файла.
На помощь приходят встроенные в Oracle методы определения лингвистической близости – Левенштейна и Джаро-Винклера. Они позволяют численно оценить похожесть двух строк, в нашем случае старого имени файла и всех, обнаруженных в данный момент на родительской странице. Тогда обнаруженная ссылка, имеющая наибольшее лингвистическое сходство со старой, может считаться кандидатом на искомое новое имя файла.
Этот метод прекрасно работает в простых случаях смены даты в имени файла, небольших отклонений формата его постоянной или переменной части. Но дает сбой в случае, если все ссылки на анализируемой родительской странице представлены хэшами. Действительно, хэш от имени искомого файла и хэш от имени файла, скажем, рекламной картинки никак между собой и со старым именем файла не связаны, их лингвистическая близость с точки зрения нашей задачи абсолютно случайна.
В этом случае приходится подключать анализ всех свойств наблюдаемой ссылки, которую мы можем собрать в фазе работы спайдера: адрес ссылки, видимый пользователем текст ссылки, расположение ссылки на родительской странице, тип файла и т.п. Далее может быть выполнено частное ранжирование всех выявленных скаутом ссылок по этим свойствам с последующим глобальным ранжированием. Вероятность попадания в необходимую изменившуюся ссылку при этом зависит от алгоритмов частного и глобального ранжирования.
Эпилог
Рассмотренные в статье методы позволили разработать и запустить на дежурство робот, с высокой вероятностью определяющий меняющиеся во времени адреса Web ссылок на отслеживаемые файлы.
Удалось создать робот, оказывающий минимальное воздействие на отслеживаемые сайты и не вызывающий повышенного критического внимания администраторов этих сайтов.
В краткой статье не представляется возможным рассмотреть все технологические аспекты созданного программного продукта, многие принципы изложены упрощенно.