Advertisement
  1. Code
  2. Ruby

Membangun Scraper Web Pertama Anda, Bagian 2

Scroll to top
Read Time: 22 min

Indonesian (Bahasa Indonesia) translation by ⚡ Rova Rindrata (you can also view the original English article)

Dalam tutorial ini, Anda akan belajar bagaimana Anda bisa menggunakan Mechanize untuk mengklik tautan, mengisi formulir, dan mengunggah file. Anda juga akan belajar bagaimana Anda bisa mengiris halaman objek Mechanize dan bagaimana cara mengotomatisasi pencarian Google dan menyimpan hasilnya.

Topik-topik

  • Halaman Tunggal vs. Paginasi
  • Mechanize
  • Agen
  • Halaman
  • Metode Nokogiri
  • Tautan-tautan
  • Klik
  • Formulir

Halaman Tunggal vs. Paginasi

Sejauh ini kita telah menghabiskan beberapa waktu mencari tahu bagaimana kita bisa meng-scrape layar satu halaman menggunakan Nokogiri. Ini adalah dasar yang baik untuk melangkah maju dan belajar mengekstrak konten dari banyak halaman.

Bagaimanapun, masalah yang ingin kita selesaikan melibatkan mendapatkan konten dari lebih dari 140 episode—yang lebih banyak konten daripada yang cukup sesuai dengan satu halaman web. Kita harus bekerja dengan paginasi dan perlu mencari cara untuk mengikuti konten di lubang kelincinya.

Di sinilah Nokogiri berhenti dan gem berguna lainnya yang disebut Mechanize ikut bermain.

Mechanize

Mechanize adalah alat lain yang hebat yang memiliki banyak barang untuk ditawarkan. Ini pada dasarnya memungkinkan Anda untuk mengotomatisasi interaksi dengan situs web yang Anda butuhkan untuk mengekstrak kontennya. Dalam hal ini, saya mengingatkan beberapa fungsi yang mungkin Anda ketahui dari pengujian dengan Capybara.

Jangan salah sangka, bermain dengan Nokogiri di satu halaman sangat mengagumkan, tapi untuk pekerjaan ekstraksi data yang lebih pedas, kita memerlukan sedikit tenaga kuda lagi. Pada intinya kita dapat merayap melalui halaman sebanyak yang kita butuhkan dan berinteraksi dengan elemen mereka—meniru dan mengotomatisasi perilaku manusia. Barang yang cukup bagus!

Permata ini memungkinkan Anda mengikuti tautan, mengisi field-field formulir, dan mengirimkan data tersebut—bahkan menangani cookie sudah dipersiapkan. Itu berarti Anda juga dapat meniru login pengguna ke sesi pribadi dan mendapatkan konten dari situs yang hanya Anda yang memiliki aksesnya.

Anda mengisi login dengan kredensial Anda dan memberitahu Mechanize bagaimana cara mengikuti. Karena Anda bisa mengklik tautan dan mengirimkan formulir, sangat sedikit yang tidak dapat Anda lakukan dengan alat ini. Ini memiliki hubungan dekat dengan Nokogiri dan juga bergantung padanya. Aaron Patterson kembali menjadi salah satu pencipta gem yang indah ini.

Instansiasi Agen Mechanize

Sebelum kita bisa mulai melakukan mekanisasi, kita perlu memberi instansiasi agen Mechanize.

some_scraper.rb

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

Agent ini akan digunakan untuk mengambil halaman, mirip dengan apa yang kita lakukan dengan 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)

Yang terjadi di sini adalah agen Mechanize mendapatkan halaman podcast dan cookies-nya.

Mengekstrak Konten Halaman

Kita sekarang memiliki halaman yang siap untuk diekstraksi. Sebelum kita melakukannya, saya menyarankan agar kita melihat apa yang terjadi dengan menggunakan metode inspect.

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

Hasilnya cukup substantif. Lihat dan perhatikan apa arti objek Mechanize::Page. Di sini Anda bisa melihat semua atribut untuk halaman itu.

Bagi saya, ini adalah objek yang sangat berguna untuk mengiris data yang ingin Anda ekstrak.

Keluaran

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}>

Jika Anda ingin melihat halaman HTML itu sendiri, Anda dapat memberi tag pada metode body atau content.

some_scraper.rb

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

Keluaran

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>

Karena podcast ini hanya memiliki sejumlah kecil elemen yang berbeda pada halaman, inilah Mechanize::Page yang akan dikembalikan dari github.com. Ini memiliki variasi konten yang lebih besar untuk dilihat. Saya pikir ini penting untuk Anda rasakan.

Keluaran 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: ]}>}>

Kembali ke podcast, Anda juga dapat melihat hal-hal seperti pengkodean, kode tanggapan HTTP, URI, atau header tanggapan.

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

Keluaran

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/

Ada banyak hal lagi jika Anda ingin menggali lebih dalam. Akan saya tinggalkan seperti itu.

Metode Nokogiri

  • at
  • search

Mechanize menggunakan Nokogiri untuk meng-scrape data dari halaman. Anda bisa menerapkan apa yang Anda pelajari tentang Nokogiri di artikel pertama dan menggunakannya di halaman Mechanize juga. Itu berarti Anda umumnya menggunakan Mechanize untuk menavigasi halaman dan metode Nokogiri untuk kebutuhan scrape Anda.

Misalnya, jika Anda ingin mencari satu objek, Anda bisa menggunakan at, sementara search mengembalikan semua objek yang sesuai dengan pemilih pada halaman tertentu. Untuk mengulanginya, metode-metode ini akan bekerja baik pada dokumen Nokogiri dan objek halaman Mechanize.

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

Keluaran

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>

Tautan-tautan

  • links
  • link_with
  • links_with

Kita juga bisa menavigasi seluruh situs sesuai dengan keinginan kita. Mungkin bagian terpenting dari Mechanize adalah kemampuannya untuk membiarkan Anda bermain dengan tautan. Jika tidak, Anda bisa tetap bertahan dengan Nokogiri itu sendiri. Mari kita lihat apa yang kita dapatkan kembali jika kita meminta halaman untuk tautannya.

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}"

Keluaran

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, mari kita rinci ini. Karena kita belum memberi tahu Mechanize untuk mencari tempat lain, kita mendapat banyak tautan dari hanya halaman pertama tersebut. Mechanize pergi melewati halaman itu dalam urutan menurun dan mengembalikan daftar tautan ini dari atas ke bawah. Saya telah membuat gambar kecil dengan pointer hijau ke berbagai tautan yang dapat Anda lihat di keluaran.

Omong-omong, ini sudah menunjukkan hasil akhir dari desain ulang untuk podcast saya. Saya pikir versi ini sedikit lebih baik untuk tujuan demonstrasi. Anda juga bisa melihat sekilas bagaimana hasil akhirnya terlihat dan mengapa saya perlu meng-scrape situs Sinatra lama saya.

Tangkapan Layar

Podcast LinksPodcast LinksPodcast Links

Seperti biasa, kita juga bisa mengekstrak teks saja darinya.

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

Keluaran

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

Mendapatkan semua tautan ini dalam jumlah besar bisa sangat berguna atau hanya membosankan. Beruntung bagi kita, kita memiliki beberapa alat untuk menyesuaikan apa yang kita butuhkan.

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

Keluaran

1
Focus

Boom! Sekarang kita mempunyai tujuan! Kita bisa memperbesar tautan tertentu seperti itu. Kita dapat menargetkan tautan yang sesuai dengan kriteria tertentu—seperti teksnya, misalnya—dengan API yang lebih bagus seperti links_with atau link_with. Selain itu, jika ada beberapa tautan Focus, kita dapat memperbesar sejumlah tertentu di halaman yang menggunakan tanda kurung [].

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

Jika Anda tidak mencari teks tautan tapi tautan itu sendiri, Anda hanya perlu menentukan href tertentu untuk menemukan tautannya. Mechanize tidak akan menghalangi Anda. Alih-alih text, Anda memberi feed metodenya dengan href.

some_scraper.rb

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

Jika Anda hanya ingin mencari tautan pertama dengan teks yang diinginkan, Anda juga bisa menggunakan sintaks ini. Sangat mudah dan sedikit lebih mudah dibaca.

some_scraper.rb

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

Bagaimana dengan mengikuti teman tersebut dan melihat apa yang tersembunyi di balik tautan Focus ini? Mari kita klik!

Klik

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

Ini akan membuat daftar panjang lainnya seperti sebelumnya. Lihat betapa mudahnya menggabungkan .click.links. Mechanize mengklik tautan untuk Anda dan mengikuti halaman ke tujuan yang baru. Karena kita juga meminta daftar tautan, kita akan mendapatkan semua tautan yang dapat ditemukan Mechanize di halaman baru tersebut.

Katakanlah saya memiliki dua tautan teks dari yang diwawancarai yang sama—yang mentautkan ke tag dan satu dengan episode terakhir—dan saya ingin mendapatkan tautan dari masing-masing halaman ini.

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

Ini akan memberi Anda daftar tautan untuk kedua halaman. Anda mengulangi setiap tautan untuk yang diwawancarai, dan Mechanize mengikuti tautan yang diklik dan mengumpulkan tautan yang ditemukannya di halaman baru untuk Anda. Di bawah ini Anda dapat menemukan beberapa contoh di mana Anda dapat membandingkan kombinasi untuk Anda memulai.

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

Formulir

  • submit
  • field_with
  • checkbox_with
  • radiobuttons_with
  • file_uploads

Mari kita lihat formulirnya!

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

Keluaran

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
]

Karena kita menggunakan metode forms, kita mendapatkan sebuah array yang dikembalikan—bahkan ketika kita hanya memiliki satu formulir yang dikembalikan kepada kita. Sekarang kita tahu bahwa formulirnya memiliki nama "f", kita bisa menggunakan form versi tunggal untuk mengasahnya.

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

Dengan menggunakan form('f'), kita memilih formulir khusus yang ingin kita bekerja dengannya. Akibatnya, kita tidak akan mendapatkan array yang dikembalikan.

Keluaran

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]}>

Kita juga bisa mengidentifikasi nama field masukan teks (q).

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

Kita bisa mentargetnya dengan nama itu dan tetapkan nilainya seperti atribut Ruby. Yang perlu kita lakukan adalah memberikannya dengan nilai baru. Anda dapat melihat dari contoh keluaran di atas yang kosong secara default.

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

Keluaran

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]}>

Seperti yang dapat Anda amati di atas, nilai field teks telah berubah ke New Google Search. Sekarang kita hanya perlu submit formulir dan mengumpulkan hasilnya dari halaman yang dikembalikan Google. Tidak bisa yang lebih mudah. Mari kita cari yang lain kali ini!

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)

Di sini saya mengidentifikasi header hasil pencarian menggunakan penyeleksi CSS h3.r, memetakan text-nya, dan mencetak hasilnya dengan cantik. Tidak sesulit itu, bukan? Itu adalah contoh yang mudah, tentu, tapi pikirkan kemungkinan tak terbatas yang Anda miliki dengan ini!

Keluaran

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 memiliki bidang masukan yang berbeda yang tersedia untuk Anda mainkan. Anda bahkan bisa mengunggah file!

  • field_with
  • checkbox_with
  • radiobuttons_with
  • file_uploads

Anda juga bisa mengenali tombol radio dan kotak centang dengan nama mereka dan mencentangnya—Anda bisa menebaknya—check.

some_scraper.rb

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

Tag option menawarkan pengguna untuk memilih satu item dari daftar drop-down. Sekali lagi, kita targetkan mereka dengan nama dan memilih nomor pilihan yang kita inginkan.

some_scraper.rb

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

Pengunggahan file bekerja sama dengan memasukkan teks ke dalam formulir dengan menyetelnya seperti atribut-atribut Ruby. Anda mengidentifikasi kolom unggahan dan kemudian menentukan path file (nama file) yang ingin Anda transfer. Kedengarannya lebih rumit dari itu. Mari kita lihat!

some_scraper.rb

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

Pemikiran Akhir

Lihat, tidak ada keajaiban! Anda sekarang dilengkapi dengan baik untuk bersenang-senang sendiri. Tentu ada sedikit lebih banyak untuk belajar tentang Nokogiri dan Mechanize, tapi bukannya menghabiskan terlalu banyak waktu untuk aspek yang tidak perlu, bermain-main dengannya dan melihat beberapa dokumentasi lagi saat Anda mengalami masalah di luar lingkup artikel pemula.

Saya harap Anda bisa melihat betapa indahnya gem ini dan berapa banyak kekuatan yang ditawarkannya. Seperti yang kita semua tahu dari budaya populer sekarang, ini juga memikul tanggung jawab. Gunakan di dalam kerangka hukum dan bila Anda tidak memiliki akses ke API. Anda mungkin tidak akan sering menggunakan alat ini, tapi sungguh mereka berguna saat Anda memiliki beberapa kebutuhan scraping nyata di depan Anda.

Seperti yang dijanjikan, pada artikel selanjutnya kita akan membahas contoh dunia nyata dimana saya akan meng-scrape data dari situs podcast saya. Saya akan mengekstraknya dari situs Sinatra yang lama dan memindahkannya ke situs Middleman baru saya yang menggunakan file .markdown untuk setiap episode. Kita akan mengekstrak tanggal, nomor episode, nama yang diwawancarai, header, subheader, dan sebagainya. Sampai jumpa!

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.