Advertisement
  1. Code
  2. Ruby

Erstellen Sie Ihren ersten Web Scraper, Teil 1

Scroll to top
Read Time: 26 min

German (Deutsch) translation by Alex Grigorovich (you can also view the original English article)

Rubyland hat zwei Juwelen, die in den letzten Jahren die Aufmerksamkeit auf sich gezogen haben: Nokogiri und Mechanize.  Wir geben zu jedem einen Artikel, bevor wir ihn mit einem praktischen Beispiel in die Tat umsetzen.

Themen

  • Web Scraping?
  • Genehmigung
  • Das Problem
  • Nokogiri
  • Extraktion?
  • Seiten
  • API
  • Knoten Navigation

Web Scraping?

Es gibt mehr Begriffe als Web oder Screen Scraping.  Web-Harvesting und Web-Datenextraktion sagen dir sofort, was los ist.  Wir können die Extraktion von Daten von Webseiten automatisieren - und das ist auch nicht so kompliziert.

Mit diesen Tools können Sie das Surfen im Internet imitieren und automatisieren.  Sie schreiben ein Programm, das nur die Art von Daten extrahiert, die Sie interessieren.  Das Targeting spezifischer Daten ist fast so einfach wie die Verwendung von CSS-Selektoren.

Vor ein paar Jahren habe ich einen Online-Video-Kurs abonniert, der eine Million kurze Videos enthält, aber keine Möglichkeit, sie in großen Mengen herunterzuladen.  Ich musste jeden Link alleine durchgehen und das gefürchtete "Speichern als" selbst machen.  Es war eine Art menschliches Web-Scraping - etwas, das wir oft tun müssen, wenn uns das Wissen fehlt, um solche Sachen zu automatisieren.  Der Kurs selbst war in Ordnung, aber ich habe ihre Dienste danach nicht mehr genutzt.  Es war einfach zu langweilig.

Heute würde ich mich nicht so sehr mit solchen Gedanken schmelzenden UX beschäftigen.  Ein Scraper, der das Herunterladen für mich übernehmen würde, würde mich nur ein paar Minuten brauchen, um ihn zusammen zu werfen.  Kein großes Problem!

Lass es mich kurz vor dem Start durchbrechen.  Das Ganze kann in ein paar Schritten zusammengefasst werden. Zuerst holen wir eine Webseite mit den gewünschten Daten, die wir brauchen.  Dann durchsuchen wir diese Seite und identifizieren die Informationen, die wir extrahieren möchten.

Der letzte Schritt besteht darin, diese Bits zu targetieren, sie bei Bedarf in Scheiben zu schneiden und zu entscheiden, wie und wo sie gespeichert werden sollen.  Gut geschriebenes HTML ist oft der Schlüssel, um diesen Prozess einfach und angenehm zu gestalten.  Bei komplizierteren Extraktionen kann es schmerzhaft sein, wenn Sie mit schlecht strukturiertem Markup umgehen müssen.

Was ist mit APIs?  Sehr gute Frage.  Wenn Sie Zugriff auf einen Service mit einer API haben, ist es oft nicht nötig, einen eigenen Scraper zu schreiben.  Dieser Ansatz ist hauptsächlich für Websites, die diese Art von Bequemlichkeit nicht bieten.  Ohne eine API ist dies oft die einzige Möglichkeit, die Extraktion von Informationen von Websites zu automatisieren.

Sie könnten fragen, wie funktioniert dieses Scraping-Ding tatsächlich?  Ohne in das tiefe Ende zu springen, ist die kurze Antwort, indem Baumdatenstrukturen durchquert werden.  Nokogiri erstellt diese Datenstrukturen aus den Dokumenten, die Sie füttern, und lässt Sie interessante Teile für die Extraktion auswählen.  Zum Beispiel ist CSS eine Sprache, die für das Traversieren von Bäumen geschrieben wird, um Baumstrukturdaten zu suchen, und wir können sie für die Datenextraktion verwenden.

Es gibt viele Ansätze und Lösungen zum Spielen.  Rubyland hat zwei Juwelen, die seit einigen Jahren im Rampenlicht stehen.  Viele Leute verlassen sich immer noch auf Nokogiri und Mechanize für HTML-Scraping-Bedürfnisse.  Beide wurden getestet und bewiesen, dass sie einfach zu bedienen sind und gleichzeitig sehr leistungsfähig sind.  Wir werden beide betrachten.  Aber vorher möchte ich einen Moment nehmen, um das Problem anzusprechen, das wir am Ende dieser kurzen Einführungsreihe lösen werden.

Genehmigung

Bevor Sie mit dem Scraping beginnen, stellen Sie sicher, dass Sie die Berechtigung der Websites haben, auf die Sie für die Datenextraktion zugreifen möchten.  Wenn die Website beispielsweise über eine API oder einen RSS-Feed verfügt, ist es möglicherweise nicht nur einfacher, den gewünschten Inhalt zu erhalten, sondern auch die legale Option der Wahl.

Nicht jeder wird es zu schätzen wissen, wenn Sie auf ihren Websites massiv scrapen - verständlicherweise.  Informieren Sie sich über die Seite, die Sie interessiert, und geraten Sie nicht in Schwierigkeiten.  Die Chancen stehen niedrig, dass Sie ernsthaften Schaden anrichten werden, aber das Risiko zu riskieren, ist unwissentlich nicht der richtige Weg.

Das Problem

Ich musste einen neuen Podcast erstellen.  Das Design war nicht da, wo ich es haben wollte, und ich hasste es, neue Beiträge zu veröffentlichen.  Verdammte WYSIWYGs!  Ein bisschen Kontext.  Vor ungefähr zwei Jahren habe ich die erste Version meines Podcasts gebaut.  Die Idee war, mit Sinatra zu spielen und etwas superleichtes zu bauen.  Ich hatte ein paar unerwartete Probleme, seit ich so ziemlich alles maßgeschneidert habe.

Von Rails kommend, war es definitiv eine lehrreiche Reise, die ich zu schätzen weiß, aber ich bedauerte es schnell, keine statische Seite verwendet zu haben, die ich über GitHub-Seiten über GitHub hätte bereitstellen können.  Die Bereitstellung neuer Episoden und deren Pflege fehlte die Einfachheit, nach der ich suchte.  Für eine Weile entschied ich, dass ich größere Fische zum Frittieren hatte und konzentrierte mich stattdessen darauf, neues Podcast-Material zu produzieren.

Im vergangenen Sommer habe ich angefangen ernst zu werden und habe an einer Middleman-Seite gearbeitet, die auf GitHub-Seiten gehostet wird.  Für die zweite Staffel der Show wollte ich etwas frisches.  Ein neues, vereinfachtes Design, Markdown für die Veröffentlichung neuer Folgen und keine Faustkämpfe mit Heroku-Himmel!  Die Sache war, dass ich 139 Episoden herumliegen hatte, die zuerst importiert und konvertiert werden mussten, um mit Middleman zu arbeiten.

Für Beiträge verwendet Middleman .markdown-Dateien, die so genannte Frontmatter für Daten haben, die meine Datenbank im Grunde ersetzt.  Diese Übertragung per Hand ist für 139 Episoden nicht möglich.  Dafür ist Berechnung da.  Ich musste eine Möglichkeit finden, den HTML-Code meiner alten Website zu analysieren, den relevanten Inhalt zu scrappen und in Blogposts zu übertragen, die ich für die Veröffentlichung neuer Podcast-Episoden auf Middleman nutze.

Deshalb werde ich Ihnen in den nächsten drei Artikeln die Werkzeuge vorstellen, die in Rubyland für solche Aufgaben gebräuchlich sind.  Am Ende werden wir auf meine Lösung eingehen, um Ihnen auch etwas Praktisches zu zeigen.

Nokogiri

Auch wenn Sie Ruby / Rails ganz neu sind, sind die Chancen sehr gut, dass Sie bereits von diesem kleinen Juwel gehört haben.  Der Name wird oft fallen gelassen und bleibt leicht bei dir.  Ich bin mir nicht sicher, ob viele wissen, dass Nokogiri japanisch für "sah" ist.

Es ist ein passender Name, sobald Sie verstehen, was das Werkzeug tut.  Der Schöpfer dieses Edelsteins ist der schöne Tenderlove, Aaron PattersonNokogiri konvertiert XML- und HTML-Dokumente in eine Datenstruktur - genauer gesagt in eine Baumdatenstruktur.  Das Tool ist schnell und bietet eine schöne Oberfläche.  Insgesamt ist es eine sehr potente Bibliothek, die sich um eine Vielzahl Ihrer HTML-Scraping-Bedürfnisse kümmert.

Sie können Nokogiri nicht nur zum Parsen von HTML verwenden; XML ist ein faires Spiel. Es gibt Ihnen die Optionen der XML-Pfadsprache und der CSS-Schnittstellen, um die geladenen Dokumente zu durchlaufen.  XML-Pfadsprache oder kurz XPath ist eine Abfragesprache.

Es ermöglicht uns, Knoten aus XML-Dokumenten auszuwählen.  CSS-Selektoren sind eher Anfängern bekannt.  Wie bei Stilen, die Sie schreiben, machen CSS-Selektoren das Targeting auf bestimmte Abschnitte von Seiten, die für die Extraktion interessant sind, denkbar einfach.  Sie müssen nur Nokogiri wissen lassen, wonach Sie suchen, wenn Sie ein bestimmtes Ziel anvisieren.

Seiten

Was wir immer anfangen müssen, ist die aktuelle Seite, an der wir interessiert sind.  Wir geben an, welche Art von Nokogiri-Dokument wir parsen wollen - XML ​​oder HTML zum Beispiel:

1
Nokogiri::XML
2
3
Nokogiri::HTML

some_scraper.rb

1
require "nokogiri"
2
3
require "open-uri"
4
5
page = Nokogiri::XML(File.open("some.xml"))
6
7
page = Nokogiri::HTML(File.open("some.html"))

Nokogiri:XML und Nokogiri:HTML kann IO-Objekte oder String-Objekte aufnehmen.  Was oben passiert, ist einfach.  Dies öffnet und ruft die angegebene Seite unter Verwendung von open-uri ab und lädt dann seine Struktur, sein XML oder HTML in ein neues Nokogiri-Dokument.  XML ist etwas, mit dem Anfänger sich nicht oft befassen müssen.

Daher würde ich empfehlen, dass wir uns vorerst auf das HTML-Parsing konzentrieren.  Warum open-uri?  Mit diesem Modul aus der Ruby Standard Library können wir die Seite ohne viel Aufwand aufnehmen.  Da IO-Objekte faires Spiel sind, können wir open-uri einfach nutzen.

API

Lassen Sie uns dies mit einem kleinen Beispiel umsetzen: 

at_css

some_podcast_scraper.rb

1
require 'nokogiri'
2
3
require "open-uri"
4
5
url = 'http://betweenscreens.fm/'
6
7
page = Nokogiri::HTML(open(url))
8
9
header = page.at_css("h2.post-title")
10
11
title = header.text
12
13
puts "This is the raw header of the latest episode: #{header}"
14
15
puts "This is the title of the latest episode: #{title}"

Was wir hier gemacht haben, stellt alle Schritte dar, die normalerweise mit Web-Scraping verbunden sind - nur auf einer Mikroebene.  Wir entscheiden, welche URL wir benötigen und welche Seite wir holen müssen, und wir laden sie in ein neues Nokogiri-Dokument.  Dann öffnen wir diese Seite und zielen auf einen bestimmten Bereich.

Hier wollte ich nur den Titel der neuesten Episode wissen.  Mit der at_css-Methode und einem CSS-Selektor für h2.post-title konnte ich den Extraktionspunkt gezielt ansteuern.  Mit dieser Methode werden wir dieses einzigartige Element jedoch nur schaben.  Das gibt uns den ganzen Selektor - was die meiste Zeit nicht genau das ist, was wir brauchen.  Daher extrahieren wir nur den inneren Textteil dieses Knotens über die text methode.  Zum Vergleich können Sie die Ausgabe sowohl für die Kopfzeile als auch für den Text unten überprüfen.

Ausgabe

1
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/142/">David Heinemeier Hansson</a></h2>
2
3
This is the title of the latest episode: David Heinemeier Hansson

Obwohl dieses Beispiel sehr begrenzte Anwendungen hat, besitzt es alle Zutaten, alle Schritte, die Sie verstehen müssen.  Ich finde es cool, wie einfach das ist.  Weil es aus diesem Beispiel nicht offensichtlich ist, möchte ich darauf hinweisen, wie mächtig dieses Werkzeug sein kann.  Mal sehen, was wir noch mit einer Nokogiri-Schrift machen können.

Beachtung!

Wenn Sie ein Anfänger sind und sich nicht sicher sind, wie Sie den hierfür benötigten HTML-Code ausrichten sollen, sollten Sie nach einer Online-Suche suchen, um herauszufinden, wie Sie den Inhalt von Websites in Ihrem Browser überprüfen können. Im Grunde genommen machen heutzutage alle gängigen Browser diesen Vorgang wirklich einfach.

In Chrome müssen Sie nur mit der rechten Maustaste auf ein Element auf der Website klicken und die Option zum Überprüfen auswählen.  Dies öffnet ein kleines Fenster am unteren Rand Ihres Browsers, das Ihnen etwas wie eine Röntgenaufnahme des DOM der Website zeigt.  Es hat viele weitere Optionen und ich würde empfehlen, einige Zeit bei Google zu verbringen, um sich weiterzubilden.  Das ist eine weise Zeit!

css

Die css-Methode liefert uns nicht nur ein einzelnes Element der Wahl, sondern jedes Element, das den Suchkriterien auf der Seite entspricht.  Ziemlich ordentlich und unkompliziert!

some_scraper.rb

1
require 'nokogiri'
2
3
require "open-uri"
4
5
url = 'http://betweenscreens.fm/'
6
7
page = Nokogiri::HTML(open(url))
8
9
headers = page.css("h2.post-title")
10
11
headers.each do |header|
12
  puts "This is the raw title of the latest episode: #{header}"
13
end
14
15
headers.each do |header|
16
  puts "This is the title of the latest episode: #{header.text}"
17
end

Output

1
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/142/">David Heinemeier Hansson</a></h2>
2
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/141/">Zach Holman</a></h2>
3
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/140/">Joel Glovier</a></h2>
4
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/139/">João Ferreira</a></h2>
5
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/138/">Corwin Harrell</a></h2>
6
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/137/">Roberto Machado</a></h2>
7
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/136/">James Edward Gray II</a></h2>
8
9
This is the title of the latest episode: David Heinemeier Hansson
10
This is the title of the latest episode: Zach Holman
11
This is the title of the latest episode: Joel Glovier
12
This is the title of the latest episode: João Ferreira
13
This is the title of the latest episode: Corwin Harrell
14
This is the title of the latest episode: Roberto Machado
15
This is the title of the latest episode: James Edward Gray II

Der einzige kleine Unterschied in diesem Beispiel ist, dass ich zuerst die rohen Header iteriere.  Ich habe auch seinen inneren text mit der textmethode extrahiert.  Nokogiri stoppt automatisch am Ende der Seite und versucht nicht, die Paginierung automatisch zu verfolgen.

Nehmen wir an, wir möchten etwas mehr Informationen haben, sagen wir das Datum und den Untertitel für jede Episode.  Wir können einfach das obige Beispiel erweitern.  Es ist trotzdem eine gute Idee, dies Schritt für Schritt zu machen.  Lassen Sie ein kleines Stück arbeiten und fügen Sie auf dem Weg mehr Komplexität hinzu.

some_scraper.rb

1
require 'nokogiri'
2
3
require "open-uri"
4
5
url = 'http://betweenscreens.fm/'
6
7
page = Nokogiri::HTML(open(url))
8
9
articles = page.css("article.index-article")
10
11
articles.each do |article|
12
  header     = article.at_css("h2.post-title")
13
  date       = article.at_css(".post-date")
14
  subtitle   = article.at_css(".topic-list")
15
16
  puts "This is the raw header:    #{header}"
17
  puts "This is the raw date:      #{date}"
18
  puts "This is the raw subtitle:  #{subtitle}\n\n"
19
 
20
  puts "This is the text header:   #{header.text}"
21
  puts "This is the text date:     #{date.text}"
22
  puts "This is the text subtitle: #{subtitle.text}\n\n"
23
end

Ausgabe

1
This is the raw header: <h2 class="post-title"><a href="episodes/142/">David Heinemeier Hansson</a></h2>
2
This is the raw date: <span class="post-date">Oct 18 | 2016</span>
3
This is the raw subtitle: <h3 class="topic-list">Rails community | Tone | Technical disagreements | Community policing | Ungratefulness | No assholes allowed | Basecamp | Open source persona | Aspirations | Guarding motivations | Dealing with audiences | Pressure | Honesty | Diverse opinions | Small talk</h3>
4
5
This is the text header: David Heinemeier Hansson
6
This is the text date: Oct 18 | 2016
7
This is the text subtitle: Rails community | Tone | Technical disagreements | Community policing | Ungratefulness | No assholes allowed | Basecamp | Open source persona | Aspirations | Guarding motivations | Dealing with audiences | Pressure | Honesty | Diverse opinions | Small talk
8
9
This is the raw header: <h2 class="post-title"><a href="episodes/141/">Zach Holman</a></h2>
10
This is the raw date: <span class="post-date">Oct 12 | 2016</span>
11
This is the raw subtitle: <h3 class="topic-list">Getting Fired | Taboo | Transparency | Different Perspectives | Timing | Growth Stages | Employment &amp; Dating | Managers | At-will Employment | Tech Industry | Europe | Low hanging Fruits | Performance Improvement Plans | Meeting Goals | Surprise Firings | Firing Fast | Mistakes | Company Culture | Communication</h3>
12
13
This is the text header: Zach Holman
14
This is the text date: Oct 12 | 2016
15
This is the text subtitle: Getting Fired | Taboo | Transparency | Different Perspectives | Timing | Growth Stages | Employment & Dating | Managers | At-will Employment | Tech Industry | Europe | Low hanging Fruits | Performance Improvement Plans | Meeting Goals | Surprise Firings | Firing Fast | Mistakes | Company Culture | Communication
16
17
This is the raw header: <h2 class="post-title"><a href="episodes/140/">Joel Glovier</a></h2>
18
This is the raw date: <span class="post-date">Oct 10 | 2016</span>
19
This is the raw subtitle: <h3 class="topic-list">Digital Product Design | Product Design @ GitHub | Loving Design | Order &amp; Chaos | Drawing | Web Design | HospitalRun | Diversity | Startup Culture | Improving Lives | CURE International | Ember | Offline First | Hospital Information System | Designers &amp; Open Source</h3>
20
21
This is the text header: Joel Glovier
22
This is the text date: Oct 10 | 2016
23
This is the text subtitle: Digital Product Design | Product Design @ GitHub | Loving Design | Order & Chaos | Drawing | Web Design | HospitalRun | Diversity | Startup Culture | Improving Lives | CURE International | Ember | Offline First | Hospital Information System | Designers & Open Source
24
25
This is the raw header: <h2 class="post-title"><a href="episodes/139/">João Ferreira</a></h2>
26
This is the raw date: <span class="post-date">Aug 26 | 2015</span>
27
This is the raw subtitle: <h3 class="topic-list">Masters @ Work | Subvisual | Deadlines | Design personality | Design problems | Team | Pushing envelopes | Delightful experiences | Perfecting details | Company values</h3>
28
29
This is the text header: João Ferreira
30
This is the text date: Aug 26 | 2015
31
This is the text subtitle: Masters @ Work | Subvisual | Deadlines | Design personality | Design problems | Team | Pushing envelopes | Delightful experiences | Perfecting details | Company values
32
33
This is the raw header: <h2 class="post-title"><a href="episodes/138/">Corwin Harrell</a></h2>
34
This is the raw date: <span class="post-date">Aug 06 | 2015</span>
35
This is the raw subtitle: <h3 class="topic-list">Q&amp;A | 01 | University | Graphic design | Design setup | Sublime | Atom | thoughtbot | Working location | Collaboration &amp; pairing | Vim advocates | Daily routine | Standups | Clients | Coffee walks | Investment Fridays |</h3>
36
37
This is the text header: Corwin Harrell
38
This is the text date: Aug 06 | 2015
39
This is the text subtitle: Q&A | 01 | University | Graphic design | Design setup | Sublime | Atom | thoughtbot | Working location | Collaboration & pairing | Vim advocates | Daily routine | Standups | Clients | Coffee walks | Investment Fridays |
40
41
This is the raw header: <h2 class="post-title"><a href="episodes/137/">Roberto Machado</a></h2>
42
This is the raw date: <span class="post-date">Aug 03 | 2015</span>
43
This is the raw subtitle: <h3 class="topic-list">CEO @ Subvisual | RubyConf Portugal | Creators School | Consultancy | Company role models | Group Buddies | Portuguese startup | Rebranding | Technologies used | JS frameworks | TDD &amp; BDD | Startup mistakes | Culture of learning | Young entrepreneurs</h3>
44
45
This is the text header: Roberto Machado
46
This is the text date: Aug 03 | 2015
47
This is the text subtitle: CEO @ Subvisual | RubyConf Portugal | Creators School | Consultancy | Company role models | Group Buddies | Portuguese startup | Rebranding | Technologies used | JS frameworks | TDD & BDD | Startup mistakes | Culture of learning | Young entrepreneurs
48
49
This is the raw header: <h2 class="post-title"><a href="episodes/136/">James Edward Gray II</a></h2>
50
This is the raw date: <span class="post-date">Jul 30 | 2015</span>
51
This is the raw subtitle: <h3 class="topic-list">Screencasting | Less Code | Reading code | Getting unstuck | Rails’s codebase | CodeNewbie | Small examples | Future plans | PeepCode | Frequency &amp; pricing</h3>
52
53
This is the text header: James Edward Gray II
54
This is the text date: Jul 30 | 2015
55
This is the text subtitle: Screencasting | Less Code | Reading code | Getting unstuck | Rails’s codebase | CodeNewbie | Small examples | Future plans | PeepCode | Frequency & pricing

An diesem Punkt haben wir bereits einige Daten zum Spielen.  Wir können es strukturieren oder schlachten, wie wir es wollen.  Das obige sollte einfach zeigen, was wir auf lesbare Weise haben.  Natürlich können wir tiefer in jeden davon gehen, indem wir reguläre Ausdrücke mit der text methode verwenden.

Wir werden das viel genauer untersuchen, wenn wir das eigentliche Podcast-Problem lösen.  Es wird keine Klasse auf Regexp sein, aber Sie werden mehr davon in Aktion sehen - aber keine Sorgen, nicht so sehr, um Ihr Gehirn zum Bluten zu bringen.

Attribute

Was in diesem Stadium hilfreich sein könnte, ist das Extrahieren des href für die einzelnen Episoden.  Es könnte nicht einfacher sein.

some_scraper.rb

1
require 'nokogiri'
2
3
require "open-uri"
4
5
url = 'http://betweenscreens.fm/'
6
7
page = Nokogiri::HTML(open(url))
8
9
articles = page.css("article.index-article")
10
11
articles.each do |article|
12
  header      = article.at_css("h2.post-title")
13
  date        = article.at_css(".post-date")
14
  subtitle    = article.at_css(".topic-list")
15
  link        = article.at_css("h2.post-title a")
16
  podcast_url = "http://betweenscreens.fm/"
17
18
  puts "This is the raw header:    #{header}"
19
  puts "This is the raw date:      #{date}"
20
  puts "This is the raw subtitle:  #{subtitle}"
21
  puts "This is the raw link:      #{link}\n\n"
22
23
  puts "This is the text header:   #{header.text}"
24
  puts "This is the text date:     #{date.text}"
25
  puts "This is the text subtitle: #{subtitle.text}"
26
  puts "This is the raw link:      #{podcast_url}#{link[:href]}\n\n"
27
end

Die wichtigsten Punkte, auf die hier zu achten ist, sind [:href] und podcast_url.  Wenn Sie [:] markieren, können Sie einfach ein Attribut aus dem Zielselektor extrahieren.  Ich habe etwas weiter abstrahiert, aber Sie können klarer sehen, wie es unten funktioniert.

1
...
2
3
href = article.at_css("h2.post-title a")[:href]
4
5
...

Um eine vollständige und nützliche URL zu erhalten, habe ich die Stammdomäne in einer Variablen gespeichert und die vollständige URL für jede Episode erstellt.

1
...
2
3
podcast_url = "http://betweenscreens.fm/"
4
5
puts "This is the raw link: #{podcast_url}#{link[:href]}\n\n"
6
7
...

Werfen wir einen kurzen Blick auf die Ausgabe:

Ausgabe

1
This is the raw header:   <h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
2
This is the raw date:     <span class="post-date">Oct 25 | 2016</span>
3
This is the raw subtitle: <h3 class="topic-list">Open source | Empathy | Lower barriers | Learning tool | Design contributions | Git website | Branding | GitHub | Neovim | Tmux | Design love | Knowing audiences | Showing work | Dribbble | Progressions | Ideas</h3>
4
This is the raw link:     <a href="episodes/143/">Jason Long</a>
5
6
This is the text header: Jason Long
7
This is the text date:   Oct 25 | 2016
8
This is the text subtitle: Open source | Empathy | Lower barriers | Learning tool | Design contributions | Git website | Branding | GitHub | Neovim | Tmux | Design love | Knowing audiences | Showing work | Dribbble | Progressions | Ideas
9
This is the href:     http://betweenscreens.fm/episodes/143/
10
11
This is the raw header:   <h2 class="post-title"><a href="episodes/142/">David Heinemeier Hansson</a></h2>
12
This is the raw date:     <span class="post-date">Oct 18 | 2016</span>
13
This is the raw subtitle: <h3 class="topic-list">Rails community | Tone | Technical disagreements | Community policing | Ungratefulness | No assholes allowed | Basecamp | Open source persona | Aspirations | Guarding motivations | Dealing with audiences | Pressure | Honesty | Diverse opinions | Small talk</h3>
14
This is the raw link:     <a href="episodes/142/">David Heinemeier Hansson</a>
15
16
This is the text header: David Heinemeier Hansson
17
This is the text date:   Oct 18 | 2016
18
This is the text subtitle: Rails community | Tone | Technical disagreements | Community policing | Ungratefulness | No assholes allowed | Basecamp | Open source persona | Aspirations | Guarding motivations | Dealing with audiences | Pressure | Honesty | Diverse opinions | Small talk
19
This is the href:     http://betweenscreens.fm/episodes/142/
20
21
This is the raw header:   <h2 class="post-title"><a href="episodes/141/">Zach Holman</a></h2>
22
This is the raw date:     <span class="post-date">Oct 12 | 2016</span>
23
This is the raw subtitle: <h3 class="topic-list">Getting Fired | Taboo | Transparency | Different Perspectives | Timing | Growth Stages | Employment &amp; Dating | Managers | At-will Employment | Tech Industry | Europe | Low hanging Fruits | Performance Improvement Plans | Meeting Goals | Surprise Firings | Firing Fast | Mistakes | Company Culture | Communication</h3>
24
This is the raw link:     <a href="episodes/141/">Zach Holman</a>
25
26
This is the text header: Zach Holman
27
This is the text date:   Oct 12 | 2016
28
This is the text subtitle: Getting Fired | Taboo | Transparency | Different Perspectives | Timing | Growth Stages | Employment & Dating | Managers | At-will Employment | Tech Industry | Europe | Low hanging Fruits | Performance Improvement Plans | Meeting Goals | Surprise Firings | Firing Fast | Mistakes | Company Culture | Communication
29
This is the href:     http://betweenscreens.fm/episodes/141/
30
31
This is the raw header:   <h2 class="post-title"><a href="episodes/140/">Joel Glovier</a></h2>
32
This is the raw date:     <span class="post-date">Oct 10 | 2016</span>
33
This is the raw subtitle: <h3 class="topic-list">Digital Product Design | Product Design @ GitHub | Loving Design | Order &amp; Chaos | Drawing | Web Design | HospitalRun | Diversity | Startup Culture | Improving Lives | CURE International | Ember | Offline First | Hospital Information System | Designers &amp; Open Source</h3>
34
This is the raw link:     <a href="episodes/140/">Joel Glovier</a>
35
36
This is the text header: Joel Glovier
37
This is the text date:   Oct 10 | 2016
38
This is the text subtitle: Digital Product Design | Product Design @ GitHub | Loving Design | Order & Chaos | Drawing | Web Design | HospitalRun | Diversity | Startup Culture | Improving Lives | CURE International | Ember | Offline First | Hospital Information System | Designers & Open Source
39
This is the href:     http://betweenscreens.fm/episodes/140/
40
41
This is the raw header:   <h2 class="post-title"><a href="episodes/139/">João Ferreira</a></h2>
42
This is the raw date:     <span class="post-date">Aug 26 | 2015</span>
43
This is the raw subtitle: <h3 class="topic-list">Masters @ Work | Subvisual | Deadlines | Design personality | Design problems | Team | Pushing envelopes | Delightful experiences | Perfecting details | Company values</h3>
44
This is the raw link:     <a href="episodes/139/">João Ferreira</a>
45
46
This is the text header: João Ferreira
47
This is the text date:   Aug 26 | 2015
48
This is the text subtitle: Masters @ Work | Subvisual | Deadlines | Design personality | Design problems | Team | Pushing envelopes | Delightful experiences | Perfecting details | Company values
49
This is the href:     http://betweenscreens.fm/episodes/139/
50
51
This is the raw header:   <h2 class="post-title"><a href="episodes/138/">Corwin Harrell</a></h2>
52
This is the raw date:     <span class="post-date">Aug 06 | 2015</span>
53
This is the raw subtitle: <h3 class="topic-list">Q&amp;A | 01 | University | Graphic design | Design setup | Sublime | Atom | thoughtbot | Working location | Collaboration &amp; pairing | Vim advocates | Daily routine | Standups | Clients | Coffee walks | Investment Fridays |</h3>
54
This is the raw link:     <a href="episodes/138/">Corwin Harrell</a>
55
56
This is the text header: Corwin Harrell
57
This is the text date:   Aug 06 | 2015
58
This is the text subtitle: Q&A | 01 | University | Graphic design | Design setup | Sublime | Atom | thoughtbot | Working location | Collaboration & pairing | Vim advocates | Daily routine | Standups | Clients | Coffee walks | Investment Fridays |
59
This is the href:     http://betweenscreens.fm/episodes/138/
60
61
This is the raw header:   <h2 class="post-title"><a href="episodes/137/">Roberto Machado</a></h2>
62
This is the raw date:     <span class="post-date">Aug 03 | 2015</span>
63
This is the raw subtitle: <h3 class="topic-list">CEO @ Subvisual | RubyConf Portugal | Creators School | Consultancy | Company role models | Group Buddies | Portuguese startup | Rebranding | Technologies used | JS frameworks | TDD &amp; BDD | Startup mistakes | Culture of learning | Young entrepreneurs</h3>
64
This is the raw link:     <a href="episodes/137/">Roberto Machado</a>
65
66
This is the text header: Roberto Machado
67
This is the text date:   Aug 03 | 2015
68
This is the text subtitle: CEO @ Subvisual | RubyConf Portugal | Creators School | Consultancy | Company role models | Group Buddies | Portuguese startup | Rebranding | Technologies used | JS frameworks | TDD & BDD | Startup mistakes | Culture of learning | Young entrepreneurs
69
This is the href:     http://betweenscreens.fm/episodes/137/

Ordentlich, nicht wahr?  Sie können dasselbe tun, um die Klasse [:class] eines Selektors zu extrahieren.

1
require 'nokogiri'
2
3
require "open-uri"
4
5
url = 'http://betweenscreens.fm/'
6
7
page = Nokogiri::HTML(open(url))
8
9
body_classes = page.at_css("body")[:class]

Wenn dieser Knoten mehr als eine Klasse hat, erhalten Sie eine Liste von allen.

Knoten Navigation

  • parent
  • children
  • previous_sibling
  • next_sibling

Wir sind es gewohnt mit Baumstrukturen in CSS oder sogar jQuery umzugehen.  Es wäre ein Schmerz, wenn Nokogiri keine handliche API anbieten würde, um sich in solchen Bäumen zu bewegen.

some_scraper.rb

1
require 'nokogiri'
2
3
require "open-uri"
4
5
url = 'http://betweenscreens.fm/'
6
7
page = Nokogiri::HTML(open(url))
8
9
header = page.at_css("h2.post-title")
10
header_children = page.at_css("h2.post-title").children
11
header_parent = page.at_css("h2.post-title").parent
12
header_prev_sibling = page.at_css("h2.post-title").previous_sibling
13
14
puts "#{header}\n\n"
15
puts "#{header_children}\n\n"
16
puts "#{header_parent}\n\n"
17
puts "#{header_prev_sibling}\n\n"

Ausgabe

1
#header

2
<h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
3
4
#header_children

5
<a href="episodes/143/">Jason Long</a>
6
7
#header_parent

8
<article class="index-article">
9
  <span class="post-date">Oct 25 | 2016</span><h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
10
    <h3 class="topic-list">Open source | Empathy | Lower barriers | Learning tool | Design contributions | Git website | Branding | GitHub | Neovim | Tmux | Design love | Knowing audiences | Showing work | Dribbble | Progressions | Ideas</h3>
11
    <div class="soundcloud-player-small">  
12
    </div>
13
</article>
14
15
#header_previous_sibling

16
<span class="post-date">Oct 25 | 2016</span>

Wie Sie selbst sehen können, ist dies ein ziemlich mächtiger Kram - besonders wenn Sie sehen, was .parent in einem Zug sammeln konnte. Anstatt einen Haufen Knoten von Hand zu definieren, könnten Sie sie im Großhandel sammeln.

Sie können sie sogar für umfangreichere Traversierungen verketten.  Sie können das natürlich so kompliziert nehmen, wie Sie möchten, aber ich würde Sie davor warnen, die Dinge einfach zu halten.  Es kann schnell ein wenig unhandlich und schwer zu verstehen sein. Denken Sie daran: "Halten Sie es einfach, dumm!"

1
...
2
3
header_parent_parent = page.at_css("h2.post-title").parent.parent
4
header_prev_sibling_parent_children = page.at_css("h2.post-title").previous_sibling.parent.children
5
6
...

some_scraper.rb

1
require 'nokogiri'
2
3
require "open-uri"
4
5
url = 'http://betweenscreens.fm/'
6
7
page = Nokogiri::HTML(open(url))
8
9
header = page.at_css("h2.post-title")
10
header_prev_sibling_children = page.at_css("h2.post-title").previous_sibling.children
11
header_parent_parent = page.at_css("h2.post-title").parent.parent
12
header_prev_sibling_parent = page.at_css("h2.post-title").previous_sibling.parent
13
header_prev_sibling_parent_children = page.at_css("h2.post-title").previous_sibling.parent.children
14
15
puts "#{header}\n\n"
16
puts "#{header_prev_sibling_children}\n\n"
17
puts "#{header_parent_parent}\n\n"
18
puts "#{header_prev_sibling_parent}\n\n"
19
puts "#{header_prev_sibling_parent_children}\n\n"

Ausgabe

1
#header

2
<h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
3
4
#header_previous_sibling_children

5
Oct 25 | 2016
6
7
#header_parent_parent

8
<li>
9
  <article class="index-article">
10
  <span class="post-date">Oct 25 | 2016</span><h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
11
    <h3 class="topic-list">Open source | Empathy | Lower barriers | Learning tool | Design contributions | Git website | Branding | GitHub | Neovim | Tmux | Design love | Knowing audiences | Showing work | Dribbble | Progressions | Ideas</h3>
12
    <div class="soundcloud-player-small">  
13
    </div>
14
  </article>
15
</li>
16
17
#header_previous_sibling_parent

18
<article class="index-article">
19
  <span class="post-date">Oct 25 | 2016</span><h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
20
    <h3 class="topic-list">Open source | Empathy | Lower barriers | Learning tool | Design contributions | Git website | Branding | GitHub | Neovim | Tmux | Design love | Knowing audiences | Showing work | Dribbble | Progressions | Ideas</h3>
21
    <div class="soundcloud-player-small">  
22
    </div>
23
</article>
24
25
#header_previous_sibling_parent_children

26
  <span class="post-date">Oct 25 | 2016</span><h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
27
    <h3 class="topic-list">Open source | Empathy | Lower barriers | Learning tool | Design contributions | Git website | Branding | GitHub | Neovim | Tmux | Design love | Knowing audiences | Showing work | Dribbble | Progressions | Ideas</h3>
28
    <div class="soundcloud-player-small">  
29
    </div>

Abschließende Gedanken

Nokogiri ist keine große Bibliothek, aber es hat viel zu bieten.  Ich empfehle Ihnen, mit dem bisher Gelernten zu spielen und Ihr Wissen durch seine Dokumentation zu erweitern, wenn Sie eine Wand treffen.  Aber mach dich nicht in Schwierigkeiten!

Dieses kleine Intro sollte Sie auf Ihrem Weg zu verstehen, was Sie tun können und wie es funktioniert.  Ich hoffe, du wirst es ein bisschen mehr selbst erkunden und ein bisschen Spaß damit haben.  Wie Sie selbst herausfinden werden, ist es ein reichhaltiges Tool, das weitergibt.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.