Was ist Web Scraping?
Beispiele von Web Scraping
Überlegungen zum eigenen Scraper
Max Maischein
DZ BANK Frankfurt
Deutsche Zentralgenossenschaftsbank
Informationsmanagement TxB
Wenn ich es von Hand kann
... kann der Computer es wiederholen
... jedesmal korrekt
DZ BANK AG
Intranet Automation und Scraping (WWW::Mechanize::Firefox)
DZ BANK AG
Intranet Automation und Scraping (WWW::Mechanize::Firefox)
Leute fragen nach Web Scraping
Leute fragen nach HTML Parsern
Web Scraping ist
die automatisierte
Extraktion von Daten
aus Datenquellen die über HTTP bereitgestellt sind
und als HTML kodiert sind
(oder Javascript)
Perl
Etwas HTTP
Etwas HTML+CSS
WWW::Mechanize::Firefox::DSL
Gemeinsame API
WWW::Scripter, WWW::Mechanize
Selbe Konzepte
Mojo::DOM, Web::Scraper, App::scrape.
Nicht alles, was technisch möglich ist, ist auch erlaubt oder erwünscht
Können wir Scraping vermeiden?
1: Datenbankzugriff 2: Datenbankdump
Ist Scraping erlaubt?
1: Nutzungsbedingungen (TOS) 2: Gelten die für uns?
Welche Schritte führt ein Mensch durch
->
Navigation
->
Inhalt/Datenextraktion
Automatisieren
Wiederholen
13. Deutscher Perl Workshop (19. bis 21. Oktober 2011)
Nachrichten verfolgen
Nur Extraktion, keine Navigation
HTML der Seite anzeigen
1: #!perl -w 2: use WWW::Mechanize::Firefox; 3: my $mech = WWW::Mechanize::Firefox->new(); 4: 5: $mech->get('http://conferences.yapceurope.org/gpw2011'); 6: print $mech->content();
WWW::Mechanize::Firefox
1: #!perl -w 2: use WWW::Mechanize::Firefox; 3: my $mech = WWW::Mechanize::Firefox->new(); 4: 5: $mech->get('http://conferences.yapceurope.org/gpw2011'); 6: print $mech->content();
WWW::Mechanize::Firefox::DSL
1: #!perl -w 2: use WWW::Mechanize::Firefox::DSL; 3: 4: 5: get('http://conferences.yapceurope.org/gpw2011'); 6: print content();
Firebug
Add-on für Firefox
Visuelles Werkzeug um Seitenelemente zu untersuchen
Nachrichten extrahieren
1: .newsbox
1: .newsbox h3 a
1: .newsbox h3 a
1: .newsbox h3 a 2: Call for Papers online
1: .newsbox h3 a 2: Call for Papers online 3: 4: .newsbox h3+p+p 5: Endlich ist es so weit ...
1: #!perl -w 2: use strict; 3: use WWW::Mechanize::Firefox::DSL; 4: 5: get_local('html/gpw-2011-news.htm');
1: #!perl -w 2: use strict; 3: use WWW::Mechanize::Firefox::DSL; 4: 5: get_local('html/gpw-2011-news.htm'); 6: 7: my @headline = selector('.newsbox h3 a'); 8: my @text = selector('.newsbox h3+p+p');
1: #!perl -w 2: use strict; 3: use WWW::Mechanize::Firefox::DSL; 4: 5: get_local('html/gpw-2011-news.htm'); 6: 7: my @headline = selector('.newsbox h3 a'); 8: my @text = selector('.newsbox h3+p+p'); 9: 10: for my $article (0..$#headline) { 11: print $headline[$article]->{innerHTML}, "\n"; 12: print "---", $text[$article]->{innerHTML}, "\n"; 13: };
1: demo/01-scrape-gpw-2011.pl
Kommandozeile bequemer
XPath Extraktoren
Mojolicious::get
App::scrape
WWW::Mechanize::Firefox/examples/scrape-ff.pl
Das Beispiel zeigte
Datenextraktion
mit CSS Selectoren
WWW::Mechanize + HTML::TreeBuilder::XPathEngine + HTML::XPath::Selector
WWW::Mechanize::Firefox
App::scrape
Mojo::DOM
Bilder der (DC) Superhelden von Wikipedia extrahieren
Input: Name des Superhelden
Output: URL des Bilds (oder Bilddaten) des Superheldenbilds
und Beschreibung
Heldennamen eingeben (Navigation)
Beschreibung auf der Ergebnisseite sehen (Extraktion)
Bild auf Ergebnisseite sehen (Extraktion)
1: use WWW::Mechanize::Firefox::DSL; 2: use strict; 3: 4: # Navigation 5: my ($hero) = @ARGV; 6: my $url = 'http://en.wikipedia.org'; 7: get $url; 8: print content; # sind wir hier richtig?
1: use WWW::Mechanize::Firefox::DSL; 2: use strict; 3: 4: # Navigation 5: my ($hero) = @ARGV; 6: my $url = 'http://en.wikipedia.org'; 7: get $url; 8: print content; # sind wir hier richtig? 9: 10: print title; 11: # Wikipedia, the free encyclopedia ...
Wichtig, nicht gleich, aber später, wenn sich die Seite ändert
1: my ($hero) = @ARGV; 2: my $url = 'http://en.wikipedia.org'; 3: get $url; 4: on_page("Wikipedia, the free encyclopedia");
Wichtig, nicht gleich, aber später, wenn sich die Seite ändert
1: my ($hero) = @ARGV; 2: my $url = 'http://en.wikipedia.org'; 3: get $url; 4: on_page("Wikipedia, the free encyclopedia"); 5: 6: ... 7: on_page("$hero - Wikipedia"); 8: 9: sub on_page { 10: my ($expected) = @_; 11: if (title !~ /\Q$expected\E/) { 12: croak sprintf "Falsche Seite [%s], erwarte [%s]", 13: title, $expected; 14: }; 15: };
Feld finden
1: search
Feld finden
1: search
Feldnamen finden
Feld finden
1: search
Feldnamen finden
1: submit_form( with_fields => { 2: search => $hero, 3: });
1: print title; 2: 3: # Superman - Wikipedia, the free ...
1: print title; 2: 3: # Superman - Wikipedia, the free ... 4: 5: on_page($hero);
1: Plastix man
1: Plastix man 2: 3: ... 4: Falsche Seite [Plastix man - Search results -...]
Heldennamen eingeben (Navigation)
Beschreibung auf der Ergebnisseite sehen (Extraktion)
Bild auf Ergebnisseite sehen (Extraktion)
Text Selector finden (Firebug, App::scrape, examples/scrape-ff.pl
)
1: .infobox +p
Extrahieren
1: print $_->{innerHTML} 2: for selector('.infobox +p');
Bild-Selektor finden (Firebug, ...)
1: .infobox a.image img
Extrahieren
1: print $_->{src} 2: for selector('.infobox a.image img'); 3: 4: # http://upload.wikimedia.org/wikipedia/en/thumb/7/72/Superman.jpg/250px-Superman.jpg
Das Beispiel zeigte
Navigation der Webseite
Datenextraktion mit CSS Selectoren
Seitenüberprüfung
Google+ is Googles Social Network
Mittlerweile gibt's eine API
Google+ nach dem Namen suchen
Information aus dem Profil extrahieren
Die "Leute in Circles" extrahieren
1: <h2 class="a-b-D-Nd-aa d-q-p">Links</h2> 2: <ul class="a-b-D-G-lg Nd"> 3: <li><img alt="" class="a-b-D-Mf" src="113231249772841733835_files/favicons_007.png"> 4: <div class="a-b-D-k k"><a class="a-b-D-k-cg url" href="http://corion.net/" 5: ...
1: div.k a.url 2: 3: my @links = selector('div.k a.url'); 4: 5: for my $link (@links) { 6: print $link->{innerHTML}, "\n"; 7: print $link->{href}, "\n"; 8: print "\n"; 9: };
1: 04-scrape-gplus-profile.pl
Google setzt auf JSON / dynamisches Javascript
1: var OZ_initData = 2: ... 3: ,""] 4: ,1,,1] 5: ,[[41,[["113771019406524834799","/113771019406524834799",...,"Paul Boldra"] 6: ,["101868469434747579306","/101868469434747579306",...,"Curtis Poe"] 7: ,["114091227580471410039","/114091227580471410039",...,"James theorbtwo Mastros"] 8: ,["116195765101222598270","/116195765101222598270",...,"Michael Kröll"] 9: ...
Google setzt auf JSON / dynamisches Javascript
1: var OZ_initData = 2: ... 3: ,""] 4: ,1,,1] 5: ,[[41,[["113771019406524834799","/113771019406524834799",...,"Paul Boldra"]
Wir wollen
1: OZ_initData["5"][3][0]
1: my ($info,$type) 2: = eval_in_page('OZ_initData["5"][3][0]'); 3: 4: my $items = $info->[0]; 5: print "$items Nutzer in Circles\n"; 6: for my $i (@{ $info->[1] }) { 7: print $i->[0], "\t", $i->[3],"\n"; 8: };
1: demo/05-scrape-gplus-circle.pl
Dieses Beispiel zeigte
Seiten/Anwendungsnavigation
Datenextraktion
aus JSON / Javascript Strukturen
WWW::Mechanize::Firefox
Vielleicht auch WWW::Scripter
Du willst es doch auch!
Seiten Navigieren
Extraktion beschreiben
Daten oder (Perl) Code?
Andere Scraper anschauen und benutzen
Konfiguration
Navigation
Extraktion
Geschwindigkeit
Externe Unterstützung (Flash, Java, Javascript, ...)
Der Flaschenhals sind Latenz und Netzwerktransfer
Navigation vermeiden
1: http://en.wikipedia.org/wiki/Superman 2: http://en.wikipedia.org/wiki/$super_hero
Funktioniert nicht für Google+
1: https://plus.google.com/v/xXxXxXx
Nicht den Server überlasten
Durchsatz erhöhen mit mehr als einem Scraper (AnyEvent::HTTP)
Durchsatz erhöhen mit mehr als einem Scraper
(threads
)
Nicht den Server überlasten
On the internet, nobody knows that you're a dog(strike)Perl script
Browser automatisieren
or
Dieselben Daten senden
Browser automatisieren
WWW::Mechanize::Firefox , PhantomJS
Visuell
Brauchen VNC Display oder X Terminal
Portable Firefox Installationen
Wireshark / Live HTTP Headers
Nachahmen, was der Browser sendet
1: GET /-8RekFwZY8ug/AAAAAAAAAAI/AAAAAAAAAAA/7gmV6WFSVG8/photo.jpg?sz=80 HTTP/1.1 2: Host: lh5.googleusercontent.com 3: User-Agent: Mozilla/5.0 (Windows; U; ...
Wireshark / Live HTTP Headers
Nachahmen, was der Browser sendet
1: GET /-8RekFwZY8ug/AAAAAAAAAAI/AAAAAAAAAAA/7gmV6WFSVG8/photo.jpg?sz=80 HTTP/1.1 2: Host: lh5.googleusercontent.com 3: User-Agent: Mozilla/5.0 (Windows; U; ...
Unterschiede eliminieren
1: ->user_agent() 2: ->cookies() 3: 4: Accept-Encoding 5: ...
Viele Frameworks mit unterschiedlichen Tradeoffs
Das Netzwerk versteckt das Programm
Browser automatisieren
Netzwerktraffic nachahmen
Der Beispielcode ist online unter
Der Beispielcode ist online unter
https://github.com/corion/webscraping-workshop
Fragen?
Max Maischein (corion@cpan.org
)
"Cognitive Hazard" von Anders Sandberg
Bilder der Superhelden von Wikipedia
Bonus Section
HTML::Selector::XPath - konvertiert von CSS(3) nach XPath
pQuery - jQuery-ähnliche extraction
HTML::JQuery - jQuery-ähnliche Extraktion
1: $dom->q('p')->q('div')->...
Mojo::DOM - AUTOLOAD jQuery-ähnliche Extraktion
1: $dom->p->div->(...)
Web::Scraper - spezielle DSL
1: scrape { title => ..., 2: 'url[]' => scrape { ... } 3: }
Die Arbeit der anderen
Tatsuhiko Miyagawa
HTML::Selector::XPath - für CSS3 Selektoren
HTML::AutoPagerize - mehrseitige Suchergebnisse