Статьи

Укрощение Snoo: игра с Reddit API

Reddit — это социальная сеть, развлекательный и новостной веб-сайт, где контент почти исключительно предоставляется пользователями. Согласно этому отчету , в феврале 2016 года Reddit имел 36 миллионов учетных записей пользователей, 231 миллион уникальных ежемесячных посещений и 11,464 активных сообщества. Недавнее исследование также показало, что 80% пользователей Reddit получают новости оттуда .

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

Реалистичная Reddit Alien Painting

Reddit API

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

В этой статье мы сначала сосредоточимся на методе search . Хотя это публичный вызов (он не требует аутентификации), он также является одним из самых мощных, поскольку он позволяет нам получать доступ ко всей истории сообщений Reddit в каждом субреддите.

Метод поиска

Метод search доступен через базовый HTTP-запрос и имеет множество свойств. Глядя на документацию , мы видим, что он поддерживает метод HTTP GET и доступен через

 https://www.reddit.com/[/r/subreddit]/search 

У нас также есть следующие доступные аргументы: after , before , count , include_facets , limit , q , restrict_sr , show , sort , sr_detail , syntax , t и type . Таблица ниже может быть найдена в документации и показывает каждый аргумент более подробно.

аргументация Принимает
после полное название вещи
перед полное название вещи
подсчитывать положительное целое число (по умолчанию: 0)
include_facets логическое значение
предел максимальное количество желаемых предметов (по умолчанию: 25, максимум: 100)
Q строка длиной не более 512 символов
restrict_sr логическое значение
Показать (необязательно) строка все
Сортировать один из (релевантность, горячие, топ, новые, комментарии)
sr_detail (необязательно) расширить субредакты
синтаксис один из (cloudsearch, lucene, plain)
T один из (час, день, неделя, месяц, год, все)
тип (необязательно) список типов результатов, разделенных запятыми (sr, ссылка)

Мы сосредоточимся на аргументах q , limit , sort и restrict_sr .

Аргумент q является наиболее важным и указывает на запрос, по которому мы будем искать данный подредит. Пример использования будет:

 https://www.reddit.com/r/php/search.json?q=oop 

Этот конкретный вызов будет искать выражение oop в субреддите php . Если вы попытаетесь позвонить с помощью браузера, вы увидите результаты (просто скопируйте и вставьте ссылку в браузер).

Аргумент limit ограничивает количество сообщений, которые будут иметь возвращаемый список. Пример использования будет:

 https://www.reddit.com/r/php/search.json?q=oop&limit=5 

Этот конкретный поиск вернул бы первые 5 результатов поиска выражения oop в субреддите php .

Аргумент sort сортирует искомые записи, используя одно из пяти свойств порядка Reddit: hot , new , comments , relevance и top . Таким образом, если мы хотим найти в php subreddit новые сообщения oop мы можем сделать следующий вызов:

 https://www.reddit.com/r/php/search.json?q=oop&sort=new 

restrict_sr — это логическое значение, которое указывает, хотим ли мы ограничить наш поиск текущим subreddit. Если мы передадим 0, мы будем искать все Reddit.

 https://www.reddit.com/r/php/search.json?q=oop&sort=new&restrict_sr=1 

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

Добавление PHP

Возможность вызывать API через наш браузер — это весело, но мы хотим что-то более мощное. Мы хотим иметь возможность анализировать и использовать полученную информацию различными способами.

Для этого примера использования Reddit API с PHP мы могли бы использовать cURL , но, хотя навыки cURL могут быть полезны, в настоящее время это довольно устаревший инструмент. Мы будем использовать библиотеку под названием Guzzle и установим ее с помощью Composer .

 composer require guzzlehttp/guzzle 

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

 <?php namespace ApiReddit; require_once './vendor/autoload.php'; class Searcher { /** * This method queries the reddit API for searches * * @param $subreddit The subreddit to search * @param $query The term to search for * @param $options The filter used to search * @param $results The number of results to return * **/ public function execSearch($subreddit = 'php', $query, $options, $results = 10) { //Executes an http request using guzzle $client = new \GuzzleHttp\Client([ 'headers' => ['User-Agent' => 'testing/1.0'], 'verify' => false]); $response = $client->request("GET", 'https://reddit.com/r/' . $subreddit . '/search.json', ['query' => 'q=' . $query . '&sort=' . $options . '&restrict_sr=1&limit=' . $results ]); $body = $response->getBody(true); return $body; } } 

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

Далее мы создадим файл index.php который будет запрашивать Reddit API. Мы будем использовать Twig для визуализации нашего представления и отображения результатов в виде таблицы. Затем мы создадим папку /templates в корне нашего проекта. Эта папка будет содержать наши шаблоны Twig.

 composer require twig/twig 

Файл index.php :

 <?php require __DIR__.'/vendor/autoload.php'; use ApiReddit\Searcher; //Executes a new search $search = new Searcher(); $json=$search->execSearch( 'php', 'composer', 'hot', 5); $data = json_decode($json); //Loads the results in Twig $loader = new Twig_Loader_Filesystem(__DIR__.'/templates'); $twig = new Twig_Environment($loader, array()); //Renders our view echo $twig->render('index.twig', array( 'results' => $data->data->children, )); 

После загрузки Twig, мы сообщаем ему, где мы храним наши шаблоны и отображаем index.twig .

Мы также хотим создать файл resources/style.css для resources/style.css наших результатов. Этот файл содержит следующее:

 #posts td, #posts th { border: 1px solid #ddd; text-align: left; padding: 8px; } #posts th { padding-top: 11px; padding-bottom: 11px; background-color: #4CAF50; color: white; } 

Наконец, мы создадим наш файл шаблона с учетом как наших результатов, так и CSS. Внутри папки /templates , давайте создадим файл index.twig :

 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <title>Reddit Search Table</title> <link rel="stylesheet" type="text/css" href="resources/style.css"> </head> <body> <table id='posts'> <tr> <th>Title</th> <th>Ups</th> <th>Downs</th> <th>Created At</th> <th>Subreddit</th> <th>Number of Comments</th> <th>Link</th> </tr> {% for item in results %} <tr> <td>{{ item.data.title }}</td> <td>{{ item.data.ups }}</td> <td>{{ item.data.downs }}</td> <td>{{ item.data.created_utc }}</td> <td>{{ item.data.subreddits }}</td> <td>{{ item.data.num_comments }}</td> <td>{{ item.data.permalink }}</td> </tr> {% endfor %} </table> </body> </html> 

Наш конечный результат здесь:

Таблица результатов

Добавление аутентификации

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

После того, как у нас есть учетная запись и прежде чем мы сможем получить доступ к API, необходимо выполнить некоторые настройки. Войдите в свою учетную запись, и в правом верхнем углу вы увидите кнопку «настройки». Нажмите на нее и перейдите на вкладку «Приложения», затем нажмите «Создать».

Заполните информацию (и не забывайте, что URI перенаправления должен быть именно тем, который мы собираемся использовать в нашем приложении). Мы можем оставить поле about url пустым.

После этого нажмите « Create App . Это даст нам доступ к идентификатору клиента и секретному токену. Мы будем использовать эту информацию для аутентификации через API OAuth2. Для аутентификации Oauth2 мы будем использовать очень известный пакет adoy/oauth2 . Этот пакет представляет собой легкую оболочку PHP для протокола OAuth 2.0 (на основе протокола авторизации OAuth 2.0 draft-ietf-oauth-v2-15).

 composer require adoy/oauth2 

Теперь, когда у нас есть инструменты для использования Oauth2, давайте создадим файл с именем Oauth.php в корне нашего проекта со следующим содержимым:

 <?php require_once './vendor/autoload.php'; use ApiReddit\Authenticator; $authorizeUrl = 'https://ssl.reddit.com/api/v1/authorize'; $accessTokenUrl = 'https://ssl.reddit.com/api/v1/access_token'; $clientId = 'Your Client Id'; $clientSecret = 'Your Secret'; $userAgent = 'RedditApiClient/0.1 by YourName'; $redirectUrl = "Your redirect url"; $auth = new Authenticator( $authorizeUrl, $accessTokenUrl, $clientId, $clientSecret, $userAgent, $redirectUrl ); $auth->authenticate(); 

Мы создаем экземпляр Authenticator и вызываем метод authenticate() . Мы также автоматически загружаем класс, добавляя его в Composer. Чтобы это работало, давайте создадим файл класса Authenticator.php в нашей папке /src .

 <?php namespace ApiReddit; class Authenticator { public function __construct($authorizeUrl, $accessTokenUrl, $clientId, $clientSecret, $userAgent, $redirectUrl) { $this->authorizeUrl = $authorizeUrl; $this->accessTokenUrl = $accessTokenUrl; $this->clientId = $clientId; $this->clientSecret = $clientSecret; $this->userAgent = $userAgent; $this->redirectUrl = $redirectUrl; } public function authenticate() { $client = new \OAuth2\Client($this->clientId, $this->clientSecret, \OAuth2\Client::AUTH_TYPE_AUTHORIZATION_BASIC); $client->setCurlOption(CURLOPT_USERAGENT, $this->userAgent); if (!isset($_GET["code"])) { $authUrl = $client->getAuthenticationUrl($this->authorizeUrl, $this->redirectUrl, array( "scope" => "identity", "state" => "SomeUnguessableValue" )); header("Location: " . $authUrl); die("Redirect"); } else { //$this->getUserPreferences($client, $this->accessTokenUrl); } } } 

В файле Oauth.php мы инициализируем переменные нашего проекта всеми данными, необходимыми для аутентификации через API. Authenticator.php — это место, где происходит волшебство.

Мы создаем новый экземпляр клиента OAuth2 с нашим идентификатором и секретом, используя adoy . После этого используется базовая логика OAuth: мы используем URL-адрес аутентификации для выполнения аутентификации и перенаправляем туда, куда мы будем перенаправлены после аутентификации.

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

И последнее, но не менее важное: у нас есть строка с комментариями. Это было специально. Метод getUserPreferences метод API, который мы хотим использовать. Итак, давайте раскомментируем эту строку и реализуем метод ниже.

 /** * This function will request the Reddit API for the user information * * @param $client The client ID * @param $accessToken The access token given */ public function getUserPreferences( $client, $accessToken ) { $params = array("code" => $_GET["code"], "redirect_uri" => $this->redirectUrl); $response = $client->getAccessToken($accessToken, "authorization_code", $params); $accessTokenResult = $response["result"]; $client->setAccessToken($accessTokenResult["access_token"]); $client->setAccessTokenType(OAuth2\Client::ACCESS_TOKEN_BEARER); $response = $client->fetch("https://oauth.reddit.com/api/v1/me.json"); echo('<strong>Response for fetch me.json:</strong><pre>'); print_r($response); echo('</pre>'); } - /** * This function will request the Reddit API for the user information * * @param $client The client ID * @param $accessToken The access token given */ public function getUserPreferences( $client, $accessToken ) { $params = array("code" => $_GET["code"], "redirect_uri" => $this->redirectUrl); $response = $client->getAccessToken($accessToken, "authorization_code", $params); $accessTokenResult = $response["result"]; $client->setAccessToken($accessTokenResult["access_token"]); $client->setAccessTokenType(OAuth2\Client::ACCESS_TOKEN_BEARER); $response = $client->fetch("https://oauth.reddit.com/api/v1/me.json"); echo('<strong>Response for fetch me.json:</strong><pre>'); print_r($response); echo('</pre>'); } 

Мы получаем токен доступа и используем его в нашем звонке для получения информации с https://oauth.reddit.com/api/v1/me.json . Этот метод GET вернет личность аутентифицированного пользователя. Ответом будет массив json.

Если мы запустим его, мы попадем на страницу входа, как это и должно случиться с OAuth. После входа нам будет предложено ввести следующую страницу:

Разрешить доступ

Просто нажмите «разрешить», и если все прошло правильно, у нас должен быть массив json, содержащий всю информацию о пользователе, с которым мы только что аутентифицировались.

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

Весь код можно найти в этом репозитории github .

Вывод

Мы узнали, как использовать функцию поиска API Reddit, и впервые взглянули на аутентификацию и использование методов, которые требуют входа в систему. Но мы просто поцарапали поверхность.

Возможности огромны, потому что Reddit API дает нам доступ к почти бесконечному пулу знаний. Обязательно ознакомьтесь со всей документацией по Reddit API, поскольку она предлагает гораздо больше, и дайте нам знать, если вы создадите что-нибудь интересное!