- PVSM.RU - https://www.pvsm.ru -
У меня достаточно часто появляется задача получить данные от стороннего сайта, при этом далеко не всегда этот сайт предоставляет возможность удобно получить эти данные через API. Единственное решение в таком случае — парсить html содержимое страниц. Когда-то я писал регэкспы, потом появились библиотеки, позволяющие получить нужное содержимое по css-селектору, а сейчас и это кажется сложной задачей, которую хотелось бы упростить.
Сегодня я хочу рассказать вам о моей небольшой библиотеке, позволяющей описать в API-стиле http-запросы и парсить ответ сервера в нужный вам формат.
Примечание: не стоит забывать об авторских правах, если вы используете чужие данные.
Библиотека доступна к установке через composer, поэтому все, что необходимо сделать — это добавить зависимость «sleeping-owl/apist»: «1.*» в ваш composer.json и вызвать composer update.
У данной библиотеки нет зависимостей от каких-либо фреймворков, поэтому вы можете использовать ее с любым фреймворком, либо же в чистом PHP-проекте. Для сетевых запросов используется Guzzle, для манипуляций с dom-деревом используется «symfony/dom-crawler».
После установки вы можете приступить к созданию нового класса, олицетворяющего API нужного вам сайта. Библиотека не накладывает никаких ограничений на то, как и где вы будете создавать свой класс. Нужно расширить класс SleepingOwlApistApist и указать базовый урл:
use SleepingOwlApistApist;
class HabrApi extends Apist
{
protected $baseUrl = 'http://habrahabr.ru';
}
Это все, что нужно для базового описания. Далее вы можете добавлять в данный класс методы, которые вам нужны:
public function index()
{
return $this->get('/', [
'title' => Apist::filter('.page_head .title')->text()->trim(),
'posts' => Apist::filter('.posts .post')->each([
'title' => Apist::filter('h1.title a')->text(),
'link' => Apist::filter('h1.title a')->attr('href'),
'hubs' => Apist::filter('.hubs a')->each(Apist::filter('*')->text()),
'author' => [
'username' => Apist::filter('.author a'),
'profile_link' => Apist::filter('.author a')->attr('href'),
'rating' => Apist::filter('.author .rating')->text()
]
])
]);
}
Здесь метод «get» — это тип используемого http-запроса, также доступны остальные методы (post, put, patch, delete и т.д.).
Первый параметр — урл данного метода, он может быть как относительным, так и абсолютным.
Второй параметр — это и есть та основа, из-за которой я создал эту библиотеку. Он описывает структуру, которую необходимо получить в результате вызова данного метода. Это может быть как массив, так и одиночное значение. То есть для описанного выше метода результат будет такого вида:
$api = new HabrApi;
$result = $api->index();
Примечание: результат будет типа array, json-формат здесь использован для удобства.
{
"title": "Публикации",
"posts": [
{
"title": "Проверьте своего хостера на уязвимость Shellshock (часть 2)",
"link": "http://habrahabr.ru/company/host-tracker/blog/240389/",
"hubs": [
"Блог компании ХостТрекер",
"Серверное администрирование",
"Информационная безопасность"
],
"author": {
"username": "smiHT",
"profile_link": "http://habrahabr.ru/users/smiHT/",
"rating": "26,9"
}
},
{
"title": "Курсы этичного хакинга и тестирования на проникновение от PentestIT",
"link": "http://habrahabr.ru/company/pentestit/blog/240995/",
"hubs": [
"Блог компании PentestIT",
"Учебный процесс в IT",
"Информационная безопасность"
],
"author": {
"username": "pentestit-team",
"profile_link": "http://habrahabr.ru/users/pentestit-team/",
"rating": "36,4"
}
},
...
]
}
Третьим опциональным параметром могут идти любые дополнительные параметры запроса, get или post переменные, загружаемые файлы, заголовки запроса и т.п. С полным списком можно ознакомиться в документации Guzzle [1].
Пара слов о том, как это работает: каждый объект, созданный через Apist::filter($cssSelector) после загрузки данных заменяется на нужное значение, он сохраняет не только сам селектор, по которому он будет искать данные, но и всю вереницу вызовов, которые к нему были применены. После загрузки данных он пытается применить эти методы к найденным элементам.
Вот некоторые типы методов, которые могут быть применены (вы можете комбинировать их в нужной вам последовательности):
Apist::filter('.navbar li')->eq(3)->filter('a.active')->text();
Apist::filter('input')->first()->attr('value');
Apist::filter('.content')->html();
Apist::filter('body')->element();
// Вернет объект класса SymfonyComponentDomCrawlerCrawler, отвечающий за элемент body
Apist::filter('.post')->each(...);
// Этот объект будет заменен на массив, каждый элемент которого будет создан согласно схеме, которая была передана параметром. Все внутренние css-селекторы будут применены относительно текущего элемента.
Apist::filter('.errors')->exists()->then(...)->else(...);
// Описывает условие, если элемент с классом "errors" был найден, то используется значение из блока "then", иначе из блока "else"
Apist::filter('.title')->text()->mb_strtoupper()->trim()->substr(5);
function myFunc($string, $find, $replace)
{
return str_replace($find, $replace, $string);
}
Apist::filter('.title')->text()->myFunc('My', 'Your');
// Если убрать ->text(), то в функцию будет передан объект, а не строка. Это можно использовать в своих целях при необходимости.
Исходники демо-класса HabrApi.php, используемого в примерах на сайте проекта можно посмотреть здесь [2].
Исходники на GitHub [3] | Документация и примеры [4]
Автор: sleeping-owl
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/php-2/72528
Ссылки в тексте:
[1] в документации Guzzle: http://guzzle.readthedocs.org/en/latest/clients.html#request-options
[2] здесь: https://github.com/sleeping-owl/apist-docs/blob/master/app/Demo/HabrApi.php
[3] Исходники на GitHub: https://github.com/sleeping-owl/apist
[4] Документация и примеры: http://sleeping-owl-apist.gopagoda.com
[5] Источник: http://habrahabr.ru/post/241335/
Нажмите здесь для печати.