Was macht Web::Scraper?
Wie können wir Web::Scraper steuern?
Anwendungen von Web::Scraper
Information im Web
Traditionell: Automation, Automation, Automation
Fahrplan
Kinoprogramm
neue Dateien zum Download
 
HTML im Browser
Daten für Perl freilegen
Navigation (WWW::Mechanize)
Extraktion (Web::Scraper)
Web::Scraper
Geschrieben von Tatsuhiko Miyagawa
 
Plagger (RSS-Anwendung)
Angelehnt an Ruby's scrapi-Modul
Die Webseite
Die Beschreibung in Web::Scraper
Abfragen in Web::Scraper mit CSS-Selektoren
Abfragen in Web::Scraper mit XPath
 
Beispiel:
Extraktion aus Kinoprogramm
 
Echte Webseite
 
Vereinfachte Webseite
 
Vereinfachte Webseite
Zielelemente
 
 
Ein erstes Beispiel:
 1:  use LWP::Simple 'get';
 2:  use Web::Scraper;
 3:  my $s = scraper {
 4:      process 'title' => 'titel' => 'TEXT';
 5:  };
Ein erstes Beispiel:
 1:  use LWP::Simple 'get';
 2:  use Web::Scraper;
 3:  my $s = scraper {
 4:      process 'title' => 'titel' => 'TEXT';
 5:  };
 6:  my $r = $s->scrape(get 'beispiele/kino.html');
 7:  print Dumper $r;
Ein erstes Beispiel:
 1:  use LWP::Simple 'get';
 2:  use Web::Scraper;
 3:  my $s = scraper {
 4:      process 'title' => 'titel' => 'TEXT';
 5:  };
 6:  my $r = $s->scrape(get 'beispiele/kino.html');
 7:  print Dumper $r;
 1:  $VAR1 = {
 2:          'titel' => 'Programm vom 19.12.2007 bis zum 26.12.2007',
 3:  }
API ist wenig dokumentiert
eigene "Sprache" mit Perl als Grundlage
Gut: Beschreibung als Code, nicht als Daten
Schlecht: Beschreibung als Code, nicht als Daten
 1:  my $s = scraper {
 2:      process 'title' => 'titel' => 'TEXT';
 3:      result 'title';
 4:  };
scraper { ... } - erzeugt ein neues Web::Scraper Objekt
process REGEL, ZIELNAME, ELEMENTE - definiert eine neue Regel zur Extraktion von Daten
 1:  my $s = scraper {
 2:      process 'title' => 'titel' => 'TEXT';
 3:      
 4:      # Ab 20 Uhr die Filme für morgen anzeigen:
 5:      if (strftime('%H%M',localtime) > '2000') {
 6:          process 'p.morgen' => 'uhrzeit' => 'TEXT'
 7:      } else { ... }
 8:      
 9:      result 'title';
10:  };
Perl Code ist erlaubt, zum Beispiel für if-Bedingungen
result LISTE - zur genauen Angabe der Ergebnisse
 
 
 
 
[] sammelt Werte
  my $s = scraper {
    process 'title' => 'titel' => 'TEXT';
    process 'p' => 'texte[]' => 'TEXT';
    }
[] sammelt Werte
  my $s = scraper {
    process 'title' => 'titel' => 'TEXT';
    process 'p' => 'texte[]' => 'TEXT';
    }
 
 
 
[] sammelt Werte
 1:  my $s = scraper {
 2:      process 'title' => 'titel' => 'TEXT';
 3:      process 'p' => 'texte[]' => 'TEXT';
 4:  }
 1:  $VAR1 = {
 2:          'titel' => 'Kinoprogramm vom 19.12.2007 bis zum 26.12.2007',
 3:          'texte' => [
 4:                       'Der Goldene Kompass',
 5:                       '3.12.07',
 6:                       'Elisabeth - Das Goldene Zeitalter',
 7:                       '3.12.07'
 8:                     ],
 9:  }
Mit
1: p.f
matchen wir CSS Klassen
1: <p class="f">Der Goldene Kompass</p>
 
 
 
 
 
 1:  my $s = scraper {
 2:      process 'title' => 'titel' => 'TEXT';
 3:      process 'p.f' => 'filme[]' => 'TEXT';
 4:      process 'p.d' => 'tage[]' => 'TEXT';
 5:  };
 1:  $VAR1 = {
 2:          'titel' => 'Kinoprogramm vom 19.12.2007 bis zum 26.12.2007',
 3:          'filme' => [
 4:                       'Der Goldene Kompass',
 5:                       'Elisabeth - Das Goldene Zeitalter'
 6:                     ],
 7:          'tage' => [
 8:                      '3.12.07',
 9:                      '3.12.07'
10:                    ]
11:  }
 
 
 
 
1: p <p ... 2: 3: p.d <p class="d" ...
1: p <p ... 2: 3: p.d <p class="d" ... 4: 5: #elizabeth <* id="elizabeth" ... 6: 7: p#elizabeth <p id="elizabeth" ...
1: p <p ... 2: 3: p.d <p class="d" ... 4: 5: #elizabeth <* id="elizabeth" ... 6: 7: p#elizabeth <p id="elizabeth" ... 8: 9: div p <div ...><p ...>...</div> 10: 11: div,p <div>... oder <p>...
CSS Selektoren
 
... finden HTML Elemente
... in einfacher Hierarchie
Wenige Attribute (class, id)
 
Falls CSS nicht genug ist
XPath beschreibt den Pfad innerhalb des Dokuments
1: # Erster Paragraph 2: /html/body/div/p[0]
Wildcards sind erlaubt
1: # In DIV enthaltene Tags 2: //div/*
Klassenattribute
1: # Filmelement 2: //*@class="f"
1: ... 2: <div> 3: <p class="f">Der Goldene Kompass</p> 4: <p>3.12.07</p> 5: </div> 6: ...
Index
1: //div/p[0] -> Filmtitel 2: //div/p[1] -> Filmdatum
XPath kann wie ein Verzeichnisbaum navigieren:
1: ... 2: <div> 3: <p>Der Goldene Kompass</p> 4: <p>3.12.07</p> 5: </div> 6: ...
XPath kann wie ein Verzeichnisbaum navigieren:
1: ... 2: <div> 3: <p>Der Goldene Kompass</p> 4: <p>3.12.07</p> 5: </div> 6: ...
1: //div/p[0]/. -> Filmtitel
XPath kann wie ein Verzeichnisbaum navigieren:
1: ... 2: <div> 3: <p>Der Goldene Kompass</p> 4: <p>3.12.07</p> 5: </div> 6: ...
1: //div/p[0]/. -> Filmtitel 2: //div/p[1]/../ -> div
XPath kann wie ein Verzeichnisbaum navigieren:
1: ... 2: <div> 3: <p>Der Goldene Kompass</p> 4: <p>3.12.07</p> 5: </div> 6: ...
1: //div/p[0]/. -> Filmtitel 2: //div/p[1]/../ -> div 3: //div/* -> Alle Kinder des div
1: ... 2: <div> 3: <p class="f">Der Goldene Kompass</p> 4: <p>3.12.07</p> 5: </div> 6: ...
1: ... 2: <div> 3: <p class="f">Der Goldene Kompass</p> 4: <p>3.12.07</p> 5: </div> 6: ...
1: //div/p[@f] -> Filmtitel
1: ... 2: <div> 3: <p class="f">Der Goldene Kompass</p> 4: <p>3.12.07</p> 5: </div> 6: ...
1: //div/p[@f] -> Filmtitel 2: //div/p[not(@f)]/../ -> Filmdatum
XPath Selektoren
 
... finden HTML Elemente
... in komplexer Hierarchie
Alle Attribute (@class)
Komplexe Prädikate (div/[p@f])
Komplexe Abfragesprache
 1:  $VAR1 = {
 2:          'filme' => [
 3:                       'Der Goldene Kompass',
 4:                       'Elisabeth - Das Goldene Zeitalter'
 5:                     ],
 6:          'tage' => [
 7:                      '3.12.07',
 8:                      '3.12.07'
 9:                    ]
10:  }
Hierarchie im HTML
Hierarchie im Code
Schleife mit Web::Scraper statt Schleife in Perl
 
 
 
 
 
 1:    process 'div' => 'filme[]' => scraper {
 2:        process( 'p.f', 'filmtitel' => 'TEXT');
 3:        process( 'p.d', 'datum' => 'TEXT');
 4:    };
1: =>
 1:  $VAR1 = {
 2:    'titel' => 'Programm vom 19.12.2007 bis zum 26.12.2007',
 3:    'filme' => [
 4:      {
 5:        'filmtitel' => 'Der Goldene Kompass',
 6:        'datum' => '3.12.07'
 7:      },
 8:      {
 9:        'filmtitel' => 'Elisabeth - Das Goldene Zeitalter',
10:        'datum' => '3.12.07'
11:      }
12:    ]
13:  };
Web::Scraper API
process Regel, Name, Werte
Regel (CSS oder XPath)
Name (einfacher Name oder mit [])
Werte  TEXT, scraper { ... }, Perl Code
Perl Module
HTML::TableExtract
Template::Extract
Web::Scraper shell
Andere Anwendungen
FireBug (FireFox)
DOM Inspector (FireFox)
CSS Selektoren
HTML::Selector::XPath
XPath Queries (W3C)
HTML::Selector::XPath
Fragen?
Abfahrtszeiten und Fahrtstrecken
1: http://www.rmv.de/auskunft/bin/jp/query.exe/dn? 2: L=vs_rmv&REQ0JourneyStopsN=-1&REQ0JourneyStopsS0A 3: =255&REQ0JourneyStopsS0G=f+roederbergweg& 4: REQ0JourneyStopsZ0A=255&REQ0JourneyStopsZ0G= 5: perlworkshop&start%26date%3D%2B0 6: %26times%3D%2B0%26dummy=jetzt 7: &querypagedisplayed=yes
 
1: ... 2: <td headers="hafasOVStop" ...>Frankfurt (Main) Röderbergweg 3: <td headers="hafasOVDate" ...>06.02.08 4: <td headers="hafasOVTime" ...>20:36 5: <td headers="hafasOVDuration" ...>7 Min. 6: ...
 1:    my $item = scraper {
 2:        process '//td[@headers = "hafasOVStop"]',
 3:           haltestelle => 'TEXT';
 1:    my $item = scraper {
 2:        process '//td[@headers = "hafasOVStop"]',
 3:           haltestelle => 'TEXT';
 4:        process '//td[@headers = "hafasOVDate"]',
 5:           datum => 'TEXT';
 6:        process '//td[@headers = "hafasOVTime"]/following-sibling::td',
 7:           uhrzeit => 'TEXT';
 8:        process '//td[@headers = "hafasOVDuration"]',
 9:           zeit => 'TEXT';
10:    };
 1:    my $item = scraper {
 2:        process '//td[@headers = "hafasOVStop"]',
 3:           haltestelle => 'TEXT';
 4:        process '//td[@headers = "hafasOVDate"]',
 5:           datum => 'TEXT';
 6:        process '//td[@headers = "hafasOVTime"]/following-sibling::td',
 7:           uhrzeit => 'TEXT';
 8:        process '//td[@headers = "hafasOVDuration"]',
 9:           zeit => 'TEXT';
10:    };
11:    
12:    my $page = scraper {
13:        process q{//table[@class = "hafasResult"]/tr[td/input]},
14:            'items[]' => $item;
15:    };
 1:  $VAR1 = {
 2:    'items' => [
 3:      {
 4:        'uhrzeit' => '21:2721:34',
 5:        'zeit' => ' 0:07 ',
 6:        'datum' => '12.02.08',
 7:        'haltestelle' => "..."
 8:      },
 9:    ...
Fragen?