Показ дописів із міткою nokogiri. Показати всі дописи
Показ дописів із міткою nokogiri. Показати всі дописи

вівторок, 15 березня 2011 р.

Nokogiri і XPath для розбору HTML таблиць

Вже третій місяць користуюся "Домашнім Інтернетом" від "Київстар". Система "Мій Київстар" дає змогу самостійно керувати своїми витратами в режимі онлайн. І звісно ж це вже потрібно автоматизувати. Для цього я буду використовувати наступні інструменти: Ruby, Mechanize, Nokogiri.

Аторизація на сайті Мій Київстар:

# -*- encoding: utf-8 -*-

require 'mechanize'
require 'nokogiri'

login    = '0010390***'
password = '***'

agent = Mechanize.new
agent.follow_meta_refresh = true

page = agent.get('https://my.kyivstar.ua/tbmb/login/perform.do')

login_form = page.form_with(:name => 'loginForm')
login_form.user     = login
login_form.password = password
show_page = agent.submit(login_form)

if show_page.uri.to_s == "https://my.kyivstar.ua/tbmb/disclaimer/show.do"
  puts "Login successful"
else
  puts "Login failure"
  exit
end

show_page_html = show_page.body.encode('utf-8', 'cp1251')

Розбір HTML таблиці використовуючи XPath:

doc = Nokogiri::HTML(show_page_html)
details = doc.search("//td[@id='mainContentBlock']/table/tr").collect do |row|
  title = row.at('td[1]').text.strip rescue ''
  data  = row.at('td[2]').text.strip.gsub("\n", " ") rescue ''
  {
    :title => title,
    :data  => data
  }
end

Вивід розпарсеної таблиці і поточного балансу:

pp details

balance = details.find {|e| e[:title] == "Поточний баланс:"}
puts "#{balance[:title]} #{balance[:data]}"

[{:title=>"Прізвище, ім'я, по-батькові:", :data=>"Іван Іванович"},
 {:title=>"Номер договору:", :data=>"0010390***"},
 {:title=>"Адреса підключення:", :data=>", Україна, Тернопіль"},
 {:title=>"Номер мобільного телефону:", :data=>"+38063*******"},
 {:title=>"Адреса електронної пошти:", :data=>"ivan.ivanovichlinux@gmail.com"},
 {:title=>nil, :data=>"Активуйте Вашу електронну адресу"},
 {:title=>nil, :data=>"Надіслати код активації"},
 {:title=>nil, :data=>nil},
 {:title=>"Особовий рахунок:", :data=>"0010390***"},
 {:title=>"Статус особового рахунка:", :data=>"Діючий"},
 {:title=>"Поточний баланс:", :data=>"55.09 грн."},
 {:title=>"Поріг відключення:", :data=>"0.0 грн."},
 {:title=>"Тарифний пакет:", :data=>"Турбо"},
 {:title=>"Статус послуги:", :data=>"Підключена"},
 {:title=>"Дата підключення:", :data=>"18.12.2010"}]
Поточний баланс: 55.09 грн.

четвер, 11 березня 2010 р.

Yahoo! Weather і Ruby

Yahoo! Weather RSS-канал дозволяє отримувати останню інформацію про погоду для вашої місцевості. Ви можете зберігати цю інформаію у вашому улюбленому RSS-агрегаторі, або включити ці дані до вашого сайту або додатку. RSS динамічно генерується на основі WOEID.

Короткий опис формату запиту URL та RSS відповіді.
Запит RSS слідує наступному простому синтакстису HTTP GET: починається з простого базого URL за яким слідують додаткові параметри і значення після знаку питання (?). Кілька параметрів розділяються амперсандом (&).
Базовий URL для каналу погоди є
http://weather.yahooapis.com/forecastrss
Два можливі параметри:
  • w - для WOID (обов'язковий параметр, що вказує на місце розташування для прогнозу погоди). Наприклад w=935810
  • u - для одиниць вимірювання(c: за Цельсієм, f: за Фаренгейтом). Наприклад u=c. Вибір 'c' покаже всі дані в метричних одиницях(наприклад швидкість вітру буде відображатися в кілометрах за годину).
http://weather.yahooapis.com/forecastrss?w=location

Наприклад, щоб отримати погоду для Тернополя, використовується код 935810.
http://weather.yahooapis.com/forecastrss?w=935810

Щоб знайти значення WOID для вашого міста, здійсність пошук на головній сторінці.
Наприклад для Тернополя, URL сайту буде мати наступний вигляд:
http://weather.yahoo.com/ukraine/ternopil-oblast/tarnopol'-935810/
Де WOID це 935810.

RSS відповідь я не буду докладно описувати.
Знизу приведений приклад коду для роботи з Yahoo! Weather з Ruby.

вівторок, 29 вересня 2009 р.

Proxy list fetcher using Ruby & Nokogiri

А чому б нам не зробити накручувалку, яка голосує за що-небудь ? "Чорні"(брудні) технології залишимо нашим політиком. А самі займемося чимось корисним.

Цей скрипт складає список проксі-серверів з сайту proxy4free.com, і записує його до файлу proxy_list.txt.

# -*- encoding: utf-8 -*-

require 'nokogiri'
require 'open-uri'

file = File.new('proxy_list.txt', 'w')
url = 'http://www.proxy4free.com/page1.html'
# Get a Nokogiri::HTML:Document for the page
doc = Nokogiri::HTML(open(url))

# Search for nodes by css
doc.css('table tr.text').each do |tr|
ip = (tr/"td:nth(1)").first.inner_html
if ip.match(/^(\d{1,3}\.){3}\d{1,3}$/)
port = (tr/"td:nth(2)").first.inner_html
file.puts "#{ip}:#{port}"
end
end
file.close



Керівництва до дії:

  1. Do something

  2. Do something else

  3. Do something once more

  4. <Do something so much you need>

  5. ?????

  6. PROFIT!


пʼятниця, 10 липня 2009 р.

Mechanize + Nokogiri + вКонтакте. Частина 5


Ніхто не помітив зовнішніх змін. Положення тіла пацієнта вКонтакте на операційному столі залишалось незмінним. Але мушу повідомити неприємну новину: ідентифіковано мутації. Тому всі попередні дослідження [1][2][3][4] вважаються недійсними. Нічого... не треба падати духом.
Їжачки плакали і кололись, але продовжували кохатися з кактусами! ©

Nokogiri - це парсер HTML, XML, SAX. Серед його численних можливостей можна виділити можливість використання XPath(XML Path Language) і CSS3 селекторів для пошуку.
Крім того Nokogiri має сумісний з Hpricot синтаксис XPath та CSS.
На даний час Nokogiri найшвидший парсер XML для Ruby.
Mechanize для синтаксичного розбору html використовує саме Nokogiri.

Приклад використання:

Підключення необхідних бібліотек
require 'nokogiri'
require 'open-uri'

Завантаження HTML сторінки, використовуючи open-uri, який йде з Ruby
doc = Nokogiri::HTML(open('http://www.google.com/search?q=ruby-ua'))

Пошук вузлів за допомогою CSS3 селекторів
doc.css('h3.r a.l').each{|link| puts link.content}

Пошук вузлів за допомогою XPath
doc.xpath('//h3/a[@class="l"]').each {|link| puts link.content}


Автор рекомендує використовувати XPath селектори для вищої швидкодії - пошук CSS швидкий ніж у Hpricot, але не такий швидкий.
Nokogiri::XML::Node#xpath(*paths) - функція пошук вузлів(nodes) для XPath шляхів(paths). Шлях повинен бути одним або декількома XPath запитами(queries).
Цікавоє можливістю є задання власних функцій XPath із використанням регекспів(regexp). Для цього потрібно створити класс і застосувати функцію # яку хочете визначити. Наприклад:

node.xpath('.//tr[mess(., "mess\d+")]', Class.new {
def mess node_set, regex
node_set.find_all { |node| node['id'] =~ /#{regex}/ }
end
}.new)


Така функція знайде всі вузли виду:
<tr id="mess127">[...]</tr>
<tr id="mess128">[...]</tr>
<tr id="mess129">[...]</tr>


вКонтакте!?
У зв'язку зі змінами на сайті vkontakte.ru мої попередні дописи про вконтакте втратили свою актуальність. Не знаю скільки часу буде працездатним цей код. Але суть в іншому: показати принципи роботи з Mechanize і Nokogiri на реальному прикладі.
Що ж робить нищеприведений код?

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

  • Отримання останніх приватних повідомлень; (get_messages)


# -*- encoding: utf-8 -*-
require 'mechanize' # recommended 0.9.2

@a = WWW::Mechanize.new{|agent|
agent.user_agent_alias = 'Linux Konqueror'
agent.follow_meta_refresh = true
}

# Authorisation by submitting email and password (Login)
#
def login_force(uid, email, pass)
login_page = @a.get('http://vkontakte.ru/login.php')
login_form = login_page.form_with(:name => "login")
login_form.email = email
login_form.pass = pass
user_page = login_form.submit
return /http:\/\/vkontakte\.ru\/id(\d+)/ === user_page.uri.to_s ? ($1 == uid ? true : false) : false
end

# Getting private messages list for current user
#
# Structure of each entry of resulting array
# [0] - message from
# [1] - message date
# [2] - message title
# [3] - message_body
#
def get_messages
url = 'http://vkontakte.ru/mail.php'
messages_page = @a.get(url)
node = Nokogiri::HTML(messages_page.body)
message = node.xpath('.//tr[mess(., "mess\d+")]', Class.new {
def mess node_set, regex
node_set.find_all { |node| node['id'] =~ /#{regex}/ }
end
}.new)
message_from = message.xpath('//td[@class="messageFrom"]/div[@class="name"]/a').map {|link| /\/id(\d+)/.match(link['href'])[1]}
message_date = message.xpath('//td[@class="messageFrom"]/div[@class="date"]').map {|link| link.content}
message_title = message.xpath('//a[@class="new messageSubject"]/span').map {|link| link.content}
message_body = message.xpath('//a[@class="new messageBody"]').map {|link| link.content}
messages = Array.new
messages = [message_from, message_date, message_title, message_body].transpose
return messages
end

id = "12345678"
email = "username@example.com"
pass = "secret"

if login_force(id, email, pass)
puts "Successfully Authentication"
get_messages.each {|message|
puts "[#{message[1]}]: #{message[0]}"
puts message[2]
puts message[3]
puts "==="
}
else
puts "Authentication Error"
end