Получение данных из Google Reader с помощью cURL

Владимир | | PHP, Web разработка.

google reader curl logo

В этой статье я продолжу тему использования cURL. Мы попробуем с помощью этой утилиты войти (аутентифицироваться) и получить список тегов из Google Reader.

Сразу объясню, в чем сложность работы с этим сервисом. Дело в том, что он использует немного необычный способ передачи cookie файлов и из-за этого усложняется аутентификация.

Когда вы заполняете форму входа и отправляете запрос, на большинстве сайтов они в ответ передают страницу и в заголовках cookie файлы. Эти файлы автоматически сохраняются (cURL'ом или браузером) и вы можете использовать их в дальнейших запросах.

Но аутентификация на Google выполняется иначе.

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

Когда вы заходите в Google Reader с помощью браузера, все эти операции выполняются JS-скриптами.

В cURL поддержка JS не входит, поэтому все придется делать ручками 😉

Тут я хочу сделать небольшое отступление.

Во-первых, насколько я знаю, на данных момент API для Google Reader нет. Поэтому все примеры из этой статьи в какой-то момент можут просто перестать работать. Для этого достаточно чтобы разработчики Reader'а совсем чуть-чуть изменили протокол.

Во-вторых, основным источником информации является неофициальный GoogleReaderAPI. Учтите, что статья была написана в 2007, и с тех пор протокол успел немного измениться, поэтому почитать комментарии очень не вредно. В них, кстати, есть пример, который я взял за основу для этой статьи.

Теперь взгляните на сам скрипт

$login = 'ваш_логин';
$pass = 'ваш_пароль';

$pathToCurl = 'path/to/curl';
$authData = array();
//получаем SID
exec($pathToCurl.'curl https://www.google.com/accounts/ClientLogin -d Email='.$login.' -d Passwd='.$pass.' -d source=Google-cURL-Example -d service=reader -k', $authData);

//запрашиваем T token
$tToken = exec($pathToCurl.'curl -s -X GET http://www.google.com/reader/api/0/token --header "Cookie: '.$authData[0].'"');

$feedTags = array();
exec($pathToCurl.'curl -s -X GET http://www.google.com/reader/api/0/tag/list?output=json --header "Cookie: '.$authData[0].'; T='.$tToken.'"', $feedTags);

$jsonStr = ''; foreach ($feedTags as $str) { $jsonStr .= $str; } $fTags = json_decode($jsonStr); var_dump($fTags);

Обратите внимание, я сделал два примера (второй листинг — в конце статьи). В первом cURL запускается с помощью функции exec, во втором — используется расширение PHP для работы с cURL.

По-идее второй вариант должен был получиться проще, но оказалось, наоборот 🙂 К тому же, первый вариант проще переделать для использования с другими языками. В общем, выбирайте тот, который вам больше нравиться.

Теперь разберем, как это работает.

1) Мы отправляем запрос с логином и паролем. В ответ приходят данные, которые содержат так называемый SID идентификатор. Его мы должны использовать во всех последующих запросах.

2) Находим SID и отправляем запрос на получение T token. Это еще один идентификатор и его тоже нужно присоединять к последующим запросам вместе с SID.

3) Отправляем запрос на получение списка тегов (или других данных).

Теперь взгляните, как передаются SID и T token (строки 10 и 13). Мы используем ключ --header, после которого идут наши cookie (Cookie: ...). Т.е. мы их не сохраняем на жесткий диск, а сразу вставляем в запрос.
Формат такой
Cookie: par1=val1; par2=val2; ...

Кроме того, обратите внимание, что в первом запросе (строка 7) использован параметр -k. Он отключает проверку SSL сертификатов.

Список тегов я вывел просто с помощью var_dump.

Теперь посмотрите на этот же скрипт, написанный с использованием PHP библиотеки.

$login = 'ваш_логин';
$pass = 'ваш_пароль';

//адреса страниц, которые нам нужны
//$authUrl и $tokenUrl - для аутентификации
//$getTagsUrl - получение списка тегов
$authUrl = 'https://www.google.com/accounts/ClientLogin';
$tokenUrl = 'http://www.google.com/reader/api/0/token';
$getTagsUrl = 'http://www.google.com/reader/api/0/tag/list?output=json';

$agent = 'Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5';

//массив с данными для аутентификации
$loginData = array();
$loginData['service'] = 'reader';
$loginData['Email'] = $login;
$loginData['Passwd'] = $pass;
$loginData['source'] = $agent;
$loginData['continue'] = 'http://www.google.com/';

//настраиваем curl
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $authUrl);
curl_setopt($ch, CURLOPT_STDERR, $el);
curl_setopt($ch, CURLOPT_USERAGENT, $agent);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($loginData));
//настройка SSL
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0);

//получаем данные...
$data = curl_exec($ch);
//... и находим в них SID
$kv = explode("\n",$data);
$authData = array();
foreach ($kv as $str) {
        if (!empty($str)) {
                $data = explode("=", $str);
                $authData[$data[0]] = $data[1];
        }
}

//получаем T token
curl_setopt($ch, CURLOPT_COOKIE, 'SID='.$authData['SID']);
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_URL, $tokenUrl);
$tToken = curl_exec($ch);

//получаем список тегов в формате JSON
curl_setopt($ch, CURLOPT_URL, $getTagsUrl);
curl_setopt($ch, CURLOPT_COOKIE, 'SID='.$authData['SID'].'; T='.$tToken);
$tags = curl_exec($ch);

curl_close($ch);

var_dump(json_decode($tags));

В принципе, все очень похоже, только параметры запроса указываются с помощью функции curl_setopt.

Правда, тут нужно быть очень внимательным.
Первый запрос уходит методом POST, а следующие два — методом GET (строки 28 и 48). Если забудете изменить — получите ошибку.

Установка cookie выполняется с помощью
curl_setopt($ch, CURLOPT_COOKIE, ...);
в третьем параметре передается строка с данными (в формате параметр=значение, т.е. точно также как и в первом примере).

Как видите, не со всеми сайтами легко работать с помощью cURL 🙂 Кстати, в качестве упражнения, попробуйте firebug'ом проанализировать протокол Google Reader. Думаю, вы быстро убедитесь, что это не так просто сделать.

Если есть вопросы или замечания, пишите, обсудим!

Постовой

Занимаемся бухгалтерскими услугами, стоимость от 10000 р. в месяц

  • Вот это просто отличный пример для понимания cURL, работы с кукисами и гуглом. Продолжайте в том же духе. Сами додумали (через фаербаг) или где-то были доки по гуглу?

    • Анализ через firebug такой системы занимает очень много времени 🙂
      Ссылка на источник (неофициальный GoogleReaderAPI) есть в статье, но все-равно пришлось поковыряться с параметрами cURL (особенно для второго примера).
      Без
      curl_setopt($ch, CURLOPT_VERBOSE, TRUE);
      настроить практически не реально 🙂

  • Вот это просто отличный пример для понимания cURL, работы с кукисами и гуглом. Продолжайте в том же духе. Сами додумали (через фаербаг) или где-то были доки по гуглу?

    • Анализ через firebug такой системы занимает очень много времени 🙂
      Ссылка на источник (неофициальный GoogleReaderAPI) есть в статье, но все-равно пришлось поковыряться с параметрами cURL (особенно для второго примера).
      Без
      curl_setopt($ch, CURLOPT_VERBOSE, TRUE);
      настроить практически не реально 🙂

  • Подозреваю, что первый вариант не у всех хостеров будет работать да и как получить путь к Curl? Там есть какая-то функция для этого или нужно у хостера узнавать? Дело в том что в phpinfo у меня нет такой информации.

    Еще вопрос: есть ли альтернативы curl со встроенным Javascript движком? На php? Жутко интересно.

    Спасибо.

    • Правильно подозреваете 🙂 , для первого примера shared хостинг, скорее всего, не подойдет. Нужен или VPS или выделенный сервер, т.е. должна быть возможность устанавливать свой софт.

      Что касается альтернатив curl с поддержкой JS. О таких инструментах на php я не слышал, но, понимаете, лучшая альтернатива — сам браузер. Например, есть проект SeleniumIDE. Это плагин к Firefox, предназначенный для тестирования. Вы можете записать практически любую последовательность действий и он будет ее выполнять, и естественно при этом будет поддержка JS.

  • Подозреваю, что первый вариант не у всех хостеров будет работать да и как получить путь к Curl? Там есть какая-то функция для этого или нужно у хостера узнавать? Дело в том что в phpinfo у меня нет такой информации.

    Еще вопрос: есть ли альтернативы curl со встроенным Javascript движком? На php? Жутко интересно.

    Спасибо.

    • Правильно подозреваете 🙂 , для первого примера shared хостинг, скорее всего, не подойдет. Нужен или VPS или выделенный сервер, т.е. должна быть возможность устанавливать свой софт.

      Что касается альтернатив curl с поддержкой JS. О таких инструментах на php я не слышал, но, понимаете, лучшая альтернатива — сам браузер. Например, есть проект SeleniumIDE. Это плагин к Firefox, предназначенный для тестирования. Вы можете записать практически любую последовательность действий и он будет ее выполнять, и естественно при этом будет поддержка JS.

  • Ну, если я хочу написать серьезного бота который будет делать какие-то массовые операции из моего сервера, причем через списки прокси, то браузер как бы не совсем подходит.
    Да, про selenium слышал в принципе, кстати, это не только плагин к фаерфокс, там есть такой инструмент: Selenium Remote Control (RC)
    Который позволяет использовать Selenium даже через php и делать что-то типа
    $s->setBrowser(«*firefox»);
    $s->setBrowserUrl(«http://www.google.com/»);
    и т. д.

    • Все зависит от того, что именно будет делать бот. Например, если это бот для твиттера, то даже curl не нужен, т.к. у них есть API.

      P.S. Насчет Selenium вы правы, я сильно упростил ситуацию. Просто хотел сказать, что вы получаете возможности браузера в полном объеме.

  • Ну, если я хочу написать серьезного бота который будет делать какие-то массовые операции из моего сервера, причем через списки прокси, то браузер как бы не совсем подходит.
    Да, про selenium слышал в принципе, кстати, это не только плагин к фаерфокс, там есть такой инструмент: Selenium Remote Control (RC)
    Который позволяет использовать Selenium даже через php и делать что-то типа
    $s->setBrowser(«*firefox»);
    $s->setBrowserUrl(«http://www.google.com/»);
    и т. д.

    • Все зависит от того, что именно будет делать бот. Например, если это бот для твиттера, то даже curl не нужен, т.к. у них есть API.

      P.S. Насчет Selenium вы правы, я сильно упростил ситуацию. Просто хотел сказать, что вы получаете возможности браузера в полном объеме.

  • Очередной раз убеждаюсь в преимуществах использования cURL. Спасибо за очередной интересный пост!

  • Очередной раз убеждаюсь в преимуществах использования cURL. Спасибо за очередной интересный пост!

  • За cURL будущее! Весьма удобно и практично!

  • За cURL будущее! Весьма удобно и практично!

  • Многовато, однако, с cURL возни выходит…

    • Тут ничего не поделаешь. Чем больше настроек, тем больше возможностей и тем больше возни.

  • Многовато, однако, с cURL возни выходит…

    • Тут ничего не поделаешь. Чем больше настроек, тем больше возможностей и тем больше возни.

  • Кстати, я вот думал-думал и не придумал, для какой цели можно вытягивать что-то скриптами из GoogleReader? 🙂

    • Хороший вопрос 🙂 Как вариант — создание своего машапа.

    • Хотя я писал пост только для того, чтобы показать более-менее интересный пример работы с cURL.

  • Кстати, я вот думал-думал и не придумал, для какой цели можно вытягивать что-то скриптами из GoogleReader? 🙂

    • Хороший вопрос 🙂 Как вариант — создание своего машапа.

    • Хотя я писал пост только для того, чтобы показать более-менее интересный пример работы с cURL.

  • Отличный пост. Однозначно сайт в закладки — здесь только полезная информация.

  • Отличный пост. Однозначно сайт в закладки — здесь только полезная информация.

  • Привет, Владимир. Вы бы не могли привести пример, как можно сграбить страничку ридера, чтоб счетчик читателей на сайт повесить? Ссылка

    $link = 'http://google.com/reader/directory/search?q=http://'.$url;

    выдает ошибку 401, а с браузера вижу. Попробовал по ваше примеру залогиниться — никак не выходит, полуучаю пустой результат. Нашел вариант через js, но для меня там сильно замучено, попробовал еще вариант, как здесь — тоже не работает. Никак сам не могу разобраться, хотя курлы уже неделю курю… Подскажите, пожалуйста, если свободная минутка есть.

    • Какой-то сильно сложный способ определения количества читателей 🙂 По-моему, проще использовать счетчик feedburner'а.

      Обычно ошибки похожие на ваши возникают если не сохранить cookie (или не сохранить в них все данные). Ещё одна причина — не подключённая поддержка SSL. В браузере и то, и другое работает по-умолчанию, скорее всего, поэтому и страница нормально видна. Тем более, что 401 ошибка — Unauthorized (не пройдена авторизация).
      В общем, нужно проверить все cookie, которые сохраняет браузер и убедиться, что curl их тоже сохраняет.

  • Привет, Владимир. Вы бы не могли привести пример, как можно сграбить страничку ридера, чтоб счетчик читателей на сайт повесить? Ссылка

    $link = 'http://google.com/reader/directory/search?q=http://'.$url;

    выдает ошибку 401, а с браузера вижу. Попробовал по ваше примеру залогиниться — никак не выходит, полуучаю пустой результат. Нашел вариант через js, но для меня там сильно замучено, попробовал еще вариант, как здесь — тоже не работает. Никак сам не могу разобраться, хотя курлы уже неделю курю… Подскажите, пожалуйста, если свободная минутка есть.

    • Какой-то сильно сложный способ определения количества читателей 🙂 По-моему, проще использовать счетчик feedburner'а.

      Обычно ошибки похожие на ваши возникают если не сохранить cookie (или не сохранить в них все данные). Ещё одна причина — не подключённая поддержка SSL. В браузере и то, и другое работает по-умолчанию, скорее всего, поэтому и страница нормально видна. Тем более, что 401 ошибка — Unauthorized (не пройдена авторизация).
      В общем, нужно проверить все cookie, которые сохраняет браузер и убедиться, что curl их тоже сохраняет.

  • Naquad

    скрипт эпикфейлнулся на получении токена с http error 403 forbidden.
    нужно тулить хэдер
    Authorization: GoogleLogin auth=<параметр Auth из ответа ClientLogin>
    выглядит в коде сие так:
    curl_setopt($h, CURLOPT_HTTPHEADER, array('Authorization: GoogleLogin auth=' . $ad['Auth']));
    это нужно *везде*, т.е. даже потом, когда токен уже получен, все
    запросы должны содержать этот хэдер

  • Спасибо за сообщение!
    Возможно, разработчики google внесли изменения.

  • Владислав

    Можно ли постер в Blogger с авторизацией в почте таким образом через curl сделать- ключевые моменты какие хотя бы?

    • У Blogger есть API, его использовать будет удобнее, чем curl.