В Сети накоплено огромное количество данных, и все актуальнее становится задача их получения в динамике непосредственно из первоисточников, c извлечением нужного контента «на лету», что позволяет избежать избыточности и не требует организации промежуточного хранения. Это особенно важно, если данные по своей природе не постоянны: контакты лиц и организаций, цены на товары, рейтинги заведений массового обслуживания, нормативные документы и пр. Нередки ситуации, когда в списке организаций, размещенном на портале какого-либо агрегатора, адреса устарели, хотя на сайте самой организации информация актуальна, либо когда на товар в магазине назначена скидка, а у агрегатора цен это еще не отражено. Для разного рода нормативных документов важны дата их размещения в Сети и дата последнего обновления [1, 2]. Кроме того, автоматическое извлечение информации из веб-ресурсов, или динамический веб-скрейпинг (real-time web scraping), может использоваться для отслеживания цен конкурентов, для получения биржевых сводок, для анализа состояния рынка труда, для получения сведений о погоде и пр.

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

Инструменты веб-скрейпинга

Имеется множество инструментов веб-скрейпинга: библиотеки, приложения для десктопа, online-сервисы, облачные сервисы, плагины к браузерам. Скрейперы обычно сочетаются с краулерами (поисковыми роботами), что позволяет извлекать информацию не только из конкретной веб-страницы, но и из страниц, на которые выводят гиперссылки. Поскольку веб-страницы часто бывают динамическими, некоторые инструменты позволяют извлекать информацию из HTML-кода, который получается после отработки скриптов.

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

Scrapy — фреймворк с открытым кодом, включающий библиотеку на языке Python, облачный сервис для запуска веб-скрейперов, средства отладки и средство ScrapyRT для создания REST API, который может возвращать результат работы скрейпера, запущенного ранее, а также запускать скрейпер и возвращать результат его работы в режиме реального времени.

Apache Any23 (Anything To Triples) — свободно распространяемый инструмент для извлечения из веб-ресурсов структурированных данных, включающий библиотеку на языке Java, веб-службу и интерфейс командной строки. Извлеченные структурированные данные представляются в виде RDF. Возможна работа с Rdfa, микроформатами, JSON-LD, микроданными, CSV, YAML. Поддерживаются словари Dublin Core Terms, Description of a Career, Description Of A Project, Friend Of A Friend, GEO Names, ICAL, lkif-core, Open Graph Protocol, BBC Programmes Ontology, RDF Review Vocabulary, schema.org, VCard, BBC Wildlife Ontology, XHTML и др. Веб-сервис представляет собой REST API, который может быть загружен с сайта Any23 и установлен на сервере пользователя. Ему можно передать в качестве аргументов URL интересующего ресурса и желаемый формат представления полученных данных.

Import.IO — одна из наиболее популярных платформ среди коммерческих реализаций. Включает инструменты для создания скрейперов, облачную платформу для их запуска, а также разные REST API, среди которых имеется API, позволяющий запускать созданный ранее скрейпер и получать его результаты в реальном времени. Имеется поддержка CORS.

Html Agility Pack — открытая библиотека на С#, позволяющая извлекать данные из HTML-страниц с использованием Xpath. ScrapySharp — расширение Html Agility Pack для извлечения данных с использованием CSS-селекторов и поддержкой динамических страниц. Extruct — библиотека на Python для извлечения структурированных данных с поддержкой форматов JSON-LD, «микроданных», RDFa.

Компания «Яндекс» предоставляет API к своему онлайн-валидатору микроразметки, при помощи которого из веб-страниц можно извлекать структурированные данные форматов JSON-LD, RDFa, микроданные (microdata) и микроформаты.

 

Набирает популярность семантическая разметка, используя которую поисковые системы адекватно отображают содержимое сайтов. Уже половина из 10 млн наиболее популярных сайтов Сети используют тот или иной вид разметки. В частности, разметку JSON-LD применяют более четверти сайтов [3]. При наличии семантической разметки возможно извлечение данных из веб-ресурсов без программирования или конструирования алгоритма — такую возможность предоставляют, например, веб-сервис Apache Any23 или API валидатора микроразметки от «Яндекс». Однако эти инструменты не предназначены для обращения к ним из веб-страниц с целью извлечения «на лету» данных из нескольких источников и имеют ряд недостатков при таком использовании: для получения данных надо делать отдельный запрос для каждого из источников, из-за чего увеличивается общее время обработки; в запросе нельзя указать тип данных (результат включает все данные, имеющиеся в разметке) и т. п. Стоит отметить также, что, какой бы из имеющихся инструментов ни использовался, для включения в контент веб-страницы извлеченных данных ее создатель должен писать программный код для клиентской части веб-приложения, что требует определенных навыков.

 

Микроразметка

Для создания веб-страницы с актуальными данными, собранными из различных внешних источников, предназначен инструмент StructScraper [4], не требующий кодирования ни на серверной, ни на клиентской стороне. Для его использования необходимо только знание HTML и CSS. При работе со StructScraper автору достаточно разметить HTML-страницу и подключить стартовые скрипты, вставив в страницу фрагмент уже готового кода, а вся остальная работа выполняется автоматически в процессе загрузки страницы.

Инструмент позволяет включать в контент веб-страницы семантические данные веб-ресурсов из словаря Schema.org, содержащиеся в микроразметках «микроданными» и JSON-LD, а также метаданные (для HTML — извлеченные из тегов "meta"; для документов формата PDF, DOC и DOCX — из встроенных и пользовательских свойств). Он может быть полезен блогерам, авторам страниц с кулинарными рецептами, трейдерам для сравнения цен и котировок, аналитикам, маркетологам и пр.

Серверная часть StructScraper представляет собой REST API для извлечения данных — ее можно использовать как вместе с клиентской частью, так и самостоятельно.

Клиентская часть включает jQuery-плагины, вызов которых при загрузке веб-страницы выполняет работу по добавлению данных в контент. REST API, входящий в состав StructScraper, допускает кросс-доменные запросы в соответствии с технологией CORS, что избавляет от необходимости устанавливать его на сервере пользователя.

 

Отображение данных из кросс-доменных ресурсов

Дополнительную сложность для извлечения «на лету» информации из внешних ресурсов (помимо слабой структурированности) создает правило одного источника — Same Origin Policy («правило одного домена», «принцип одинакового источника», «политика одного домена» и т. п.). Это правило введено из соображений безопасности с целью дать возможность коду из веб-страницы одного сайта свободно взаимодействовать с ресурсами этого же сайта, но максимально ограничив такое взаимодействие с ресурсами других сайтов. Без такого ограничения скрипт из страницы, загруженной с какого-нибудь сайта, может обратиться, например, к почтовому серверу пользователя через сессию, открытую в другом окне браузера, получить его почту или отправить от его имени письмо, что непременно бы использовали злоумышленники.

Считается, что два ресурса имеют один и тот же источник, если в их веб-адресах совпадают протокол, домен и порт. Запросы из веб-страниц к сторонним источникам (cross-origin requests) в русскоязычной литературе называют кросс-доменными запросами, хотя это и не совсем корректно. В соответствии с правилом одного источника, браузеры запрещают производить кросс-доменные запросы через XMLHttpRequest API, и до появления технологии CORS (fetch.spec.whatwg.org/#http-cors-protocol) такие запросы были полностью запрещены. Технология CORS частично сняла этот запрет: запросы к стороннему серверу можно осуществлять, если сторонний сервер дает на это явное разрешение. При этом сервер также контролирует детали кросс-доменных запросов: разрешенные методы, возможности передачи авторизующих заголовков и т. п.

В зависимости от того, что представляет собой кросс-доменный ресурс, и от того, допускает ли его сервер кросс-доменные запросы, для получения данных из него используются разные методы. Идеальный вариант — когда сайт, данные которого требуется показывать на веб-странице, предоставляет их через API с разрешенным кросс-доменным доступом. В этом случае получить данные можно, непосредственно выполнив ajax-запрос. Если API отсутствует, но ресурс представляет собой html- или xml-документ, к которому разрешен кросс-доменный доступ, то через ajax-запрос можно получить текст документа и выполнить его разбор средствами JavaScript. Если кросс-доменные запросы не разрешены, то можно получить содержимое документа с помощью запроса к одному из имеющихся в Сети прокси-сервисов (allorigins.win, corsproxy.github.io), позволяющих обойти правило одного источника и разрешающих кросс-доменный доступ.

Для получения данных из кросс-доменных ресурсов используют также технику JSONP (JSON with padding), применяющую для запросов не XMLHttpRequest, а тег "script", из которого не запрещены обращения к кросс-доменным ресурсам. Формат JSONP — это JSON, «обернутый» вызовом JavaScript-функции, однако техника JSONP, в отличие от СORS, позволяет делать только GET-запросы.

Еще один метод, используемый для обхода правила одного источника, — метод промежуточного сервера, при котором запрос направляется не напрямую к стороннему серверу, а к промежуточному, находящемуся в том же домене, что и веб-страница. Промежуточный сервер перенаправляет запрос к стороннему, получает ответ и посылает его клиенту. Метод основан на том, что правило одного источника относится только к клиентской части веб-приложения и реализуется браузерами, а запросы от сервера к серверу не ограничиваются. Однако со стороны стороннего сервера могут быть ограничения другого характера. Например, некоторые допускают запросы только через браузеры и имеют механизмы защиты от роботов, а другие блокируют веб-адрес, если запросы с него приходят слишком часто. Метод промежуточного сервера особенно удобен в тех случаях, когда данные, поступающие от стороннего сервера, имеют сложную структуру (Word, PDF и пр.), а в клиентской части нужна только их часть. Извлечение данных из ресурсов таких форматов средствами JavaScript невозможно — требуются специальные библиотеки. И хотя с появлением технологии Web Assembly теперь можно выполнять обработку подобных форматов в клиентской части веб-приложения, написанный с применением этой технологии код может не работать, поскольку поддержка этой технологии была включена во все основные версии браузеров лишь в конце 2017 года.

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

 

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

Рис. 1. Запрос к веб-ресурсу через прокси-API

 

В общем случае использование промежуточного REST API требует программирования для извлечения данных на серверной стороне. REST API для извлечения данных можно создать, пользуясь, например, инструментами Scrapy и ScrapyRT. При помощи первого на языке Python программируется алгоритм извлечения данных, а при помощи второго создается REST API. Для извлечения структурированных данных, содержащихся в микроразметках, можно также воспользоваться REST API, входящим в состав Apache Any23 или API валидатора микроразметки «Яндекса». В этом случае программирования на серверной стороне не требуется, однако для задачи представления на веб-странице данных из нескольких веб-ресурсов эти REST API неудобны. В запросе к этим сервисам можно указать только один адрес URL, что увеличивает время обработки. На обращения к API валидатора микроразметки установлено ограничение: не более 10 запросов в секунду с одного ключа. В случае, если адресов больше, придется ждать секунду, прежде чем делать запросы для остальных адресов. Еще один недостаток этих сервисов в том, что возвращаемый ими результат содержит все структурированные данные, имеющиеся в микроразметках ресурса. Для включения в веб-страницу, как правило, все эти данные полностью не нужны. Если бы была возможность извлекать данные только определенного типа, это сократило бы трафик и упростило программирование на клиентской стороне.

REST API StructScraper реализован на языке C#, имеющем встроенную поддержку асинхронного программирования. Для извлечения микроданных был создан парсер на основе предварительной версии парсера Chapleau.MicrodataParser.

Веб-API имеет три контроллера: для извлечения отдельных метаданных из конкретных тегов, тегов "meta" и свойств документов в форматах Word и PDF, для извлечения микроданных определенного типа и для извлечения данных формата JSON-LD определенного типа. Каждый из контроллеров имеет по два POST-метода: для одного URL и для нескольких URL. Параметры запроса передаются в формате JSON и содержат адреса веб-ресурсов, из которых необходимо извлечь данные и сведения о том, какие именно данные должны быть извлечены. Для метаданных, извлекаемых из тегов и свойств документов, передаются названия; для микроданных и разметки JSON-LD передается тип из словаря Schema.org.

Преимущества предлагаемого REST API по сравнению с имеющимися в свободном доступе REST API для извлечения структурированных данных заключаются в том, что структурированные данные извлекаются не только из HTML-документов, но и из свойств документов формата Word и PDF; из HTML-документов извлекаются не все структурированные данные, а только те, которые указаны в запросе; в одном запросе можно задать несколько URL.

Рис. 2. Запрос к нескольким веб-ресурсам через прокси-API

 

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

REST API StructScraper допускает CORS, запросы к нему могут производиться из клиентских частей веб-приложений любых доменов.

Работу по загрузке клиентом данных на веб-страницу осуществляет JavaScript-код, оформленный в виде плагинов jQuery [4]. Для того чтобы плагин загрузил данные на веб-страницу, в нее должна быть добавлена специальная разметка, по которой код плагина определяет, из каких веб-ресурсов должны быть загружены данные и какие именно данные необходимо загрузить. Эта разметка использует атрибуты class.

Пример разметки для извлечения метаданных показан в файле test-meta.html на GitHub, а соответствующая веб-страница с подгружаемыми метаданными имеется на alive.keldysh.ru/Test_Pages/test-meta.html. На GitHuв приводятся также примеры разметок для извлечения JSON-LD и микроданных.

Рис. 3. Цены на одну модель телефона в разных интернет-магазинах, актуальные на момент загрузки страницы

 

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

***

Сегодня во Всемирной паутине еще редко встречаются страницы, предъявляющие посетителю информацию из нескольких активно обновляемых сайтов, собранную именно в момент обращения к этой странице. Инструмент StructScraper позволяет создавать такие страницы без программирования при работе с сайтами, имеющими семантическую разметку. Модуль метаданных серверной части StructScraper несколько лет работает в режиме промышленной эксплуатации. В частности, на сайте ИПМ им. М. В. Келдыша — для добавления в ссылки на «живые» публикации даты последней редакции документов. В дальнейшем планируется расширить возможности инструмента за счет добавления средств обработки страниц, использующих gzip-сжатие, загрузки изображений, задания списка типов из словаря Schema.org, извлечения данных из разметки RDFa Lite и др. 

Литература

1. Горбунов-Посадов М.М. Живая публикация // Открытые системы — 2011. — № 4. — С. 51–52. URL: http://keldysh.ru/gorbunov/live.htm (дата обращения: 21.09.2019).

2. Горбунов-Посадов М.М., Скорнякова Р.Ю. Обновляемая дата последней редакции в ссылке на живую публикацию // Препринты ИПМ им. М.В. Келдыша. 2017. № 82. 14 с. doi:10.20948/prepr-2017-82 URL: http://library.keldysh.ru/preprint.asp-id=2017-82 (дата обращения: 01.09.2019).

3. Usage Statistics of Structured Data Formats for Websites. URL: https://w3techs.com/technologies/overview/structured_data/all (дата обращения: 01.09.2019).

4. StructScraper на GitHub. URL: https://github.com/RimmaSkorn/struct-scraper (дата обращения: 01.09.2019). 

Евгений Китаев ( kitaev@keldysh.ru ), Римма Скорнякова ( RimmaSkorn@gmail.com )  —  сотрудники, ИПМ им. М.В. Келдыша РАН (Москва).