Hiperlinks scraper – jak szybko napisać przydatne narzędzie skryptowe do wydobywania hiperlinków z treści stron webowych

scraperNa potrzeby moich autorskich warsztatów z zaawansowanego programowania użytecznych rozwiązań w języku Ruby, powstało kolejne narzędzie, które pokazuje jak prosty i efektywny może być web data scraping z wykorzystaniem skryptów. Napisanie web scrapera przy odrobinie wprawy to kwestia kilku, no może kilkunastu minut, zaś możliwości tego rodzaju narzędzi są ogromne, tym większe, jeśli dekodowanie struktur CSS stron webowych połączymy dodatkowo z ogromną siłą wyrażeń regularnych. Połączenie tych dwóch elementów daje nam nieograniczone możliwości tworzenia najbardziej zaawansowanych scraperów, jakie tylko jesteśmy w stanie wykoncypować i zaprojektować.

Skrypt korzysta ze świetnej, moim zdaniem, biblioteki Mechanize. Przy jej pomocy możliwe jest wyjście poza ograniczone ramy tworzenia wyłącznie prostych scraperów do pozyskiwania danych ze stron nie wchodzących w interakcję z użytkownikiem i wejście w obszar zastosowań, gdzie biblioteka Mechanize ujawnia swoja prawdziwą moc – mianowicie, w możliwość pełnego oprogramowania dowolnej tego rodzaju interakcji. Po rozpoznaniu podstawowej struktury formularzy, proste staje się bowiem wypełnianie ich treścią i sterowanie przebiegiem aplikacji webowych.

Załączony skrypt wydobywa hiperlinki ze strony znajdującej się pod podanym adresem URI, ale równie dobrze może wydobywać dowolne inne dane. Kluczem jest ten fragment kodu:

agent = Mechanize.new { |a| a.ssl_version, a.verify_mode = 'SSLv3', OpenSSL::SSL::VERIFY_NONE }
page = agent.get(uri)
page.search('a[href]').each do |line|       # Tu: szukanie wszystkich hiperlinków
   if line.to_s =~ /(^.*?)(http\S*)(".*$)/  # Przefiltrowanie hiperlinków HTTP i HTTPS
      results += "#{$2}\n"
   end
end

Metoda ‚search’ pozwala na proste wyróżnienie dowolnej sekcji CSS.

Skrypt został wyposażony w graficzny interfejs użytkownika napisany w oparciu o bibliotekę Gtk2.

W razie potrzeby chętnie udostępnię także wersję do uruchamiania z poziomu linii poleceń.

Przypominam dla porządku, że dla poprawności działania skryptu wymagane jest wcześniejsze zainstalowanie bibliotek Mechanize i Gtk2 poleceniami:

gem install gtk2
gem install mechanize

Osoby zainteresowane zaawansowanym wykorzystaniem biblioteki Mechanize poproszę o pozostawienie mi wiadomości poprzez formularz kontaktowy.

Zachęcam jak zwykle do modyfikacji skryptu we własnym zakresie i dostosowania go do własnych potrzeb.

Interfejs użytkownika prezentuje się następująco: link_scraper Oto kod źródłowy programu:

# encoding: UTF-8 
require 'gtk2'
require 'rubygems'
require 'mechanize'

def get_links(uri)
   results = ""
   begin
      agent = Mechanize.new { |a| a.ssl_version, a.verify_mode = 'SSLv3', OpenSSL::SSL::VERIFY_NONE }
      page = agent.get(uri)
      page.search('a[href]').each do |line|
         if line.to_s =~ /(^.*?)(http\S*)(".*$)/
            results += "#{$2}\n"
         end
      end
   rescue => error
      STDERR.puts "Problem with following the link"
      exit 
   end
   return results 
end

def save_button_clicked (parent, btt)
  filename = ""
  dialog = Gtk::FileChooserDialog.new(
      "Save File As ...",
      parent,
      Gtk::FileChooser::ACTION_SAVE,
      nil,
      [ Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL ],
      [ Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT ]
  )
  dialog.signal_connect('response') do |w, r|
    odg = case r
      when Gtk::Dialog::RESPONSE_ACCEPT
        filename = dialog.filename
        "'ACCEPT' (#{r}) button pressed -- filename is {{ #{filename} }}"
      when Gtk::Dialog::RESPONSE_CANCEL;   "'CANCEL' (#{r}) button pressed"
      else; "Undefined response ID; perhaps Close-x? (#{r})"
    end
    dialog.destroy 
  end
  dialog.run
  return filename
end

def message_box(parent, message)
   dialog = Gtk::MessageDialog.new(
      parent,
      Gtk::Dialog::MODAL,
      Gtk::MessageDialog::INFO,
      Gtk::MessageDialog::BUTTONS_OK,
      message
   )
   dialog.title = "Attention"
   dialog.run
   dialog.destroy
end

def button_clicked (parent)
  dialog = Gtk::MessageDialog.new(
      parent,
      Gtk::Dialog::MODAL,
      Gtk::MessageDialog::INFO,
      Gtk::MessageDialog::BUTTONS_OK,
      "The button was clicked!"
  )
  dialog.title = "Information"
  dialog.run {|r| puts "response=%d" % [r]}
  dialog.destroy
end

window = Gtk::Window.new(Gtk::Window::TOPLEVEL)
window.set_title  "Hiperlinks scraper - Janusz Nawrat (2014)"
window.border_width = 10
window.set_size_request(350, 420)

window.signal_connect('delete_event') { Gtk.main_quit }

main_vbox = Gtk::VBox.new()
main_frame = Gtk::Frame.new("Hiperlinks extractor from web page")
main_frame.add(main_vbox)

ask_hbox = Gtk::HBox.new()
ask_frame = Gtk::Frame.new("Enter web page address")
ask_frame.add(ask_hbox)
ask_entry = Gtk::Entry.new()
ask_entry.text = "http://"
ask_button = Gtk::Button.new("Go")
ask_hbox.pack_start(ask_entry, true, true, 2)
ask_hbox.pack_start(ask_button, true, true, 2)

main_vbox.pack_start(ask_frame, true, true, 2)

results = Gtk::TextView.new()
results.buffer.text = ""

scrolled_window = Gtk::ScrolledWindow.new
scrolled_window.border_width = 5
scrolled_window.add(results)
scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)
scrolled_window.set_size_request(300, 300)

main_vbox.pack_start(scrolled_window, true, true, 2)

control_hbox = Gtk::HBox.new()
control_frame = Gtk::Frame.new()
control_frame.add(control_hbox)

save_button = Gtk::Button.new("Save results")
clear_button = Gtk::Button.new("Clear")
exit_button = Gtk::Button.new("Exit")

save_button.signal_connect("clicked") do
   file_to_save = save_button_clicked(window, save_button)
   begin
      result_file = File.new(file_to_save, "w")
      if result_file
         result_file.syswrite(results.buffer.text)
         message_box(window, "Results data saved in #{File.basename(file_to_save)}")
      else
         raise error, 'File #{file_to_save} opening error'
      end
   rescue => error
      puts "Error in opening the file to save results: #(error)"
      Gtk.main_quit
   end
end

exit_button.signal_connect("clicked") do
   Gtk.main_quit
end

clear_button.signal_connect("clicked") do
   results.buffer.text = ""
end

ask_button.signal_connect("clicked") do
   results.buffer.text = get_links(ask_entry.text)
end

control_hbox.pack_start(save_button, true, true, 2)
control_hbox.pack_start(clear_button, true, true, 2)
control_hbox.pack_start(exit_button, true, true, 2)

main_vbox.pack_start(control_frame, true, true, 2)

window.add(main_frame)

window.show_all
Gtk.main

Informacje Janusz Nawrat
Just ordinary man who likes thinking...

2 Responses to Hiperlinks scraper – jak szybko napisać przydatne narzędzie skryptowe do wydobywania hiperlinków z treści stron webowych

  1. erertyrtep3rwrew.pl pisze:

    mechanize to ciekawa biblioteka, a nie myslales by za jej pomoca zrobic siec anonimowa?
    wystarczy na dowolnej stronie postawic cos na ksztalt proxy. wysylasz zapytanie i mechanize zapisuje wszystko w bazie i czeka. Gdy ktos poprosi o te strone wyswietlisz ja. Cala idea jest tylko w tym by proxy sie ze soba komunikowaly i by zapytanie bylo losowe tab by za kazdym razem kto inny odczytywal dane. System nie umozliwialby pisania (PUSH, AJAX) tylko czytanie. Mozna bylo by wrecz wylaczyc JS. Kazdy uzytkownik mialby lokalnie klienta i na dowolnych darmowych serwerach bylby serwer proxy.

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s

TOMASZ WEŁNA

artysta grafik | wykładowca

PRACOWNIA OKO

Szkoła Rysunku Malarstwa i Grafiki DR TOMASZA WEŁNY | KRAKÓW | Plac Matejki 10 | tel 691 81 75 74

Piękno neurobiologii

Blog Jerzego Vetulaniego

Teoria muzyki, zasady muzyki, podstawy muzyki

Teoria muzyki, zasady muzyki, podstawy muzyki - czyli to co każdy amator muzyki wiedzieć powinien :)

Personal Development & Inspirations

Przemyślenia i refleksje, którymi warto się podzielić (blog by Janusz Nawrat)

Business IT Cooperation Platform

Biznes i IT - dwa światy, które muszą współdziałać

%d bloggers like this: