Донецкий техникум промышленной автоматики

Друзі друзів Вконтакте на Ruby

  1. трохи логіки
  2. Реалізація
  3. Багато букoв?
  4. авторизація
  5. Розбір друзів
  6. аналіз
  7. висновок

September 23 2009 data scraping Mechanize Ruby Вконтакте

Захотілося мені написати щось безпосередньо корисне.

трохи логіки

Якщо кілька твоїх знайомих знайомі з Васею Пупкіним, то з великою ймовірністю ти теж з ним знайомий. Логічно?

Реалізація

На «Моєму колі», наприклад є таке поняття, як «друге коло» - друзі твоїх друзів. На Вконтакте "друге коло" просто так не подивишся. Тобто можна, звичайно, лазити по друзях і виглядати знайомі обличчя (якщо Особа не поставило ідіотську аватарку) і імена (якщо Особа не намагається анонімізувати). У мене на це немає часу.

Завдання: написати скрипт, який збирає «друге коло» автоматично і сортує по числу спільних знайомих.

Багато букoв?

можеш просто скачати працює скрипт з Github . У нього тільки потрібно дописати свої власні логін / пароль. Крім того, знадобляться геми: mechanize, json, haml.

авторизація

Над завданням автоматизованого логіна в контакт б'ються багато. тисячі їх . На Ruby це завдання вирішується буквально в п'ять рядків. Зустрічайте Mechanize :

# Створюємо наш віртуальний браузер agent = WWW :: Mechanize .new # отримуємо форму логіна login_form = agent. get ( 'http://vkontakte.ru') .form ( 'login') # параметри авторизації ... login_form. email = '[email protected]' login_form. pass = 'gfhjkm' # авторізуемся agent. submit (agent. submit (login_form, login_form. buttons .first) .forms .first)

Mechanize - це бібліотека, яка реалізує доступ до сайтів зі збереженням стану - в першу чергу, куків. Як браузер. Ще вона дозволяє обробляти одержувані сторінки, наприклад, діставати з них форми і посилання, або довільні елементи за допомогою CSS-селекторів і XPath. Рекомендую.

Останній рядок скрипта така ж дивна, як і те, що після логіна тебе перекидає на якусь сторінку, а потім вже на твій профіль. Там насправді виробляється відправка ще однієї форми, так.

Розбір друзів

Не повіриш, але Контакт віддає список друзів в json в тілі сторінки friends.php. Ура! Не треба буде довільні HTML.

# Дістаємо сторінку з друзями ... friends_page = agent. get ( 'http://vkontakte.ru/friends.php') # ... і викусивать з неї рядок з json-об'єктом. friends_json_string = friends_page. body .match (/ ^ \ s + var friendsData = (\ {. + \}); $ /) [1] # отримуємо хеш friends_json = JSON. parse friends_json_string # OH SHI ...

Не зовсім ура: json цей чомусь неправильний і засобами Ruby НЕ Парс. Перевіряємо рядок валідатором JSON Lint . Виявляємо (поки) три проблеми: 1) одинарні лапки; 2) числові ключі без лапок; 3) некоректні символи. Все це виправляється:

friends_json_string = friends_json_string. gsub ( " '", "\" "). gsub (/ (\ d +): /," \ "$ 1 \": ") .gsub (/ [\ x00 - \ x19] /," ") friends_json = JSON. parse friends_json_string # profit!

аналіз

Далі все просто - збираємо друге коло, для кожного товариша звідти вважаємо кількість спільних знайомих, сортуємо і виводимо.

# {Id => name, ...} names = {} # [id, id, ...] my_friends = [] # {id => [id, id, id], ...} common_friends = {} # get_friends - це така функція, яка повертає масив типу [{: id => id,: name => name}, ...] get_friends. each do | friend | # Збираємо своїх друзів my_friends << friend [: id] # запам'ятовуємо імена для зручності names [friend [: id]] = friend [: name] end my_friends. each do | friend_id | get_friends (friend_id). each do | his_friend | # Додаємо одного в список спільних знайомих common_friends [his_friend [: id]] || = [] Common_friends [his_friend [: id]] << friend_id # знову-таки запам'ятовуємо ім'я names [his_friend [: id]] = his_friend [: name] end end # відкидаємо своїх друзів, а також людей, у яких тільки один загальний знайомий common_friends. reject! {| id, friends | my_friends. include? (id) || (Friends. Length <2)} # сортуємо залишилися за кількістю спільних знайомих common_friends. sort! {| a, b | b [1]. length <=> a [1]. length}

Усе! Залишається вивести красиво відформатований список people. Звичайно, використовуючи haml.

!!! % Html% body% h1 = "Total people in 2nd circle: # {people.length}"% ul -people.each do | id, friends | % Li% div% a {: href => "http://vkontakte.ru/id#{id}"} = names [id] = "(# {friends.length})"% div = friends.map { | id | names [id]}. join ','

висновок

Є думка зробити більш зручну бібліотеку для доступу до даних Вконтакте, тільки я сумніваюся в доцільності такого бібліотеки. Хіба що проводити всякий статистичний аналіз, або автоматично розсилати повідомлення / запрошення /.

Якщо кому-небудь таке цікаво, пишіть в коменти.

Сподобався пост Сподобався пост? почастуєте кави

Логічно?
Багато букoв?
Include?
Сподобався пост?