API Медузы: пишем полнотекстовый RSS

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

Meduza.io — не исключение: текст приходит урезанный, приходится каждый раз переходить из ридера в браузер для прочтения одной новости. Особенно это выглядело ужасным, когда на Медузе не было нормальной мобильной версии, веб-версия на телефоне сильно тормозила.

Существуют различные сервисы для парсинга html в rss, но когда я наткнулся на консольный клиент для Медузы, у меня сразу же возник вопрос, а какое API там используется и можно ли его заюзать для написания своего приложения?

image

API


Далеко ходить не пришлось, код консольного приложения выложен на гитхабе и представляет собой js-ку, которая обращается к искомому API.

Получение списка новостей


https://meduza.io/api/v3/search?chrono=news&page=0&per_page=10&locale=ru
chrono — принимает значения news, cards, articles, shapito или polygon, в зависимости от рубрики, которую хотим получить;
page — номер страницы;
per_page — количество записей на странице;
locale — локаль ru или en;

Получение отдельной новости


https://meduza.io/api/v3/shapito/2015/06/02/vyshel-neofitsialnyy-terminalnyy-klient-meduzy
Тут просто подставляется url, полученный из прошлого пункта.

Идея


Взять исходный фид rss по адресу https://meduza.io/rss/all, но вместо урезанных новостей подставлять текст новости, полученный через API.

Пример реализации (прототип)


Я взял руби и написал немного кода для парсинга исходного rss фида:

Nokogiri::XML(open('https://meduza.io/rss/all'))

А также код, который парсит json отдельно взятой новости:

JSON::parse(open('https://meduza.io/api/v3/' + post_url).read)['root']['content']['body']


Подставляем одно в другое и получаем нечто следующее:

require 'open-uri'
require 'json'
require 'nokogiri'

$meduza = 'https://meduza.io'
$meduza_rss = $meduza + '/rss/%s'
$meduza_api = $meduza + '/api/v3/%s'

class Meduza
  def Meduza.generate(feed = 'all')
    doc = Nokogiri::XML(open($meduza_rss % feed))
    doc.xpath('/rss/channel/item').each do |item|
      post_id = item.xpath('link').inner_text.gsub(/^#{$meduza}\//, '')
      json = JSON::parse(open($meduza_api % post_id).read)
      item.search('description').each do |description|
        description.content = json['root']['content']['body'].gsub('src="/image/', 'src="//meduza.io/image/')
      end
    end
    doc.to_xml
  end
end

puts Meduza.generate

Попутно меняем относительные url картинок на абсолютные с помощью метода gsub.

Использование


Написано минималистичное приложение на sinatra, которое можно развернуть, например, на хостинге heroku и пользоваться на здоровье (и к тому же совершенно бесплатно). Избавиться от «засыпания» приложений на heroku поможет сервис вроде этого.

Исходный код приложения выложен на github, спасибо за внимание!

P. S. Ссылка на работающее приложение meduza.herokuapp.com/rss (до тех пор, пока бесплатный аккаунт heroku сможет выдержать нагрузку).
  • +12
  • 17.1k
  • 6
Share post

Comments 6

    +3
    Кажется хабр как коммьюнити и срачи в комментах умерло уже давно, но если что — техдир медузы в чяте.
      0
      проще просто воспользоваться readability. простое и универсальное решение.
        0
        Они дают полнотекстовую RSS?
          0
          они вычленяют полный текст со страницы без API сайта. в отличие от API, это решение будет работать не только с медузой.
        0
        Добрый день. Я пользовался Вашим расширением, но с 21/12 новости не приходят. Можете проверить работоспособность? Спасибо
          0
          похоже, снова сломалось (
          периодичность=месяц?

        Only users with full accounts can post comments. Log in, please.