Advertisement
  1. Code
  2. Ruby

Erstellen Ihres ersten Web Scraper, Teil 2

Scroll to top
Read Time: 22 min

German (Deutsch) translation by Katharina Grigorovich-Nevolina (you can also view the original English article)

In diesem Tutorial erfahren Sie, wie Sie mit Mechanize auf Links klicken, Formulare ausfüllen und Dateien hochladen können. Außerdem erfahren Sie, wie Sie Seitenobjekte mechanisieren und eine Google-Suche automatisieren und ihre Ergebnisse speichern können.

Themen

  • Einzelseite vs. Paginierung
  • Mechanisieren
  • Agent
  • Seite
  • Nokogiri-Methoden
  • Links
  • Klicken
  • Formen

Einzelseite vs. Paginierung

Bisher haben wir einige Zeit damit verbracht, herauszufinden, wie wir mit Nokogiri den Bildschirm einer einzelnen Seite abkratzen können. Dies war eine gute Grundlage, um einen Schritt vorwärts zu gehen und zu lernen, wie Inhalte von mehreren Seiten extrahiert werden.

Schließlich besteht das Problem, das wir lösen möchten, darin, den Inhalt aus mehr als 140 Episoden abzurufen. Dies ist mehr Inhalt, als für eine einzelne Webseite angemessen ist. Wir müssen mit Paginierung arbeiten und herausfinden, wie wir den Inhalten im Kaninchenbau folgen können.

Hier hört Nokogiri auf und ein weiteres nützliches Juwel namens Mechanize kommt ins Spiel.

Mechanisieren

Mechanisieren ist ein weiteres leistungsstarkes Werkzeug, das viele Extras zu bieten hat. Es ermöglicht Ihnen im Wesentlichen, Interaktionen mit Websites zu automatisieren, von denen Sie Inhalte extrahieren müssen. In diesem Sinne erinnert es mich ein wenig an einige Funktionen, die Sie vielleicht aus Tests mit Capybara kennen.

Verstehen Sie mich nicht falsch, das Spielen mit Nokogiri auf einer einzigen Seite ist an sich schon großartig, aber für scharfere Datenextraktionsjobs benötigen wir etwas mehr Leistung. Wir können im Wesentlichen so viele Seiten durchsuchen, wie wir benötigen, und mit ihren Elementen interagieren - menschliches Verhalten imitieren und automatisieren. Ziemlich mächtiges Zeug!

Mit diesem Juwel können Sie Links folgen, Formularfelder ausfüllen und diese Daten übermitteln - selbst der Umgang mit Cookies steht auf dem Tisch. Das heißt, Sie können auch die Anmeldung von Benutzern in privaten Sitzungen imitieren und Inhalte von einer Site abrufen, auf die nur Sie Zugriff haben.

Sie füllen das Login mit Ihren Anmeldeinformationen aus und teilen Mechanize mit, wie sie vorgehen sollen. Da Sie auf Links klicken und Formulare senden können, können Sie mit diesem Werkzeug nur sehr wenig tun. Es hat eine enge Beziehung zu Nokogiri und hängt auch davon ab. Aaron Patterson ist wieder einer der Autoren dieses schönen Juwel.

Instanziieren eines Mechanize Agent

Bevor wir mit der Mechanisierung beginnen können, müssen wir einen Mechanisierungsagenten instanziieren.

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new

Dieser agent wird verwendet, um eine Seite abzurufen, ähnlich wie bei Nokogiri.

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
podcast_url = "http://betweenscreens.fm/"
6
7
page = agent.get(podcast_url)

Was hier passiert ist, dass der Mechanize-Agent die Podcast-Seite und ihre Cookies erhalten hat.

Seiteninhaltextrahieren

Wir haben jetzt eine Seite, die zur Extraktion bereit ist. Bevor wir dies tun, empfehle ich, dass wir mit der inspect-Methode einen Blick unter die Haube werfen.

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
podcast_url = "http://betweenscreens.fm/"
6
7
page = agent.get(podcast_url)
8
9
puts page.inspect

Die Ausgabe ist ziemlich substanziell. Überzeugen Sie sich selbst, woraus ein Mechanize::Page-Objekt besteht. Hier sehen Sie alle Attribute für diese Seite.

Für mich ist das ein sehr praktisches Objekt, um die Daten, die Sie extrahieren möchten, aufzuteilen.

Ausgabe

1
#<Mechanize::Page

2
 {url #http://betweenscreens.fm/>}

3
 {meta_refresh}
4
 {title "Between | Screens "}
5
 {iframes
6
  #<Mechanize::Page::Frame

7
   nil
8
   "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/290328784&color=ff0000&auto...>

9
  #<Mechanize::Page::Frame

10
   nil

11
   "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/290126141&color=ff0000&auto...>
12
  #<Mechanize::Page::Frame

13
   nil
14
   "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/289018386&color=ff0000&auto...>

15
  #<Mechanize::Page::Frame

16
   nil

17
   "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/287425105&color=ff0000&auto...>
18
  #<Mechanize::Page::Frame

19
   nil
20
   "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/287105342&color=ff0000&auto...>

21
  #<Mechanize::Page::Frame

22
   nil

23
   "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/221003494&color=ff0000&auto...>
24
  #<Mechanize::Page::Frame

25
   nil
26
   "">https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/218101809&color=ff0000&auto...}
27
 {frames}
28
 {links
29
  #<Mechanize::Page::Link "Logo cube" "/">

30
  #https://github.com/vis-kid/betweenscreens">

31
  #<Mechanize::Page::Link "about" "pages/about/">

32
  #<Mechanize::Page::Link "design" "design/">

33
  #<Mechanize::Page::Link "code" "code/">

34
  #<Mechanize::Page::Link "Randy J. Hunt" "episodes/144/">

35
  #<Mechanize::Page::Link "Jason Long" "episodes/143/">

36
  #<Mechanize::Page::Link "David Heinemeier Hansson" "episodes/142/">

37
  #<Mechanize::Page::Link "Zach Holman" "episodes/141/">

38
  #<Mechanize::Page::Link "Joel Glovier" "episodes/140/">

39
  #<Mechanize::Page::Link "João Ferreira" "episodes/139/">

40
  #<Mechanize::Page::Link "Corwin Harrell" "episodes/138/">

41
  #<Mechanize::Page::Link "Older Stuff »" "page/2/">

42
  #<Mechanize::Page::Link "Exercise" "/tags/exercise/">

43
  #<Mechanize::Page::Link "Company benefits" "/tags/company-benefits/">

44
  #<Mechanize::Page::Link "Tmux" "/tags/tmux/">

45
  #<Mechanize::Page::Link "FileTask" "/tags/filetask/">

46
  #<Mechanize::Page::Link "Decision making" "/tags/decision-making/">

47
  #<Mechanize::Page::Link "Favorite feature" "/tags/favorite-feature/">

48
  #<Mechanize::Page::Link "Working out" "/tags/working-out/">

49
  #<Mechanize::Page::Link "Scott Savarie" "/tags/scott-savarie/">

50
  #<Mechanize::Page::Link "Titles" "/tags/titles/">

51
  #<Mechanize::Page::Link "Erik Spiekermann" "/tags/erik-spiekermann/">

52
  #<Mechanize::Page::Link "Newbie mistakes" "/tags/newbie-mistakes/">

53
  #<Mechanize::Page::Link "Playbook" "/tags/playbook/">

54
  #<Mechanize::Page::Link "Delegation" "/tags/delegation/">

55
  #<Mechanize::Page::Link "Heat maps" "/tags/heat-maps/">

56
  #<Mechanize::Page::Link "Europe" "/tags/europe/">

57
  #<Mechanize::Page::Link "Sizing type" "/tags/sizing-type/">

58
  #<Mechanize::Page::Link "Focus" "/tags/focus/">

59
  #<Mechanize::Page::Link "Virtual assistants" "/tags/virtual-assistants/">

60
  #<Mechanize::Page::Link "Writing" "/tags/writing/">

61
  #<Mechanize::Page::Link "Hacking" "/tags/hacking/">

62
  #<Mechanize::Page::Link "Joel Glovier" "/tags/joel-glovier/">

63
  #<Mechanize::Page::Link "Corwin Harrell" "/tags/corwin-harrell/">

64
  #<Mechanize::Page::Link "Mario C. Delgado" "/tags/mario-c-delgado/">

65
  #<Mechanize::Page::Link "Tom Dale" "/tags/tom-dale/">

66
  #<Mechanize::Page::Link "Obie Fernandez" "/tags/obie-fernandez/">

67
  #<Mechanize::Page::Link "Chad Pytel" "/tags/chad-pytel/">

68
  #<Mechanize::Page::Link "Zach Holman" "/tags/zach-holman/">

69
  #<Mechanize::Page::Link "Max Luster" "/tags/max-luster/">

70
  #<Mechanize::Page::Link "Kyle Fiedler" "/tags/kyle-fiedler/">

71
  #<Mechanize::Page::Link "Roberto Machado" "/tags/roberto-machado/">}

72
 {forms}>

Wenn Sie sich die HTML-Seite selbst ansehen möchten, können Sie den body oder die content-Methoden mit Tags versehen.

some_scraper.rb

1
...
2
3
print page.body
4
5
...

Ausgabe

1
<!doctype html>
2
3
<html>
4
  <head>
5
    <meta charset="utf-8" />
6
    <meta http-equiv='X-UA-Compatible' content='IE=edge;chrome=1' />
7
    <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
8
    <meta name="viewport" content="initial-scale=1">
9
    <title>Between | Screens </title>
10
    <link rel="alternate" type="application/atom+xml" title="Atom Feed" href="/feed.xml" />
11
    <link href="stylesheets/all-11b45acc.css" rel="stylesheet" />
12
    <script src="javascripts/all-4c20da82.js"></script>
13
  </head>
14
15
  <body>
16
    <header>
17
      <div id="logo">
18
        <a href="/"><img src="images/Between_Screens_Logo_Cube_Up-539d6997.svg" alt="Logo cube" /></a>
19
      </div>
20
      <nav class="navigation">
21
        <ul class="nav-list"> 
22
fork">https://github.com/vis-kid/betweenscreens">fork!
23
          <li><a href="pages/about/">about</a></li>
24
          <li><a href="design/">design</a></li>
25
          <li><a href="code/">code</a></li>
26
        </ul>
27
      </nav>
28
    </header>
29
30
    <div id="main" role="main">
31
      <div class='posts'>
32
        <ul>
33
          <li>
34
            <article class="index-article">
35
              <span class='post-date'>Oct 27 | 2016</span><h2 class='post-title'><a href="episodes/144/">Randy J. Hunt</a></h2>
36
              <h3 class='topic-list'>Organizing teams | Diversity | Desires | Pizza rule | Effective over clever | Novel solutions | Straightforwardness | Research | Coffeeshop test | Small changes | Reducing errors | Granular diffs</h3>
37
              <div class='soundcloud-player-small'>
38
                <iframe width="100%"
39
                  height="166"
40
                  scrolling="no"
41
                  frameborder="no"
42
                  src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/290328784&color=ff0000&...>

43
              </div>

44
            </article>

45
          </li>

46


47
          <li>

48
            <article class="index-article">
49
              <span class='post-date'>Oct 25 | 2016</span><h2 class='post-title'><a href="episodes/143/">Jason Long</a></h2>
50
              <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>
51
              <div class='soundcloud-player-small'>
52
                <iframe width="100%"
53
                height="166"
54
                scrolling="no"
55
                frameborder="no"
56
                src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/290126141&color=ff0000&...>

57
              </div>

58
            </article>

59
          </li>

60


61
          <li>

62
            <article class="index-article">
63
              <span class='post-date'>Oct 18 | 2016</span><h2 class='post-title'><a href="episodes/142/">David Heinemeier Hansson</a></h2>
64
              <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>
65
              <div class='soundcloud-player-small'>
66
                <iframe width="100%"
67
                height="166"
68
                scrolling="no"
69
                frameborder="no"
70
                src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/289018386&color=ff0000&...>

71
              </div>

72
            </article>

73
          </li>

74


75
          <li>

76
            <article class="index-article">
77
              <span class='post-date'>Oct 12 | 2016</span><h2 class='post-title'><a href="episodes/141/">Zach Holman</a></h2>
78
              <h3 class='topic-list'>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</h3>
79
              <div class='soundcloud-player-small'>  
80
                <iframe width="100%"
81
                  height="166"
82
                  scrolling="no"
83
                  frameborder="no"
84
                  src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/287425105&color=ff0000&...>

85
              </div>

86
            </article>

87
          </li>

88


89
          <li>

90
            <article class="index-article">
91
              <span class='post-date'>Oct 10 | 2016</span><h2 class='post-title'><a href="episodes/140/">Joel Glovier</a></h2>
92
              <h3 class='topic-list'>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</h3>
93
              <div class='soundcloud-player-small'>
94
                <iframe width="100%"
95
                  height="166"
96
                  scrolling="no"
97
                  frameborder="no"
98
                  src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/287105342&color=ff0000&...>

99
              </div>

100
            </article>

101
          </li>

102


103
          <li>

104
            <article class="index-article">
105
              <span class='post-date'>Aug 26 | 2015</span><h2 class='post-title'><a href="episodes/139/">João Ferreira</a></h2>
106
              <h3 class='topic-list'>Masters @ Work | Subvisual | Deadlines | Design personality | Design problems | Team | Pushing envelopes | Delightful experiences | Perfecting details | Company values</h3>
107
              <div class='soundcloud-player-small'>
108
                <iframe width="100%"
109
                height="166"
110
                scrolling="no"
111
                frameborder="no"
112
                src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/221003494&color=ff0000&...>

113
              </div>

114
            </article>

115
          </li>

116


117
          <li>

118
            <article class="index-article">
119
              <span class='post-date'>Aug 06 | 2015</span><h2 class='post-title'><a href="episodes/138/">Corwin Harrell</a></h2>
120
              <h3 class='topic-list'>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 |</h3>
121
              <div class='soundcloud-player-small'>
122
                <iframe width="100%"
123
                height="166"
124
                scrolling="no"
125
                frameborder="no"
126
                src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/218101809&color=ff0000&...>

127
              </div>

128
            </article>

129
          </li>

130
        </ul>

131
      </div>

132


133
      <section>

134
        <div class='pagination-link'><a href="page/2/">Older Stuff »</a></div>
135
      </section>
136
    </div>
137
138
    <footer>
139
      <div class='footer-tags'>
140
        <h3>Random Tags</h3>
141
        <ul class='random-tag-list'>
142
          <li><a href="/tags/exercise/">Exercise</a></li>
143
          <li><a href="/tags/company-benefits/">Company benefits</a></li>
144
          <li><a href="/tags/tmux/">Tmux</a></li>
145
          <li><a href="/tags/filetask/">FileTask</a></li>
146
          <li><a href="/tags/decision-making/">Decision making</a></li>
147
          <li><a href="/tags/favorite-feature/">Favorite feature</a></li>
148
          <li><a href="/tags/working-out/">Working out</a></li>
149
          <li><a href="/tags/scott-savarie/">Scott Savarie</a></li>
150
          <li><a href="/tags/titles/">Titles</a></li>
151
          <li><a href="/tags/erik-spiekermann/">Erik Spiekermann</a></li>
152
          <li><a href="/tags/newbie-mistakes/">Newbie mistakes</a></li>
153
          <li><a href="/tags/playbook/">Playbook</a></li>
154
          <li><a href="/tags/delegation/">Delegation</a></li>
155
          <li><a href="/tags/heat-maps/">Heat maps</a></li>
156
          <li><a href="/tags/europe/">Europe</a></li>
157
          <li><a href="/tags/sizing-type/">Sizing type</a></li>
158
          <li><a href="/tags/focus/">Focus</a></li>
159
          <li><a href="/tags/virtual-assistants/">Virtual assistants</a></li>
160
          <li><a href="/tags/writing/">Writing</a></li>
161
          <li><a href="/tags/hacking/">Hacking</a></li>
162
        </ul>
163
      </div>
164
165
      <div class='recent-posts'>
166
        <h3>Random Interviewees</h3>
167
        <ul>
168
          <li><a href="/tags/joel-glovier/">Joel Glovier</a></li>
169
          <li><a href="/tags/corwin-harrell/">Corwin Harrell</a></li>
170
          <li><a href="/tags/mario-c-delgado/">Mario C. Delgado</a></li>
171
          <li><a href="/tags/tom-dale/">Tom Dale</a></li>
172
          <li><a href="/tags/obie-fernandez/">Obie Fernandez</a></li>
173
          <li><a href="/tags/chad-pytel/">Chad Pytel</a></li>
174
          <li><a href="/tags/zach-holman/">Zach Holman</a></li>
175
          <li><a href="/tags/max-luster/">Max Luster</a></li>
176
          <li><a href="/tags/kyle-fiedler/">Kyle Fiedler</a></li>
177
          <li><a href="/tags/roberto-machado/">Roberto Machado</a></li>
178
        </ul>
179
      </div>
180
    </footer>
181
  </body>
182
</html>

Da dieser Podcast nur eine geringe Anzahl verschiedener Elemente auf der Seite enthält, finden Sie hier die Mechanize::Page, die von github.com zurückgegeben wird. Es gibt eine größere Auswahl an Inhalten. Ich denke, das ist wichtig, um ein Gefühl dafür zu bekommen.

Ausgabe von github.com

1
#<Mechanize::Page

2
 {url #https://github.com/>}

3
 {meta_refresh}
4
 {title "How people build software · GitHub"}
5
 {iframes}
6
 {frames}
7
 {links
8
  #<Mechanize::Page::Link "Skip to content" "#start-of-content">

9
  #https://github.com/">

10
  #<Mechanize::Page::Link "\n          Personal\n" "/personal">

11
  #<Mechanize::Page::Link "\n          Open source\n" "/open-source">

12
  #<Mechanize::Page::Link "\n          Business\n" "/business">

13
  #<Mechanize::Page::Link "\n          Explore\n" "/explore">

14
  #<Mechanize::Page::Link "Sign up" "/join?source=header-home">

15
  #<Mechanize::Page::Link "Sign in" "/login">

16
  #<Mechanize::Page::Link "Pricing" "/pricing">

17
  #<Mechanize::Page::Link "Blog" "/blog">

18
  #https://help.github.com">

19
  #https://github.com/search">

20
  #https://help.github.com/terms">

21
  #https://help.github.com/privacy">

22
  #<Mechanize::Page::Link "Sign up for GitHub" "/join?source=button-home">

23
  #<Mechanize::Page::Link

24
   "\n      \n        \n      \n      \n        A whole new Universe\n        \n          Learn about the exciting features and announcements revealed at this year's GitHub Universe conference.\n        \n      \n    "
25
   "/universe-2016">
26
  #<Mechanize::Page::Link "Individuals " "/personal">

27
  #<Mechanize::Page::Link "Communities " "/open-source">

28
  #<Mechanize::Page::Link "Businesses " "/business">

29
  #<Mechanize::Page::Link "NASA" "//github.com/nasa">

30
  #<Mechanize::Page::Link "Sign up for GitHub" "/join?source=button-home">

31
  #https://github.com/contact">

32
  #https://developer.github.com">

33
  #https://training.github.com">

34
  #https://shop.github.com">

35
  #https://github.com/blog">

36
  #https://github.com/about">

37
  #https://github.com">

38
  #https://github.com/site/terms">

39
  #https://github.com/site/privacy">

40
  #https://github.com/security">

41
  #https://status.github.com/">

42
  #https://help.github.com">

43
  #<Mechanize::Page::Link "Reload" "">

44
  #<Mechanize::Page::Link "Reload" "">}

45
 {forms
46
  #<Mechanize::Form

47
   {name nil}
48
   {method "GET"}
49
   {action "/search"}
50
   {fields
51
    [hidden:0x3feb90f8297c type: hidden name: utf8 value: ✓]
52
    [text:0x3feb90f827d8 type: text name: q value: ]}
53
   {radiobuttons}
54
   {checkboxes}
55
   {file_uploads}
56
   {buttons}>
57
  #<Mechanize::Form

58
   {name nil}
59
   {method "POST"}
60
   {action "/join"}
61
   {fields
62
    [hidden:0x3feb90f7be38 type: hidden name: utf8 value: ✓]
63
    [hidden:0x3feb90f7bbb8 type: hidden name: authenticity_token value: vjRATKj7smXreq6Lt02r+MzW+ewWoi+fRzQXPedFAlOZgwzxQ0dZnChirhDfd7vyWZZZBO+ZFydLNedjIEDsrQ==]
64
    [text:0x3feb90f7b9d8 type: text name: user[login] value: ]
65
    [text:0x3feb90f7b7f8 type: text name: user[email] value: ]
66
    [field:0x3feb90f7b654 type: password name: user[password] value: ]
67
    [hidden:0x3feb90f7b474 type: hidden name: source value: form-home]}
68
   {radiobuttons}
69
   {checkboxes}
70
   {file_uploads}
71
   {buttons [button:0x3feb90f7a038 type: submit name:  value: ]}>}>

Zurück zum Podcast können Sie sich auch Dinge wie Codierungen, den HTTP-Antwortcode, den URI oder die Antwortheader ansehen.

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
podcast_url = "http://betweenscreens.fm/"
6
7
page = agent.get(podcast_url)
8
9
puts 'Encodings'
10
puts page.encodings
11
puts 'Repsonse Headers'
12
puts page.response
13
puts 'HTTP response code'
14
puts page.code
15
puts 'URI'
16
puts page.uri

Ausgabe

1
Encodings
2
EUC-JP
3
utf-8
4
utf-8
5
6
Repsonse Headers
7
{"server"=>"GitHub.com", "date"=>"Sat, 29 Oct 2016 17:56:00 GMT", "content-type"=>"text/html; charset=utf-8", "transfer-encoding"=>"chunked", "last-modified"=>"Fri, 28 Oct 2016 01:48:56 GMT", "access-control-allow-origin"=>"*", "expires"=>"Sat, 29 Oct 2016 18:06:00 GMT", "cache-control"=>"max-age=600", "content-encoding"=>"gzip", "x-github-request-id"=>"501C936D:C723:1631523C:5814E2B0"}
8
9
HTTP response code
10
200
11
12
URI
13
http://betweenscreens.fm/

Es gibt viel mehr Zeug, wenn Sie tiefer graben möchten. Ich werde es dabei belassen.

Nokogiri-Methoden

  • at
  • search

Mechanize verwendet Nokogiri, um Daten von Seiten zu kratzen. Sie können das, was Sie im ersten Artikel über Nokogiri gelernt haben, anwenden und es auch auf Mechanize-Seiten verwenden. Das bedeutet, dass Sie im Allgemeinen Mechanize verwenden, um durch Seiten und Nokogiri-Methoden für Ihre Scraping-Anforderungen zu navigieren.

Wenn Sie beispielsweise ein einzelnes Objekt suchen möchten, können Sie at verwenden, während die search alle Objekte zurückgibt, die mit einem Selektor auf einer bestimmten Seite übereinstimmen. Um dies neu zu formulieren, funktionieren diese Methoden sowohl für Nokogiri-Dokumentobjekte als auch für Seitenobjekte mechanisieren.

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
podcast_url = "http://betweenscreens.fm/"
6
7
page = agent.get(podcast_url)
8
9
first_title = page.at('h2.post-title')
10
11
all_titles = page.search('h2.post-title')
12
13
all_titles.each do |title|
14
  puts title
15
end
16
17
puts " * "*33
18
19
puts first_title

Ausgabe

1
<h2 class="post-title"><a href="episodes/144/">Randy J. Hunt</a></h2>
2
<h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
3
<h2 class="post-title"><a href="episodes/142/">David Heinemeier Hansson</a></h2>
4
<h2 class="post-title"><a href="episodes/141/">Zach Holman</a></h2>
5
<h2 class="post-title"><a href="episodes/140/">Joel Glovier</a></h2>
6
<h2 class="post-title"><a href="episodes/139/">João Ferreira</a></h2>
7
<h2 class="post-title"><a href="episodes/138/">Corwin Harrell</a></h2>
8
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 
9
<h2 class="post-title"><a href="episodes/144/">Randy J. Hunt</a></h2>

Links

  • links
  • link_with
  • links_with

Wir können auch die gesamte Site nach unseren Wünschen navigieren. Der wahrscheinlich wichtigste Teil von Mechanize ist die Fähigkeit, mit Links spielen zu können. Ansonsten könnte man so ziemlich alleine bei Nokogiri bleiben. Werfen wir einen Blick darauf, was wir zurückerhalten, wenn wir eine Seite nach ihren Links fragen.

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
podcast_url = "http://betweenscreens.fm/"
6
7
page = agent.get(podcast_url)
8
9
puts "#{page.links}"

Ausgabe

1
[#<Mechanize::Page::Link "Logo cube" "/">

2
, #https://github.com/vis-kid/betweenscreens">

3
, #<Mechanize::Page::Link "about" "pages/about/">

4
, #<Mechanize::Page::Link "design" "design/">

5
, #<Mechanize::Page::Link "code" "code/">

6
, #<Mechanize::Page::Link "Randy J. Hunt" "episodes/144/">

7
, #<Mechanize::Page::Link "Jason Long" "episodes/143/">

8
, #<Mechanize::Page::Link "David Heinemeier Hansson" "episodes/142/">

9
, #<Mechanize::Page::Link "Zach Holman" "episodes/141/">

10
, #<Mechanize::Page::Link "Joel Glovier" "episodes/140/">

11
, #<Mechanize::Page::Link "João Ferreira" "episodes/139/">

12
, #<Mechanize::Page::Link "Corwin Harrell" "episodes/138/">

13
, #<Mechanize::Page::Link "Older Stuff »" "page/2/">

14
, #<Mechanize::Page::Link "Exercise" "/tags/exercise/">

15
, #<Mechanize::Page::Link "Company benefits" "/tags/company-benefits/">

16
, #<Mechanize::Page::Link "Tmux" "/tags/tmux/">

17
, #<Mechanize::Page::Link "FileTask" "/tags/filetask/">

18
, #<Mechanize::Page::Link "Decision making" "/tags/decision-making/">

19
, #<Mechanize::Page::Link "Favorite feature" "/tags/favorite-feature/">

20
, #<Mechanize::Page::Link "Working out" "/tags/working-out/">

21
, #<Mechanize::Page::Link "Scott Savarie" "/tags/scott-savarie/">

22
, #<Mechanize::Page::Link "Titles" "/tags/titles/">

23
, #<Mechanize::Page::Link "Erik Spiekermann" "/tags/erik-spiekermann/">

24
, #<Mechanize::Page::Link "Newbie mistakes" "/tags/newbie-mistakes/">

25
, #<Mechanize::Page::Link "Playbook" "/tags/playbook/">

26
, #<Mechanize::Page::Link "Delegation" "/tags/delegation/">

27
, #<Mechanize::Page::Link "Heat maps" "/tags/heat-maps/">

28
, #<Mechanize::Page::Link "Europe" "/tags/europe/">

29
, #<Mechanize::Page::Link "Sizing type" "/tags/sizing-type/">

30
, #<Mechanize::Page::Link "Focus" "/tags/focus/">

31
, #<Mechanize::Page::Link "Virtual assistants" "/tags/virtual-assistants/">

32
, #<Mechanize::Page::Link "Writing" "/tags/writing/">

33
, #<Mechanize::Page::Link "Hacking" "/tags/hacking/">

34
, #<Mechanize::Page::Link "Joel Glovier" "/tags/joel-glovier/">

35
, #<Mechanize::Page::Link "Corwin Harrell" "/tags/corwin-harrell/">

36
, #<Mechanize::Page::Link "Mario C. Delgado" "/tags/mario-c-delgado/">

37
, #<Mechanize::Page::Link "Tom Dale" "/tags/tom-dale/">

38
, #<Mechanize::Page::Link "Obie Fernandez" "/tags/obie-fernandez/">

39
, #<Mechanize::Page::Link "Chad Pytel" "/tags/chad-pytel/">

40
, #<Mechanize::Page::Link "Zach Holman" "/tags/zach-holman/">

41
, #<Mechanize::Page::Link "Max Luster" "/tags/max-luster/">

42
, #<Mechanize::Page::Link "Kyle Fiedler" "/tags/kyle-fiedler/">

43
, #<Mechanize::Page::Link "Roberto Machado" "/tags/roberto-machado/">

44
]

Holy Moly, lass uns das zusammenfassen. Da wir Mechanize nicht angewiesen haben, sich anderswo umzusehen, haben wir nur von dieser ersten Seite an eine Reihe von Links erhalten. Mechanize geht diese Seite in absteigender Reihenfolge durch und gibt Ihnen diese Liste mit Links von oben nach unten zurück. Ich habe ein kleines Bild mit grünen Zeigern auf die verschiedenen Links erstellt, die Sie in der Ausgabe sehen können.

Das zeigt Ihnen übrigens bereits das Endergebnis der Neugestaltung für meinen Podcast. Ich denke, diese Version ist zu Demonstrationszwecken etwas besser. Sie erhalten auch einen Einblick, wie das Endergebnis aussieht und warum ich meine alte Sinatra-Site abkratzen musste.

Bildschirmfoto

Podcast LinksPodcast LinksPodcast Links

Wie immer können wir auch nur den Text daraus extrahieren.

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
podcast_url = "http://betweenscreens.fm/"
6
7
page = agent.get(podcast_url)
8
9
page.links.each do |link|
10
  puts link.text
11
end

Ausgabe

1
Logo cube
2
fork!
3
about
4
design
5
code
6
Randy J. Hunt
7
Jason Long
8
David Heinemeier Hansson
9
Zach Holman
10
Joel Glovier
11
João Ferreira
12
Corwin Harrell
13
Older Stuff »
14
Exercise
15
Company benefits
16
Tmux
17
FileTask
18
Decision making
19
Favorite feature
20
Working out
21
Scott Savarie
22
Titles
23
Erik Spiekermann
24
Newbie mistakes
25
Playbook
26
Delegation
27
Heat maps
28
Europe
29
Sizing type

30
Focus
31
Virtual assistants
32
Writing
33
Hacking
34
Joel Glovier
35
Corwin Harrell
36
Mario C. Delgado
37
Tom Dale
38
Obie Fernandez
39
Chad Pytel
40
Zach Holman
41
Max Luster
42
Kyle Fiedler
43
Roberto Machado

Es kann sehr nützlich oder einfach mühsam sein, all diese Links in großen Mengen zu erhalten. Zum Glück haben wir ein paar Werkzeugs, mit denen wir genau das einstellen können, was wir brauchen.

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
podcast_url = "http://betweenscreens.fm/"
6
7
page = agent.get(podcast_url)
8
9
focus_link = agent.page.links.find { |link| link.text == 'Focus' }
10
11
puts focus_link

Ausgabe

1
Focus

Boom! Jetzt kommen wir voran! Wir können solche spezifischen Links vergrößern. Wir können Links, die bestimmten Kriterien entsprechen - wie zum Beispiel den Text - mit einer schöneren API wie links_with oder link_with ansprechen. Wenn wir mehrere Fokus-Links haben, können wir eine bestimmte Zahl auf der Seite mit Klammern [] vergrößern.

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
podcast_url = "http://betweenscreens.fm/"
6
7
page = agent.get(podcast_url)
8
9
focus_link = agent.page.links_with(:text => 'Focus')[2]
10
11
puts focus_link

Wenn Sie nicht nach dem Linktext, sondern nach dem Link selbst suchen, müssen Sie nur eine bestimmte href angeben, um diesen Link zu finden. Mechanisieren steht Ihnen nicht im Weg. Anstelle von text füttern Sie die Methoden mit href.

some_scraper.rb

1
page = agent.page.link_with(href: '/episodes/95/')
2
3
page = agent.page.links_with(href: '/episodes/95/')

Wenn Sie nur den ersten Link mit dem gewünschten Text finden möchten, können Sie auch diese Syntax verwenden. Sehr praktisch und etwas lesbarer.

some_scraper.rb

1
focus_links = agent.page.link_with(:text => 'Focus')

Wie wäre es, diesem Kerl zu folgen und zu sehen, was sich hinter diesem Focus-Link verbirgt? click wir darauf!

Klicken

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
podcast_url = "http://betweenscreens.fm/"
6
7
page = agent.get(podcast_url)
8
9
focus_links = agent.page.links.find { |link| link.text == 'Focus' }.click.links
10
11
puts focus_links

Dies würde uns eine weitere lange Liste von Links wie zuvor bringen. Sehen Sie, wie einfach es war, .click.links zu kombinieren. Mechanize klickt auf den Link für Sie und folgt der Seite zum neuen Ziel. Da wir auch eine Liste von Links angefordert haben, erhalten wir alle Links, die Mechanize auf dieser neuen Seite finden kann.

Angenommen, ich habe zwei Textlinks desselben Befragten - einen, der auf Tags verweist, und einen auf eine aktuelle Episode - und ich möchte die Links von jeder dieser Seiten erhalten.

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
podcast_url = "http://betweenscreens.fm/"
6
7
page = agent.get(podcast_url)
8
9
links = agent.page.links_with(text: "Some interviewee")
10
11
links.each do |link|
12
  puts link.click.links
13
end

Dies würde Ihnen eine Liste von Links für beide Seiten geben. Sie durchlaufen jeden Link für den Befragten, und Mechanize folgt dem angeklickten Link und sammelt die auf der neuen Seite gefundenen Links für Sie. Im Folgenden finden Sie einige Beispiele, in denen Sie Kombinationen vergleichen können, um loszulegen.

some_scraper.rb

1
agent.page.links.find { |l| l.text == 'Focus' }
2
agent.page.links.find { |l| l.text == 'Focus' }.click
3
agent.page.link_with(text: 'Focus')
4
agent.page.links_with(text: 'Focus')[0]
5
agent.page.links_with(text: 'Focus')[1].click
6
agent.page.links_with(text: 'Focus')[2].click.links
7
agent.page.link_with(href: '/some-href')
8
agent.page.link_with(href: '/some-href').click
9
agent.page.links_with(href: '/some-href')
10
agent.page.links_with(href: '/some-href').click

Formen

  • submit
  • field_with
  • checkbox_with
  • radiobuttons_with
  • file_uploads

Schauen wir uns die Formulare an!

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
google_url = "http://google.com/"
6
7
page = agent.get(google_url)
8
9
forms = page.forms
10
11
puts forms.inspect

Ausgabe

1
[#<Mechanize::Form

2
# Attention!!

3
 {name "f"}
4
# Attention!!

5
 {method "GET"}
6
 {action "/search"}
7
 {fields
8
  [hidden:0x3fea91d2eb08 type: hidden name: ie value: ISO-8859-1]
9
  [hidden:0x3fea91d2e964 type: hidden name: hl value: es]
10
  [hidden:0x3fea91d2e7e8 type: hidden name: source value: hp]
11
  [hidden:0x3fea91d2e5f4 type: hidden name: biw value: ]
12
  [hidden:0x3fea91d2e428 type: hidden name: bih value: ]
13
# Attention!!

14
  [text:0x3fea91d2e248 type:  name: q value: ]
15
# Attention!!

16
  [hidden:0x3fea91d2bcb4 type: hidden name: gbv value: 1]}
17
 {radiobuttons}
18
 {checkboxes}
19
 {file_uploads}
20
 {buttons
21
  [submit:0x3fea91d2e0f4 type: submit name: btnG value: Buscar con Google]
22
  [submit:0x3fea91d2be80 type: submit name: btnI value: Voy a tener suerte]}>
23
]

Da wir die forms-Methode verwenden, wird ein Array zurückgegeben - auch wenn nur ein Formular an uns zurückgegeben wird. Jetzt, da wir wissen, dass das Formular den Namen "f" hat, können wir das Singular-Versions-form verwenden, um dieses zu verfeinern.

1
...
2
3
{name "f"}
4
5
...

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
google_url = "http://google.com/"
6
7
page = agent.get(google_url)
8
9
search_form = page.form('f')
10
11
puts search_form.inspect

Mit dem form('f') haben wir das bestimmte Formular ausgewählt, mit dem wir arbeiten möchten. Infolgedessen wird kein Array zurückgegeben.

Ausgabe

1
#<Mechanize::Form

2
# Attention!!

3
 {name "f"}
4
# Attention!!

5
 {method "GET"}
6
 {action "/search"}
7
 {fields
8
  [hidden:0x3ffe9ce85ba4 type: hidden name: ie value: ISO-8859-1]
9
  [hidden:0x3ffe9ce859d8 type: hidden name: hl value: es]
10
  [hidden:0x3ffe9ce857bc type: hidden name: source value: hp]
11
  [hidden:0x3ffe9ce85618 type: hidden name: biw value: ]
12
  [hidden:0x3ffe9ce853e8 type: hidden name: bih value: ]
13
# Attention!!

14
  [text:0x3ffe9ce851cc type:  name: q value: ]
15
# Attention!!

16
  [hidden:0x3ffe9ce84bdc type: hidden name: gbv value: 1]}
17
 {radiobuttons}
18
 {checkboxes}
19
 {file_uploads}
20
 {buttons
21
  [submit:0x3ffe9ce85078 type: submit name: btnG value: Buscar con Google]
22
  [submit:0x3ffe9ce84e48 type: submit name: btnI value: Voy a tener suerte]}>

Wir können auch den Namen des Texteingabefeldes (q) identifizieren.

1
...
2
3
[text:0x3ffe9ce851cc type:  name: q value: ]
4
5
...

Wir können es unter diesem Namen anvisieren und seinen Wert wie Ruby-Attribute festlegen. Alles was wir tun müssen, ist ihm einen neuen Wert zu geben. Sie können dem obigen Ausgabebeispiel entnehmen, dass es standardmäßig leer ist.

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
google_url = "http://google.com/"
6
7
page = agent.get(google_url)
8
9
search_form = page.form('f')
10
search_form.q = 'New Google Search'
11
12
puts search_form.inspect

Ausgabe

1
#<Mechanize::Form

2
 {name "f"}
3
 {method "GET"}
4
 {action "/search"}
5
 {fields
6
  [hidden:0x3fcb85b6a784 type: hidden name: ie value: ISO-8859-1]
7
  [hidden:0x3fcb85b6a57c type: hidden name: hl value: es]
8
  [hidden:0x3fcb85b6a3b0 type: hidden name: source value: hp]
9
  [hidden:0x3fcb85b6a16c type: hidden name: biw value: ]
10
  [hidden:0x3fcb85b67f20 type: hidden name: bih value: ]
11
# Attention!!

12
  [text:0x3fcb85b67d18 type:  name: q value: New Google Search]
13
# Attention!!

14
  [hidden:0x3fcb85b67728 type: hidden name: gbv value: 1]}
15
 {radiobuttons}
16
 {checkboxes}
17
 {file_uploads}
18
 {buttons
19
  [submit:0x3fcb85b67b9c type: submit name: btnG value: Buscar con Google]
20
  [submit:0x3fcb85b67994 type: submit name: btnI value: Voy a tener suerte]}>

Wie Sie oben sehen können, wurde der Wert für das Textfeld in Neue Google-Search geändert. Jetzt müssen wir nur noch das Formular submit und die Ergebnisse von der von Google zurückgegebenen Seite sammeln. Einfacher geht es nicht. Lassen Sie uns diesmal nach etwas anderem suchen!

some_scraper.rb

1
require 'mechanize'
2
3
agent = Mechanize.new
4
5
google_url = "http://google.com/"
6
page = agent.get(google_url)
7
8
search_form = page.form('f')
9
search_form.q = 'GitHub TouchFart'
10
11
page = agent.submit(search_form)
12
13
pp page.search('h3.r').map(&:text)

Hier habe ich den Suchergebnis-Header mit einem CSS-Selektor h3.r identifiziert, seinen text zugeordnet und die Ergebnisse hübsch gedruckt. War das nicht schwer? Das ist sicher ein einfaches Beispiel, aber denken Sie an die unendlichen Möglichkeiten, die Ihnen damit zur Verfügung stehen!

Ausgabe

1
["GitHub - hungtruong/TouchFart: A fart app for the new Macbook ...",
2
 "TouchFart/TouchFart at master · hungtruong/TouchFart · GitHub",
3
 "Commits · hungtruong/TouchFart · GitHub",
4
 "Projects · hungtruong/TouchFart · GitHub",
5
 "Pull Requests · hungtruong/TouchFart · GitHub",
6
 "Issues · hungtruong/TouchFart · GitHub",
7
 "TouchFart/license.txt at master · hungtruong/TouchFart · GitHub",
8
 "Add autoplay attribute to <audio> tag and touchfart (er ... - GitHub",
9
 "Find file - File Finder · GitHub",
10
 "Fart app for the new Macbook Pro's Touch... #3860 on topic touchfart ..."]

Mechanize verfügt über verschiedene Eingabefelder, mit denen Sie spielen können. Sie können sogar Dateien hochladen!

  • field_with
  • checkbox_with
  • radiobuttons_with
  • file_uploads

Sie können Optionsfelder und Kontrollkästchen auch anhand ihres Namens identifizieren und mit - Sie haben es erraten - check.

some_scraper.rb

1
form.radiobuttons_with(:name => 'gender')[3].check
2
3
form.checkbox_with(:name => 'coder').check

Mit Options-Tags können Benutzer ein Element aus einer Dropdown-Liste auswählen. Wir richten sie erneut nach Namen aus und wählen die gewünschte Optionsnummer aus.

some_scraper.rb

1
form.field_with(:name => 'countries').options[22].select

Das Hochladen von Dateien funktioniert ähnlich wie das Eingeben von Text in Formulare, indem es wie Ruby-Attribute festgelegt wird. Sie identifizieren das Upload-Feld und geben dann den Dateipfad (Dateinamen) an, den Sie übertragen möchten. Es klingt komplizierter als es ist. Werfen wir einen Blick!

some_scraper.rb

1
form.file_uploads.first.file_name = "some-path/some-image.jpg"

Abschließende Gedanken

Seht, doch keine Magie! Sie sind jetzt gut gerüstet, um selbst Spaß zu haben. Es gibt sicherlich ein bisschen mehr über Nokogiri und Mechanize zu lernen, aber anstatt zu viel Zeit mit unnötigen Aspekten zu verbringen, spielen Sie damit herum und lesen Sie mehr Dokumentation, wenn Sie auf Probleme stoßen, die über den Rahmen eines Anfängerartikels hinausgehen.

Ich hoffe, Sie können sehen, wie einfach dieses Juwel ist und wie viel Kraft es bietet. Wie wir alle inzwischen aus der Populärkultur wissen, trägt dies auch Verantwortung. Verwenden Sie es innerhalb rechtlicher Rahmenbedingungen und wenn Sie keinen Zugriff auf eine API haben. Sie werden diese Werkzeuge wahrscheinlich nicht häufig verwenden, aber Junge, sie sind nützlich, wenn Sie echte Kratzbedürfnisse vor sich haben.

Wie versprochen werden wir im nächsten Artikel ein Beispiel aus der Praxis behandeln, in dem ich Daten von meiner Podcast-Site kratzen werde. Ich werde es von einer alten Sinatra-Site extrahieren und auf meine neue Middleman-Site übertragen, die für jede Episode .markdown-Dateien verwendet. Wir werden die Daten, Episodennummern, Namen der Befragten, Überschriften, Unterüberschriften usw. extrahieren. Wir sehen uns dort!

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.