Advertisement
  1. Code
  2. Ruby

Membuat Web Scraper Pertama Anda, Bagian 1

Scroll to top
Read Time: 25 min

Indonesian (Bahasa Indonesia) translation by Muhammad Gufron (you can also view the original English article)

Rubyland memiliki dua permata yang telah menduduki sorotan web scraping selama beberapa tahun terakhir: Nokogiri dan Mekanize. Kita menghabiskan artikel pada masing-masing sebelum kita menempatkan mereka ke dalam tindakan dengan contoh praktis.

Topik

  • Web Scraping?
  • Permission
  • Masalah
  • Nokogiri
  • Ekstraksi?
  • Halaman
  • API
  • Node Navigation

Web Scraping?

Ada istilah yang lebih bagus di sekitar daripada web atau screen scraping. Web harvesting dan web data extraction cukup banyak memberitahu Anda segera apa yang terjadi. We dapat mengotomatisasi ekstraksi data dari halaman web — dan tidak yang rumit juga.

Dengan cara, alat-alat ini memungkinkan Anda untuk meniru dan mengotomatisasi browsing web manusia. Anda menulis sebuah program yang hanya ekstrak jenis data yang menarik bagi Anda. Penargetan data tertentu hampir semudah dengan menggunakan CSS selector.

Beberapa tahun lalu saya berlangganan beberapa kursus video online yang punya seperti satu juta video pendek tapi tidak ada pilihan untuk men-download dalam jumlah besar. Saya harus melalui setiap tautan saya sendiri dan melakukan hal yang ditakuti ‘save as’ sendiri. Itu adalah semacam manusia web scraping — sesuatu yang kita sering perlu lakukan ketika kita kekurangan pengetahuan untuk mengotomatisasi hal semacam itu. Kursus itu sendiri baik-baik saja, tetapi saya tidak menggunakan layanan mereka lagi setelah itu. Itu terlalu membosankan.

Hari ini, aku tidak peduli terlalu banyak tentang seperti mind-melting UX. Scraper yang akan melakukan download untuk saya saya akan mengambil hanya beberapa menit untuk melemparkan bersama-sama. Tidak ada masalah besar!

Biarkan saya memecahnya dengan cepat sebelum kita mulai. Semuanya dapat diringkas menjadi beberapa langkah. Pertama kita mengambil halaman web yang memiliki data yang diinginkan yang kita butuhkan. Kemudian kita mencari melalui halaman tersebut dan mengidentifikasi informasi yang kami inginkan untuk mengekstrak.

Langkah terakhir adalah untuk menargetkan bit ini, iris mereka jika diperlukan, dan putuskan bagaimana dan di mana Anda ingin menyimpannya. HTML yang ditulis dengan baik sering kali menjadi kunci untuk membuat proses ini mudah dan menyenangkan. Untuk ekstraksi yang lebih terlibat, itu bisa menjadi sakit jika Anda harus berurusan dengan markup yang tidak terstruktur dengan baik.

Bagaimana dengan API? Pertanyaan yang sangat bagus. Jika Anda memiliki akses ke layanan dengan API, sering ada sedikit kebutuhan untuk menulis scraper Anda sendiri. Pendekatan ini adalah sebagian besar untuk situs web yang tidak menawarkan semacam kenyamanan. Tanpa API, hal ini sering satu-satunya cara untuk mengotomatisasi proses ekstraksi informasi dari situs web.

Anda mungkin bertanya, bagaimana scraping benar-benar bekerja? Tanpa melompat ke ujung yang dalam, jawaban pendek adalah, dengan melintasi pohon struktur data. Nokogiri membangun struktur data ini dari dokumen-dokumen Anda memberinya makan dan memungkinkan Anda menargetkan bit menarik untuk ekstraksi. Misalnya, CSS adalah bahasa yang ditulis untuk pohon traversal, untuk mencari pohon struktur data, dan kita dapat menggunakannya untuk ekstraksi data.

Ada banyak pendekatan dan solusi di luar sana untuk dimainkan. Rubyland memiliki dua permata yang telah menduduki sorotan selama beberapa tahun sekarang. Banyak orang masih bergantung pada Nokogiri dan Mechanize untuk kebutuhan HTML scraping. Keduanya telah diuji dan membuktikan dirinya sebagai mudah digunakan sementara menjadi sangat mampu. Kita akan melihat keduanya. Namun sebelum itu, saya ingin meluangkan waktu untuk mengatasi masalah yang akan kami pecahkan di akhir seri pengantar singkat ini.

Permision

Sebelum Anda mulai scraping pergi, pastikan Anda memiliki izin dari situs yang Anda mencoba untuk mengakses data ekstraksi. Jika situs memiliki API atau RSS feed, misalnya, mungkin tidak hanya lebih mudah untuk mendapatkan konten yang diinginkan, itu juga mungkin menjadi pilihan legal.

Tidak semua orang akan menghargai jika Anda melakukan scraping besar-besaran di situs mereka — dimengerti. Mendapatkan diri Anda yang berpendidikan pada situs tertentu Anda tertarik, dan tidak mendapatkan diri Anda dalam kesulitan. Kemungkinan rendah bahwa Anda akan menimbulkan kerusakan serius, tapi mempertaruhkan masalah tanpa sadar tidak cara untuk pergi.

Masalah

Aku perlu untuk membangun podcast baru. Desain itu tidak mana saya ingin menjadi, dan aku benci cara penerbitan posting baru. WYSIWYGs sialan! Sedikit dari konteks. Sekitar dua tahun yang lalu, aku membangun versi pertama dari podcast. Idenya adalah untuk bermain dengan Sinatra dan membangun sesuatu yang super ringan. Aku berlari ke dalam beberapa masalah yang tak terduga sejak aku tailor-made pretty much semua.

Datang dari rel, itu pasti perjalanan pendidikan yang saya menghargai, tapi dengan cepat menyesal tidak digunakan situs statis yang saya bisa digunakan melalui GitHub melalui GitHub pages. Mendeploy episode baru dan mempertahankannya tidak memiliki kesederhanaan yang saya cari. Untuk sementara, saya memutuskan bahwa saya punya ikan yang lebih besar untuk menggoreng dan terfokus pada menghasilkan bahan podcast baru sebagai gantinya.

Ini musim panas lalu saya mulai mendapatkan serius dan bekerja di situs perantara yang di-host melalui halaman GitHub. Untuk musim dua acara, aku ingin sesuatu yang segar.  Desain baru yang disederhanakan, Penurunan harga untuk memublikasikan episode baru, dan tidak ada perkelahian dengan Heroku — surga! Masalahnya adalah bahwa saya memiliki 139 episode yang tergeletak di sekitar yang diperlukan untuk diimpor dan dikonversi pertama untuk bekerja dengan perantara.

Untuk posting, perantara menggunakan file .markdown yang telah disebut frontmatter untuk data — yang menggantikan database saya pada dasarnya. Melakukan transfer ini dengan tangan bukanlah suatu pilihan untuk episode 139. Itulah gunanya perhitungan. Saya perlu mencari cara untuk menguraikan HTML situs web lama saya, mengikis konten yang relevan, dan mentransfernya ke posting blog yang saya gunakan untuk menerbitkan episode podcast baru di perantara.

Oleh karena itu, selama tiga artikel berikutnya, saya akan memperkenalkan Anda ke alat yang biasa digunakan di Rubyland untuk tugas-tugas tersebut.  Pada akhirnya, kami akan membahas solusi saya untuk menunjukkan kepada Anda sesuatu yang praktis juga.

Nokogiri

Bahkan jika Anda benar-benar baru Ruby Rails, kemungkinan baik bahwa Anda telah mendengar tentang permata kecil ini. Nama dijatuhkan sering dan tongkat dengan Anda dengan mudah. Saya tidak yakin banyak yang tahu bahwa nokogiri adalah bahasa Jepang untuk “melihat”.

Ini adalah nama yang pas setelah Anda memahami apa yang dilakukan alat tersebut.  Pencipta permata ini adalah Tenderlove yang cantik, Aaron Patterson. Nokogiri mengkonversi dokumen XML dan HTML ke dalam struktur data — struktur data pohon, menjadi lebih tepat. Alat cepat dan menawarkan antarmuka yang bagus juga. Secara keseluruhan, ini adalah pustaka yang sangat kuat yang menangani banyak kebutuhan scraping HTML Anda.

Anda dapat menggunakan Nokogiri tidak hanya untuk menguraikan HTML; XML adalah game yang adil juga. Ini memberi Anda pilihan dari bahasa jalur XML dan antarmuka CSS untuk melintasi dokumen yang Anda muat. Bahasa Path XML, atau XPath untuk pendek, adalah bahasa kueri.

Hal ini memungkinkan kita untuk pilih node dari dokumen-dokumen XML. CSS selector adalah kemungkinan lebih akrab untuk pemula. Seperti halnya gaya yang Anda tulis, pemilih CSS membuatnya sangat mudah untuk menargetkan bagian tertentu dari halaman yang menarik untuk ekstraksi. Anda hanya perlu membiarkan Nokogiri tahu apa yang Anda cari ketika Anda menargetkan tujuan tertentu.

Halaman

Yang harus selalu kita mulai adalah mengambil halaman yang sebenarnya kita minati. Kita menentukan apa jenis dokumen Nokogiri kita ingin parse — XML atau HTML untuk contoh:

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 dan Nokogiri:HTML dapat mengambil objek IO atau objek String. Apa yang terjadi di atas sederhana. Ini membuka dan mengambil Ruangan Khusus halaman menggunakan open-uri dan kemudian beban strukturnya, XML atau HTML ke dokumen Nokogiri baru. XML bukanlah sesuatu yang harus dihadapi pemula dengan sangat sering.

Oleh karena itu, saya akan merekomendasikan bahwa kita fokus pada parsing HTML untuk saat ini. Mengapa open-uri? Modul ini dari Perpustakaan Standar Ruby memungkinkan kami mengambil situs tanpa banyak keributan. Karena IO objek permainan yang adil, kita dapat membuat mudah penggunaan open-uri.

API

Mari praktikkan ini dengan contoh mini:

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

Apa yang kami lakukan di sini mewakili semua langkah yang biasanya terlibat dengan web scraping — hanya pada tingkat mikro. Kami memutuskan URL mana yang kami butuhkan dan situs mana yang perlu kami ambil, dan kami memuatnya ke dokumen Nokogiri yang baru. Lalu kami membuka halaman itu dan menargetkan bagian tertentu.

Di sini saya hanya ingin tahu judul episode terbaru. Menggunakan metode at_css dan pemilih CSS untuk h2.post-title adalah yang saya perlukan untuk menargetkan titik ekstraksi. Dengan metode ini kami hanya akan mengikis elemen tunggal ini, meskipun. Ini memberi kita seluruh pemilih - yang sebagian besar waktu bukan apa yang kita butuhkan. Oleh karena itu kami hanya mengekstrak bagian teks bagian dalam dari node ini melalui metode teks. Sebagai perbandingan, Anda dapat memeriksa output untuk header dan teks di bawah ini.

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
 
3
 This is the title of the latest episode: David Heinemeier Hansson

Meskipun contoh ini memiliki aplikasi yang sangat terbatas, ia memiliki semua bahan, semua langkah yang perlu Anda pahami. Saya pikir itu keren betapa sederhananya hal ini. Karena mungkin tidak jelas dari contoh ini, saya ingin menunjukkan seberapa kuat alat ini. Mari kita lihat apa lagi yang bisa kita lakukan dengan skrip Nokogiri.

Perhatian!

Jika Anda seorang pemula dan tidak yakin bagaimana menargetkan HTML yang diperlukan untuk ini, saya sarankan Anda mencari online untuk mencari tahu cara memeriksa isi situs web di browser Anda. Pada dasarnya, semua browser utama membuat proses ini sangat mudah akhir-akhir ini.

Di Chrome Anda hanya perlu klik kanan pada sebuah elemen dalam situs web dan memilih inspect option. Ini akan membuka jendela kecil di bagian bawah browser Anda yang menunjukkan kepada Anda sesuatu seperti x-ray dari situs DOM. Ini memiliki lebih banyak pilihan, dan saya akan merekomendasikan menghabiskan beberapa waktu di Google untuk mendidik diri sendiri. Ini adalah waktu yang dihabiskan dengan bijaksana!

CSS

Metode css akan memberi kita tidak hanya satu elemen pilihan tetapi setiap elemen yang cocok dengan kriteria pencarian pada halaman. Cukup rapi dan mudah!

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

Satu-satunya sedikit perbedaan dalam hal ini contoh adalah bahwa saya iterate pada header mentah yang pertama. Saya juga mengekstrak teks bagian dalamnya dengan metode teks. Nokogiri berhenti secara otomatis di bagian akhir halaman dan tidak mencoba mengikuti paginasi di mana saja secara otomatis.

Katakanlah kita ingin memiliki lebih banyak informasi, katakan tanggal dan subtitle untuk setiap episode. Kami hanya dapat memperluas contoh di atas. Ini adalah ide yang baik pula untuk mengambil langkah demi langkah ini. Dapatkan sedikit karya dan tambahkan lebih banyak kerumitan di sepanjang jalan.

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:      #Jun 13, 2018"
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

Output

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

Pada titik ini, kita sudah memiliki beberapa data untuk dimainkan. Kita dapat menyusun atau memotongnya sesuka kita. Hal di atas seharusnya hanya menunjukkan apa yang kita miliki dengan cara yang mudah dibaca. Tentu saja kita dapat menggali masing-masing dengan menggunakan regular expressions dengan metode teks.

Kami akan melihat ini secara lebih detail ketika kami dapat memecahkan masalah podcast yang sebenarnya. Ini tidak akan menjadi kelas pada regexp, tetapi Anda akan melihat lebih banyak dari itu dalam tindakan — tetapi jangan khawatir, jangan sampai membuat otak Anda berdarah.

Atribut

Apa yang bisa menjadi berguna pada tahap ini adalah penggalian href untuk episode individu juga. Itu tidak bisa lebih sederhana.

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:      #Jun 13, 2018"
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

Bit yang paling penting untuk diperhatikan di sini adalah [: href] dan podcast_url. Jika Anda memberi tag pada [:] Anda cukup mengekstrak atribut dari pemilih yang ditargetkan. Saya sedikit lebih abstrak, tetapi Anda dapat melihat lebih jelas bagaimana cara kerjanya di bawah ini.

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

Untuk mendapatkan URL yang lengkap dan berguna, saya menyimpan domain root dalam sebuah variabel dan membuat URL lengkap untuk setiap episode.

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

Mari kita lihat dengan cepat hasilnya:

Output

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/

Rapi, bukan? Anda dapat melakukan hal yang sama untuk mengekstrak [:class] dari pemilih.

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]

Jika simpul itu memiliki lebih dari satu kelas, Anda akan mendapatkan daftar semuanya.

Node Navigation

  • parent
  • children
  • previous_sibling
  • next_sibling

Kita terbiasa menangani struktur pohon di CSS atau bahkan jQuery. Akan sangat merepotkan jika Nokogiri tidak menawarkan API yang berguna untuk bergerak di dalam pohon seperti itu.

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"

Output

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>

Seperti yang dapat Anda lihat sendiri, ini adalah beberapa hal yang sangat kuat — terutama ketika Anda melihat apa yang bisa dilakukan oleh .parent. Alih-alih mendefinisikan sekelompok simpul dengan tangan, Anda bisa mengumpulkannya secara grosir.

Anda bahkan dapat mengikat mereka untuk dilalui lebih banyak lagi. Anda dapat menganggap ini serumit yang Anda suka, tentu saja, tetapi saya akan mengingatkan Anda untuk membuat semuanya tetap sederhana. Ini dapat dengan cepat menjadi sedikit sulit dan sulit dimengerti. Ingat, 'Keep it simple, stupid!'

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"

Output

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>

Pemikiran Akhir

Nokogiri bukanlah sebuah perpustakaan besar, tetapi memiliki banyak untuk menawarkan. Saya sarankan Anda bermain dengan apa yang telah Anda pelajari sejauh ini dan perluas pengetahuan Anda melalui dokumentasi ketika Anda mendapat stack. Tapi jangan membuat masalah!

Pengantar kecil ini akan membantu Anda memahami apa yang dapat Anda lakukan dan bagaimana cara kerjanya. Saya harap Anda akan menjelajahinya sedikit lebih sendiri dan bersenang-senang dengannya. Seperti yang Anda akan temukan sendiri, itu adalah alat yang kaya yang terus memberi.

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.