Rss с drive2
Мне очень нравится сайт drive2.ru. Отличное сообщество, красивые машины и интересные обсуждения. Но разработчики сайта не позаботились о том, чтобы отдавать ленту событий в RSS. Пришлось снова писать костыли. На этот раз костыль я решил написать не на привычном и горячо любимом питоне, а на руби.
Распарсить ленту не представляет труда, а вот авторизоваться на сайте с ходу не получится. На форму входа навешен javascript и без него "войти" невозможно. Мне известны два способа как решить эту проблему. Во-первых, использовать какую-нибудь библиотеку, которая работает с настоящим браузером. Соответственно и javascript и всё остальное там прекрасно работает. Для руби есть, например, Watir. Во-вторых, можно своему скрипту подсунуть рабочие куки и таким образом вообще пропустить стадию авторизации. Собственно этот второй путь я и выбрал.
Моим повседневным браузером является firefox, который хранит куки в базе данных SQLite, которая лежит в ~/.mozilla/firefox/%profile%/cookies.sqlite (путь для линукса, в windows очень похожий). Откроем этот файл и посмотрим что там внутри:
$ sqlite3 /tmp/cookies.sqlite
SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .tables
moz_cookies
sqlite> .headers on
sqlite> select * from moz_cookies limit 3;
id|name|value|host|path|expiry|lastAccessed|isSecure|isHttpOnly
1254769091658566|PREF|моя кука|.google.com|/|1326648773|1264938324355994|0|0
1254769091658706|NID|моя кука|.google.com|/|1280320725|1264938264007374|0|1
1254769091832306|PREF|моя кука|.google.ru|/|1317842867|1264938309932153|0|0
Отлично. Значит мы без труда может вытащить рабочие куки из нашего браузера. Но браузер работает на десктопе, а скрипт должен работать на сервере, чтобы постоянно мониторить обновления ленты. Следовательно нужно каким-то образом держать на сервере актуальную базу. Я для этого решил использовать Dropbox, т.к он и так постоянно запущен как на сервере, так и на десктопе. Кидаю ссылку в директорию дропбокса и готово.
Ну а теперь собственно сам скрипт.
# coding: utf-8
require 'sqlite3'
require 'net/http'
require 'nokogiri'
require 'rss/maker'
class Parser
TITLE = "Drive2.ru Feed"
LINK = "http://www.drive2.ru/my/feed"
DESCRIPTION = "Rss from my feed"
def initialize(sqlfile = nil, txtfile = nil)
if sqlfile
@doc = Nokogiri::HTML(get_page(sqlfile))
elsif txtfile
@doc = Nokogiri::HTML(get_from_file(txtfile))
else
exit()
end
end
def get_page(sqlfile)
cookies = ''
`cp #{sqlfile} /tmp/cookies.sqlite`
db = SQLite3::Database.new('/tmp/cookies.sqlite')
db.execute( "select name, value from moz_cookies where host = '.www.drive2.ru'" ) do |row|
cookies += row[0] + '=' + row[1] + ';'
end
con = Net::HTTP.new('www.drive2.ru', 80)
path = '/my/feed/'
headers = { 'Cookie' => cookies,
'Refer' => 'http://www.drive2.ru',
'User-Agent' => 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20100105 Shiretoko/3.5.7'}
res = con.get(path, headers)
res.body
end
def get_from_file(txtfile)
f = File.new(txtfile)
f.read()
end
def login?
title = @doc.css('title').first.content.strip
return true if title == 'Лента'
return false
end
def parse
result = Array.new
@doc.css('.journalentries').each do |entry|
time = entry.css('.eventtime').first.content
time = Time.parse(modify_time(time))
title = entry.css('h3').first.content
content = entry.css('div:regex("j\d+")', Class.new {
def regex node, regex
node.find_all { |node| node['id'] =~ /#{regex}/ }
end
}.new).first.inner_html
link = entry.css('.commentslink > a').first['href']
result << { :title => title,
:datetime => time,
:content => content,
:link => 'http://www.drive2.ru' + link}
end
return result
end
def create_rss(entries)
content = RSS::Maker.make('2.0') do |m|
m.channel.title = TITLE
m.channel.link = LINK
m.channel.description = DESCRIPTION
m.items.do_sort = true # sort items by date
entries.each do |entry|
i = m.items.new_item
i.title = entry[:title]
i.link = entry[:link]
i.date = entry[:datetime]
i.description = entry[:content]
end
end
return content
end
private
def modify_time(string)
dict = { 'января в' => 'Jan', 'февраля в' => 'Feb',
'марта в' => 'Mar', 'апреля в' => 'Apr',
'мая в' => 'May', 'июня в' => 'Jun',
'июля в' => 'Jul', 'августа в' => 'Aug',
'сентября в' => 'Sep', 'октября в' => 'Oct',
'ноября в' => 'Nov', 'декабря в' => 'Dec',
'вчера в' => (Time.now - 60*60*24).strftime("%d %b")}
dict.each do |key, value|
string.sub!(key, value)
end
return string
end
end
if __FILE__ == $0
parser = Parser.new('/home/smacker/Dropbox/cookies.sqlite')
if parser.login?
rss = parser.create_rss(parser.parse)
f = File.open('/var/www/media/drive2.rss', 'w')
f.write(rss)
f.close()
end
end
Если код не очень красив, не сердчайте, я только начал изучать ruby. В методе get_page я копирую базу в /tmp, потому что пока firefox запущен, он блокирует базу и не даёт из неё ничего читать. Готовый rss файл просто кладётся в директорию доступную по http, а эту ссылку я добавляю в свой Google Reader. Ну а скрипт соответственно прописан в кроне и выполняется раз в 2 часа. Надеюсь, он пригодится кому-нибудь ещё.
Комментарии:
[HTML_REMOVED]Урок в Вовочкином классе. Детишки рассказывают. Петя: - Мой папа ГАИшник, денег у нас много, живем в достатке. Маша: - Моя мама проститутка, денег у нас много, живем в достатке. Вовочка: - Мой папа дальнобойщик. Если бы не ГАИшники и проститутки, то денег у нас было бы много и жили бы мы в достатке. [HTML_REMOVED] Общество Мегаполис Pi7.ru порадовала новым выходом очередного сборника нюансов. Меня удивила например это "[HTML_REMOVED]Бесплодие разрушает всю мою жизнь! [HTML_REMOVED]" - Канечно вы можете найти и для себя бездну интерестного Ну а однако лучшее снадобье от скуки это анекдотец. [HTML_REMOVED][HTML_REMOVED]http://www.my.pi7.ru/images/users/photos/medium/a60f8906f1ca292298f2a30ce89a2331.jpg[HTML_REMOVED][HTML_REMOVED]
> цитата *курсив*
> цитата **жирный**
* список 1. список
* список 2. список
* список 3. список
отступ в 4 пробела:
def some_code():
return "code"
print some_code()
[ссылка](http://example.com/)