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?