Concludiamo questo capitolo illustrando l'utilizzo di Mechanize, una potente libreria per l'automatizzazione delle operazioni sul Web. Mechanize gestisce automaticamente i cookie, i form, i redirect, i link e tutto quello che è possibile trovare in una pagina web.
Vediamo subito un esempio che ci permette di illustrare come è possibile operare su una pagina web:
require 'rubygems' require 'mechanize' agent = WWW::Mechanize.new page = agent.get('http://ruby-it.org/')
La pagina non ci viene fornita sotto forma di HTML ma come un oggetto di tipo WWW::Mechanize::Page
che è la forma sotto la quale Mechanize incapsula il codice HTML. Ogni elemento della pagina è rappresentato come un oggetto o un attributo della classe WWW::Mechanize
.
Per ottenere il codice HTML va utilizzato il metodo get_file
al posto di get
.
Particolare enfasi è riservata ai form e ai link rappresentati rispettivamente da oggetti di tipo WWW::Mechanize::Form
e WWW::Mechanize::Page::Link
. Come esempio per illustrare la gestione dei form vediamo come effettuare il login ad un blog su WordPress utilizzando Mechanize.
Innanzitutto creiamo un oggetto WWW::Mechanize
che ci permetta di interagire con la pagina web:
agent = WWW::Mechanize.new wp = agent.get('https://wordpress.com/wp-login.php')
Per poter fare il login ci occorre conoscere i nomi dei campi del form. Li possiamo dal codice sorgente della pagina o direttamente da Mechanize:
wp_form = wp.forms.first puts "#{wp_form.name} (#{wp_form.method})" wp_form.fields.each do |f| puts " " + f.name + ": " + f.value if f.value end
Nel nostro esempio il form è uno ma in casi più complessi è possibile iterare sui vari form attraverso il metodo forms
della pagina:
wp.forms.each do |form| puts form.name end
Tornando all'esempio, wp_form
è un oggetto WWW::Mechanize::Form
costituito a sua volta dai vari elementi del form ovvero i campi (Field
), i bottoni (Button
, RadioButton
), liste (SelectList
), etc. Ogni campo f
del form è invece di tipo WWW::Mechanize::Form::Field
con gli attributi name
e value
. Nel nostro caso l'output sarà simile a questo:
loginform (POST) log: pwd: redirect_to: wp-admin/ testcookie: 1
Per chiarezza ipotizziamo di conoscere sia il nome del form sia quello dei campi. Quindi per fare il login e ottenere la pagina di amministrazione del nostro blog basta solo compilare il form e inviare i dati attraverso il metodo submit che simula la pressione del tasto indicato come secondo argomento:
wp_form = wp.form('loginform') wp_form.log = 'username' wp_form.pwd = 'password' res = agent.submit(wp_form, wp_form.buttons.first)
Ovviamente il risultato sarà un oggetto di tipo WWW::Mechanize::Page
. Nel nostro caso il tasto da premere è wp_form.buttons.first
, ovvero:
>> pp wp_form.buttons.first #<WWW::Mechanize::Form::Button:0xb76a5880 @name="wp-submit", @value="Log In">
In caso di form più complessi possiamo iterare sui bottoni attraverso l'attributo buttons
come abbiamo fatto per i campi del form
. La gestione degli altri elementi del form è altrettanto efficace. Ad esempio nel nostro form c'è il classico checkbox "Remember me" che può essere selezionato semplicemente:
cb = wp_form.checkboxes.first
cb
è di tipo WWW::Mechanize::Form::CheckBox
, per selezionarlo va utilizzato il metodo check
. Il seguente stralcio di sessione Irb illustra gli attributi e il metodo check dei CheckBox:
>> pp cb #<WWW::Mechanize::Form::CheckBox:0xb76a6078 @checked=false, @name="rememberme", @value="forever"> => nil >> cb.check => true >> pp cb #<WWW::Mechanize::Form::CheckBox:0xb76a6078 @checked=true, @name="rememberme", @value="forever"> => nil
Come già detto Mechanize gestisce automaticamente i cookie, è possibile vedere i cookie salvati attraverso il metodo cookies
.
agent.cookies.each do |c| puts c.to_s end
Ogni cookie è un oggetto di classe WWW::Mechanize::Cookie
che oltre al nome e al valore (mostrati da to_s
) ha altri utili attributi come domain
, expires
, discarded
, max_age
, secure
, etc.
Vediamo infine come Mechanize permette di gestire i link. Iniziamo come al solito creando un agente e recuperando la pagina desiderata con get:
require 'rubygems' require 'mechanize' agent = WWW::Mechanize.new rubini = agent.get('http://rubini.us')
Per ottenere semplicemente l'elenco dei link presenti nella pagina occorre utilizzare il metodo links che ci restituisce una lista (WWW::Mechanize::List
) di oggetti WWW::Mechanize::Page::Link
:
puts "Links on #{rubini.title}" rubini.links.each do |link| puts "#{link.text} (#{link.href})" end
e in output avremo una lista del genere:
Links on Rubinius : The Ruby Virtual Machine Home (/) Download (/download) Documentation (/rbx_documentation) Contribute (/contribute) Community (/community) FAQ (/faq) News (/news) Ruby (http://ruby-lang.org) RSpec (http://rspec.rubyforge.org) Rubinius on Lighthouse (http://rubinius.lighthouseapp.com/) Evan Phoenix (http://blog.fallingsnow.net) the BSD license (http://en.wikipedia.org/wiki/BSD_license#Terms)
Di notevole utilità è il metodo click
che permette di aprire un link semplicemente indicandone il nome, ad esempio se dalla pagina vista di prima vogliamo aprire la pagina delle FAQ basta solo clickare sul link giusto:
faq_page = agent.click rubini.links.text('FAQ')