четвер, 12 березня 2009 р.

Ruby + User API Vkontakte. Частина 3

28 жовтня 2008 Павло Дуров заявив про відкриття нового проекту: User API.
Сервіс призначений для швидкої побудови соціальної мережі або будь-яких інших клієнтів (цього на сторінці не заявлено).
Нові проекти будуть використовувати дані мережі ВКонтакте (користувачі, фото, т.п.).
Докладна інформація і документація по User API ВКонтакте доступна на англійською і російською мовами.
API побудований на обміні даними між клієнтом і сервером у вигляді HTTP-запитів, і відповіді від сервера клієнту у вигляді JSON-масиву в кодуванні UTF-8. Підтримується пакування GZIP. Передача даних клієнту, як правило, передбачає авторизацію клієнта в системі за допомогою передачі серверу ідентифікатора сесії('SiD') при будь-якому запиті даних.

Від сухої теорії до практики.

Напишемо простий скрипт:

  • Авторизація через надсилання email-адреси та пароля користувача;

  • Отримання інформації профілю;

  • Отримання списку друзів користувача, які в даний момент онлайн на сайті.


Будемо використовувати вже знайомі з мої попередніх постів бібліотеки WWW::Mechanize і JSON.
Створимо клас VkontakteAPI і методи login, get_user_page, get_friends_online_list.

Невеликий нюанс. Після успішної авторизації, на запит "http://userapi.com/data?act=profile&id=#{id}&sid=#{sid}", сервер повертає JSON на кшталт
[...]
{0: "xxxxxxxx_", 1: xxxxxxxx, 2: 1, 3: "First Last", 4: null, 5: "", "ts": 346000002}
[...]

Згідно специфікіції: строка - це набір символів Unicode, взятих у подвійні лапки А тут - без повдійних лапок. Парсер Ruby JSON видає помилку. Використаємо хак для виправлення цього у функції hack_json.

# -*- encoding: utf-8 -*-
#
# For more documentation see http://userapi.com

require 'json'
require 'mechanize'

class VkontakteAPI
def initialize
@sid = nil
@id = nil
@agent = WWW::Mechanize.new{|agent|
agent.user_agent_alias = 'Linux Konqueror'
}
end

# Authorisation by submitting email and password (Login)
#
def login(email, pass)
url = "http://login.userapi.com/auth?login=force&site=2&email=#{email}&pass=#{pass}"
login_page = @agent.get(url)
if !@agent.cookies.nil?
@id = /remixmid=(\d+)/.match(@agent.cookies[0].to_s)[1]
@sid = /.*;sid=(\w*)/.match(login_page.uri.to_s)[1]
return true
else
return false
end
end

# Getting user's profile information
#
def get_user_page(id = @id)
url = "http://userapi.com/data?act=profile&id=#{id}&sid=#{@sid}"
user_info_page = @agent.get(url)
JSON.parse(hack_json(user_info_page.body))
end

# List of online friends of a user
#
def get_friends_online_list(id = @id, from=0, to=5000)
url = "http://userapi.com/data?act=friends_online&from=#{from}&to=#{to}&id=#{id}&sid=#{@sid}"
friends_list_page = @agent.get(url)
JSON.parse(friends_list_page.body)
end

# little User API JSON hack :)
# Name property must be a String wrapped in double quotes
#
def hack_json(json_s)
json_s.gsub(/(\d+):/, '"\1":')
end

private :hack_json

end

if __FILE__ == $0
email = ARGV[0]
pass = ARGV[1]

vk = VkontakteAPI.new
if vk.login(email, pass)
puts vk.get_user_page
puts "Online friends:"
vk.get_friends_online_list.each do|friend|
puts "#{friend[0]}: #{friend[1]}"
end
else
"Error"
end
end

1 коментар:

Анонім сказав...

Привет, круто все описываешь, очень интересно!
Но скажи, ты пробовал ковырять этот юзерапи еще?
Я столкнулся с проблемой, что не возвращаются редиректы, которые ожидаешь.
Т.е. с форс логином, допустим, все правильно, а с логаутом или с логином через куки никакого ответа.
Помоги, пожалуйста. В чем тут дело?