Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

การสร้าง Web Scraper แรกของคุณ ตอนที่ 1

Rubyland มีอัญมณีสองชิ้นที่ครองสปอตไลท์การขูดเว็บในช่วงไม่กี่ปีที่ผ่านมา ได้แก่ Nokogiri และ Mechanize เราใช้บทความเกี่ยวกับสิ่งเหล่านี้ก่อนที่จะนำไปปฏิบัติด้วยตัวอย่างที่ใช้งานได้จริง

หัวข้อ

  • การขูดเว็บ?
  • การอนุญาต
  • ปัญหา
  • โนโคกิริ
  • สกัด?
  • หน้า
  • API
  • การนำทางโหนด

การขูดเว็บ?

มีคำศัพท์เกี่ยวกับนักเล่นมากกว่าการขูดเว็บหรือหน้าจอ การเก็บเกี่ยวเว็บและการดึงข้อมูลเว็บสามารถบอกคุณได้ทันทีว่าเกิดอะไรขึ้น เราสามารถดึงข้อมูลจากหน้าเว็บได้โดยอัตโนมัติ และมันก็ไม่ได้ซับซ้อนขนาดนั้นเช่นกัน

เครื่องมือเหล่านี้ช่วยให้คุณสามารถเลียนแบบและทำให้การท่องเว็บของมนุษย์เป็นไปโดยอัตโนมัติ คุณเขียนโปรแกรมที่ดึงเฉพาะข้อมูลที่คุณสนใจเท่านั้น การกำหนดเป้าหมายข้อมูลเฉพาะนั้นทำได้ง่ายเหมือนกับการใช้ตัวเลือก CSS

ไม่กี่ปีที่ผ่านมาฉันสมัครรับข้อมูลหลักสูตรวิดีโอออนไลน์ที่มีวิดีโอสั้น ๆ เกือบล้านรายการ แต่ไม่มีตัวเลือกให้ดาวน์โหลดเป็นกลุ่ม ฉันต้องผ่านทุกลิงก์ด้วยตัวฉันเองและทำ 'บันทึกในฐานะ' ด้วยตัวเอง เป็นการขูดเว็บของมนุษย์ ซึ่งเป็นสิ่งที่เราต้องทำบ่อยๆ เมื่อเราขาดความรู้ในการทำให้สิ่งนั้นเป็นอัตโนมัติ ตัวหลักสูตรเองนั้นโอเค แต่หลังจากนั้นฉันก็ไม่ได้ใช้บริการอีกเลย มันน่าเบื่อเกินไป

วันนี้ฉันจะไม่สนใจ UX ที่ละลายใจเช่นนี้มากเกินไป มีดโกนที่จะทำการดาวน์โหลดให้ฉันจะใช้เวลาเพียงไม่กี่นาทีในการรวบรวม ไม่เป็นไร!

ให้ฉันทำลายมันลงอย่างรวดเร็วก่อนที่เราจะเริ่ม สิ่งทั้งหมดสามารถย่อเป็นสองขั้นตอน ขั้นแรก เราดึงหน้าเว็บที่มีข้อมูลตามที่เราต้องการ จากนั้นเราค้นหาผ่านหน้านั้นและระบุข้อมูลที่เราต้องการดึงออกมา

ขั้นตอนสุดท้ายคือการกำหนดเป้าหมายบิตเหล่านี้ แบ่งส่วนหากจำเป็น และตัดสินใจว่าคุณต้องการจัดเก็บอย่างไรและที่ไหน HTML ที่เขียนได้ดีมักเป็นกุญแจสำคัญในการทำให้กระบวนการนี้ง่ายและสนุกสนาน สำหรับการสกัดที่เกี่ยวข้องมากขึ้น อาจเป็นเรื่องที่เจ็บปวดหากคุณต้องรับมือกับมาร์กอัปที่มีโครงสร้างไม่ดี

แล้ว API ล่ะ? คำถามที่ดีมาก หากคุณมีสิทธิ์เข้าถึงบริการด้วย API คุณไม่จำเป็นต้องเขียนมีดโกนของคุณเอง แนวทางนี้ส่วนใหญ่ใช้สำหรับเว็บไซต์ที่ไม่ได้อำนวยความสะดวกแบบนั้น หากไม่มี API นี่มักจะเป็นวิธีเดียวในการดึงข้อมูลจากเว็บไซต์โดยอัตโนมัติ

คุณอาจถามว่าสิ่งที่ขูดนี้ทำงานอย่างไร? คำตอบสั้น ๆ โดยไม่ต้องกระโดดลงไปในส่วนลึกคือโดยการสำรวจโครงสร้างข้อมูลต้นไม้ Nokogiri สร้างโครงสร้างข้อมูลเหล่านี้จากเอกสารที่คุณป้อน และให้คุณกำหนดเป้าหมายบิตที่น่าสนใจสำหรับการดึงข้อมูล ตัวอย่างเช่น CSS เป็นภาษาที่เขียนขึ้นสำหรับการข้ามผ่านต้นไม้ สำหรับการค้นหาโครงสร้างข้อมูลต้นไม้ และเราสามารถใช้ประโยชน์จากมันสำหรับการดึงข้อมูล

มีแนวทางและวิธีแก้ปัญหามากมายให้เล่น Rubyland มีอัญมณีสองชิ้นที่ครองสปอตไลท์มาหลายปีแล้ว หลายคนยังคงพึ่งพา Nokogiri และ Mechanize สำหรับความต้องการในการขูด HTML ทั้งสองได้รับการทดสอบและพิสูจน์แล้วว่าใช้งานง่ายในขณะที่มีความสามารถสูง เราจะดูทั้งสองอย่าง แต่ก่อนหน้านั้น ฉันต้องการใช้เวลาสักครู่เพื่อแก้ไขปัญหาที่เราจะแก้ไขในตอนท้ายของซีรีส์แนะนำสั้นๆ นี้

การอนุญาต

ก่อนที่คุณจะเริ่มคัดแยกข้อมูล ตรวจสอบให้แน่ใจว่าคุณได้รับอนุญาตจากไซต์ที่คุณกำลังพยายามเข้าถึงเพื่อดึงข้อมูล ตัวอย่างเช่น หากไซต์มีฟีด API หรือ RSS อาจไม่เพียงแต่จะได้รับเนื้อหาที่ต้องการได้ง่ายขึ้นเท่านั้น แต่ยังอาจเป็นทางเลือกทางกฎหมายอีกด้วย

ไม่ใช่ทุกคนที่จะชื่นชมมันหากคุณทำการขูดไซต์ของพวกเขาเป็นจำนวนมาก - เข้าใจได้เช่นนั้น รับการศึกษาเกี่ยวกับไซต์ที่คุณสนใจโดยเฉพาะ และอย่าสร้างปัญหาให้ตัวเอง มีโอกาสน้อยที่คุณจะสร้างความเสียหายร้ายแรง แต่การเสี่ยงต่อปัญหาโดยไม่รู้ตัวไม่ใช่หนทางที่จะไป

ปัญหา

ฉันต้องการสร้างพอดแคสต์ใหม่ การออกแบบไม่ใช่ที่ที่ฉันต้องการ และฉันเกลียดวิธีเผยแพร่โพสต์ใหม่ ประณาม WYSIWYG! บริบทเล็กน้อย ประมาณสองปีที่แล้ว ฉันสร้างพอดแคสต์เวอร์ชันแรกของฉัน แนวคิดคือการเล่นกับ Sinatra และสร้างบางสิ่งที่เบามาก ฉันพบปัญหาที่ไม่คาดคิดสองสามอย่างเนื่องจากฉันปรับแต่งทุกอย่างได้แทบทุกอย่าง

มาจาก Rails แน่นอนว่าเป็นการเดินทางเพื่อการศึกษาที่ฉันซาบซึ้ง แต่ฉันรู้สึกเสียใจอย่างรวดเร็วที่ไม่ได้ใช้ไซต์แบบคงที่ที่ฉันสามารถปรับใช้ผ่าน GitHub ผ่านหน้า GitHub ได้ การปรับใช้ตอนใหม่และการบำรุงรักษานั้นขาดความเรียบง่ายที่ฉันต้องการ อยู่พักหนึ่ง ฉันตัดสินใจว่าฉันมีปลาตัวใหญ่กว่าที่จะทอดและมุ่งเน้นไปที่การผลิตสื่อพอดคาสต์ใหม่แทน

ฤดูร้อนที่ผ่านมานี้ ฉันเริ่มจริงจังและทำงานบนไซต์คนกลางที่โฮสต์ผ่านหน้า GitHub สำหรับซีซันที่สองของการแสดง ฉันต้องการอะไรที่สดใหม่ การออกแบบใหม่ที่เรียบง่าย Markdown สำหรับการเผยแพร่ตอนใหม่ และไม่มีการต่อสู่กับ Heroku—สวรรค์! ประเด็นคือฉันมี 139 ตอนที่วางอยู่รอบ ๆ ซึ่งจำเป็นต้องนำเข้าและดัดแปลงก่อนเพื่อที่จะทำงานร่วมกับคนกลาง

สำหรับการโพสต์ คนกลางใช้ .markdown ไฟล์ที่เรียกว่า frontmatter สำหรับข้อมูล ซึ่งมาแทนที่ฐานข้อมูลของฉันโดยพื้นฐาน การโอนด้วยมือไม่ใช่ตัวเลือกสำหรับ 139 ตอน นั่นคือสิ่งที่การคำนวณมีไว้สำหรับ ฉันต้องการหาวิธีแยกวิเคราะห์ HTML ของเว็บไซต์เก่าของฉัน ขูดเนื้อหาที่เกี่ยวข้อง และโอนไปยังบล็อกโพสต์ที่ฉันใช้เพื่อเผยแพร่ตอนพอดแคสต์ใหม่ใน Middleman

ดังนั้น ในอีกสามบทความถัดไป ฉันจะแนะนำคุณเกี่ยวกับเครื่องมือที่ใช้กันทั่วไปใน Rubyland สำหรับงานดังกล่าว ในท้ายที่สุด เราจะมาดูวิธีแก้ปัญหาของฉันเพื่อแสดงให้คุณเห็นถึงสิ่งที่ใช้ได้จริงเช่นกัน

โนโคกิริ

แม้ว่าคุณจะยังใหม่กับ Ruby/Rails เลยก็ตาม มีโอกาสที่ดีที่คุณเคยได้ยินเกี่ยวกับอัญมณีเล็กๆ นี้มาแล้ว ชื่อนี้หลุดบ่อยและติดคุณอย่างง่ายดาย ฉันไม่แน่ใจว่าหลายคนรู้ว่า nokogiri เป็นภาษาญี่ปุ่นสำหรับ "เลื่อย"

เป็นชื่อที่เหมาะสมเมื่อคุณเข้าใจว่าเครื่องมือนี้ทำอะไร ผู้สร้างอัญมณีนี้คือแอรอน แพตเตอร์สัน เทนเดอร์เลิฟผู้น่ารัก Nokogiri แปลงเอกสาร XML และ HTML ให้เป็นโครงสร้างข้อมูล ซึ่งเป็นโครงสร้างข้อมูลแบบต้นไม้ เพื่อให้แม่นยำยิ่งขึ้น เครื่องมือนี้รวดเร็วและมีอินเทอร์เฟซที่ดีเช่นกัน โดยรวมแล้ว มันเป็นห้องสมุดที่มีศักยภาพมากที่ดูแลความต้องการการขูด HTML จำนวนมากของคุณ

คุณสามารถใช้ Nokogiri ไม่เพียงแต่สำหรับการแยกวิเคราะห์ HTML เท่านั้น XML เป็นเกมที่ยุติธรรมเช่นกัน มันให้ตัวเลือกแก่คุณทั้งภาษาพาธ XML และอินเทอร์เฟซ CSS เพื่อสำรวจเอกสารที่คุณโหลด ภาษาเส้นทาง XML หรือ XPath สั้น ๆ เป็นภาษาแบบสอบถาม

ช่วยให้เราเลือกโหนดจากเอกสาร XML ตัวเลือก CSS มักจะคุ้นเคยกับผู้เริ่มต้นมากกว่า เช่นเดียวกับสไตล์ที่คุณเขียน ตัวเลือก CSS ทำให้ง่ายต่อการกำหนดเป้าหมายเฉพาะส่วนของหน้าที่สนใจสำหรับการดึงข้อมูล คุณเพียงแค่ต้องให้ Nokogiri รู้ว่าคุณกำลังตามหาอะไรเมื่อคุณกำหนดเป้าหมายไปยังจุดหมายปลายทางที่เฉพาะเจาะจง

หน้า

สิ่งที่เราจำเป็นต้องเริ่มต้นเสมอคือการดึงหน้าจริงที่เราสนใจ เราระบุประเภทของเอกสาร Nokogiri ที่เราต้องการแยกวิเคราะห์ เช่น XML หรือ HTML:

Nokogiri::XML

Nokogiri::HTML

some_scraper.rb

require "nokogiri"

require "open-uri"

page = Nokogiri::XML(File.open("some.xml"))

page = Nokogiri::HTML(File.open("some.html"))

Nokogiri:XML และ Nokogiri:HTML สามารถนำวัตถุ IO หรือวัตถุสตริง สิ่งที่เกิดขึ้นข้างต้นตรงไปตรงมา การดำเนินการนี้จะเปิดขึ้นและเรียกหน้าเว็บที่กำหนดโดยใช้ open-uri แล้วโหลดโครงสร้าง XML หรือ HTML ลงในเอกสาร Nokogiri ใหม่ XML ไม่ใช่สิ่งที่ผู้เริ่มต้นต้องรับมือบ่อยๆ

ดังนั้น เราขอแนะนำให้คุณเน้นที่การแยกวิเคราะห์ HTML ในตอนนี้ ทำไมต้อง open-uri ? โมดูลนี้จาก Ruby Standard Library ช่วยให้เราคว้าไซต์ได้โดยไม่ยุ่งยากมากนัก เนื่องจากวัตถุ IO เป็นเกมที่ยุติธรรม เราจึงสามารถใช้ open-uri . ได้ง่าย .

API

มาลองทำสิ่งนี้ด้วยตัวอย่างสั้นๆ:

at_css

some_podcast_scraper.rb

require 'nokogiri'

require "open-uri"

url = 'https://betweenscreens.fm/'

page = Nokogiri::HTML(open(url))

header = page.at_css("h2.post-title")

title = header.text

puts "This is the raw header of the latest episode: #{header}"

puts "This is the title of the latest episode: #{title}"

สิ่งที่เราทำที่นี่แสดงถึงขั้นตอนทั้งหมดที่มักเกี่ยวข้องกับการขูดเว็บ—แค่ในระดับจุลภาค เราตัดสินใจว่าเราต้องการ URL ใดและต้องดึงข้อมูลเว็บไซต์ใด และโหลดลงในเอกสาร Nokogiri ฉบับใหม่ จากนั้นเราจะเปิดหน้านั้นและกำหนดเป้าหมายเฉพาะส่วน

ที่นี่ฉันเพียงต้องการทราบชื่อตอนล่าสุด การใช้ at_css เมธอดและตัวเลือก CSS สำหรับ h2.post-title คือสิ่งที่ฉันต้องการเพื่อกำหนดเป้าหมายไปยังจุดสกัด ด้วยวิธีนี้เราจะขูดองค์ประกอบเอกพจน์นี้เท่านั้น สิ่งนี้ทำให้เรามีตัวเลือกทั้งหมด—ซึ่งโดยส่วนใหญ่ไม่ใช่สิ่งที่เราต้องการ ดังนั้นเราจึงแยกเฉพาะส่วนข้อความภายในของโหนดนี้ผ่าน text กระบวนการ. สำหรับการเปรียบเทียบ คุณสามารถตรวจสอบผลลัพธ์ของทั้งส่วนหัวและข้อความด้านล่างได้

ผลลัพธ์

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

This is the title of the latest episode: David Heinemeier Hansson

แม้ว่าตัวอย่างนี้มีการใช้งานที่จำกัด แต่ก็มีส่วนประกอบทั้งหมด รวมถึงขั้นตอนทั้งหมดที่คุณต้องเข้าใจ ฉันคิดว่ามันง่ายมากที่มันง่าย เนื่องจากอาจไม่ชัดเจนจากตัวอย่างนี้ ฉันอยากจะชี้ให้เห็นว่าเครื่องมือนี้มีประสิทธิภาพเพียงใด มาดูกันว่าเราจะทำอะไรกับสคริปต์ Nokogiri ได้อีก

โปรดทราบ!

หากคุณเป็นมือใหม่และไม่แน่ใจว่าจะกำหนดเป้าหมาย HTML ที่จำเป็นสำหรับสิ่งนี้อย่างไร เราขอแนะนำให้คุณค้นหาทางออนไลน์เพื่อดูวิธีตรวจสอบเนื้อหาของเว็บไซต์ในเบราว์เซอร์ของคุณ โดยทั่วไป เบราว์เซอร์หลักทั้งหมดทำให้กระบวนการนี้ง่ายจริงๆ ในทุกวันนี้

ใน Chrome คุณเพียงแค่คลิกขวาที่องค์ประกอบในเว็บไซต์และเลือกตัวเลือกการตรวจสอบ การดำเนินการนี้จะเปิดหน้าต่างเล็กๆ ที่ด้านล่างของเบราว์เซอร์ ซึ่งจะแสดงบางอย่างให้คุณเห็น เช่น ภาพเอ็กซ์เรย์ของ DOM ของไซต์ มีตัวเลือกอีกมากมาย และฉันขอแนะนำให้ใช้เวลากับ Google เพื่อให้ความรู้กับตัวเอง นี่คือเวลาที่ใช้อย่างชาญฉลาด!

css

css เมธอดจะไม่เพียงแต่ให้องค์ประกอบทางเลือกเดียวแก่เราเท่านั้น แต่ยังมีองค์ประกอบใดๆ ที่ตรงกับเกณฑ์การค้นหาในหน้าอีกด้วย ค่อนข้างเรียบร้อยและตรงไปตรงมา!

some_scraper.rb

require 'nokogiri'

require "open-uri"

url = 'https://betweenscreens.fm/'

page = Nokogiri::HTML(open(url))

headers = page.css("h2.post-title")

headers.each do |header|
  puts "This is the raw title of the latest episode: #{header}"
end

headers.each do |header|
  puts "This is the title of the latest episode: #{header.text}"
end

ผลลัพธ์

This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/142/">David Heinemeier Hansson</a></h2>
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/141/">Zach Holman</a></h2>
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/140/">Joel Glovier</a></h2>
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/139/">João Ferreira</a></h2>
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/138/">Corwin Harrell</a></h2>
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/137/">Roberto Machado</a></h2>
This is the raw title of the latest episode: <h2 class="post-title"><a href="episodes/136/">James Edward Gray II</a></h2>

This is the title of the latest episode: David Heinemeier Hansson
This is the title of the latest episode: Zach Holman
This is the title of the latest episode: Joel Glovier
This is the title of the latest episode: João Ferreira
This is the title of the latest episode: Corwin Harrell
This is the title of the latest episode: Roberto Machado
This is the title of the latest episode: James Edward Gray II

ความแตกต่างเพียงเล็กน้อยในตัวอย่างนี้คือฉันวนซ้ำในส่วนหัวดิบก่อน ฉันยังแยกข้อความด้านในด้วย text กระบวนการ. Nokogiri จะหยุดโดยอัตโนมัติที่ส่วนท้ายของหน้าและไม่พยายามติดตามการแบ่งหน้าโดยอัตโนมัติ

สมมติว่าเราต้องการข้อมูลเพิ่มเติมอีกเล็กน้อย เช่น วันที่และคำบรรยายของแต่ละตอน เราสามารถขยายตัวอย่างข้างต้นได้ เป็นความคิดที่ดีที่จะทำตามขั้นตอนนี้ ทำงานเล็ก ๆ น้อย ๆ และเพิ่มความซับซ้อนไปพร้อมกัน

some_scraper.rb

require 'nokogiri'

require "open-uri"

url = 'https://betweenscreens.fm/'

page = Nokogiri::HTML(open(url))

articles = page.css("article.index-article")

articles.each do |article|
  header     = article.at_css("h2.post-title")
  date       = article.at_css(".post-date")
  subtitle   = article.at_css(".topic-list")

  puts "This is the raw header:    #{header}"
  puts "This is the raw date:      #{date}"
  puts "This is the raw subtitle:  #{subtitle}\n\n"
 
  puts "This is the text header:   #{header.text}"
  puts "This is the text date:     #{date.text}"
  puts "This is the text subtitle: #{subtitle.text}\n\n"
end

ผลลัพธ์

This is the raw header: <h2 class="post-title"><a href="episodes/142/">David Heinemeier Hansson</a></h2>
This is the raw date: <span class="post-date">Oct 18 | 2016</span>
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>

This is the text header: David Heinemeier Hansson
This is the text date: Oct 18 | 2016
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

This is the raw header: <h2 class="post-title"><a href="episodes/141/">Zach Holman</a></h2>
This is the raw date: <span class="post-date">Oct 12 | 2016</span>
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>

This is the text header: Zach Holman
This is the text date: Oct 12 | 2016
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

This is the raw header: <h2 class="post-title"><a href="episodes/140/">Joel Glovier</a></h2>
This is the raw date: <span class="post-date">Oct 10 | 2016</span>
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>

This is the text header: Joel Glovier
This is the text date: Oct 10 | 2016
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

This is the raw header: <h2 class="post-title"><a href="episodes/139/">João Ferreira</a></h2>
This is the raw date: <span class="post-date">Aug 26 | 2015</span>
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>

This is the text header: João Ferreira
This is the text date: Aug 26 | 2015
This is the text subtitle: Masters @ Work | Subvisual | Deadlines | Design personality | Design problems | Team | Pushing envelopes | Delightful experiences | Perfecting details | Company values

This is the raw header: <h2 class="post-title"><a href="episodes/138/">Corwin Harrell</a></h2>
This is the raw date: <span class="post-date">Aug 06 | 2015</span>
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>

This is the text header: Corwin Harrell
This is the text date: Aug 06 | 2015
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 |

This is the raw header: <h2 class="post-title"><a href="episodes/137/">Roberto Machado</a></h2>
This is the raw date: <span class="post-date">Aug 03 | 2015</span>
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>

This is the text header: Roberto Machado
This is the text date: Aug 03 | 2015
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

This is the raw header: <h2 class="post-title"><a href="episodes/136/">James Edward Gray II</a></h2>
This is the raw date: <span class="post-date">Jul 30 | 2015</span>
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>

This is the text header: James Edward Gray II
This is the text date: Jul 30 | 2015
This is the text subtitle: Screencasting | Less Code | Reading code | Getting unstuck | Rails’s codebase | CodeNewbie | Small examples | Future plans | PeepCode | Frequency & pricing

ณ จุดนี้ เรามีข้อมูลให้เล่นอยู่แล้ว เราสามารถจัดโครงสร้างหรือแล่เนื้อได้ตามต้องการ ข้างต้นควรแสดงสิ่งที่เรามีในรูปแบบที่สามารถอ่านได้ แน่นอน เราสามารถเจาะลึกลงไปในแต่ละสิ่งเหล่านี้ได้โดยใช้นิพจน์ทั่วไปที่มี text กระบวนการ.

เราจะพิจารณาในรายละเอียดมากกว่านี้เมื่อเราได้แก้ไขปัญหาพอดคาสต์จริง จะไม่ใช่คลาสใน regexp แต่คุณจะเห็นการใช้งานจริงมากกว่านี้ แต่ไม่ต้องกังวล ไม่มากเท่ากับทำให้สมองของคุณตกเลือด

คุณสมบัติ

สิ่งที่น่าจะสะดวกในขั้นตอนนี้คือการแยก href สำหรับแต่ละตอนด้วย ไม่มีอะไรง่ายไปกว่านี้แล้ว

some_scraper.rb

require 'nokogiri'

require "open-uri"

url = 'https://betweenscreens.fm/'

page = Nokogiri::HTML(open(url))

articles = page.css("article.index-article")

articles.each do |article|
  header      = article.at_css("h2.post-title")
  date        = article.at_css(".post-date")
  subtitle    = article.at_css(".topic-list")
  link        = article.at_css("h2.post-title a")
  podcast_url = "https://betweenscreens.fm/"

  puts "This is the raw header:    #{header}"
  puts "This is the raw date:      #{date}"
  puts "This is the raw subtitle:  #{subtitle}"
  puts "This is the raw link:      #{link}\n\n"

  puts "This is the text header:   #{header.text}"
  puts "This is the text date:     #{date.text}"
  puts "This is the text subtitle: #{subtitle.text}"
  puts "This is the raw link:      #{podcast_url}#{link[:href]}\n\n"
end

บิตที่สำคัญที่สุดที่ต้องให้ความสนใจคือ [:href] และ podcast_url . หากคุณแท็ก [:] คุณสามารถแยกแอตทริบิวต์จากตัวเลือกเป้าหมายได้ ฉันสรุปเพิ่มเติมเล็กน้อย แต่คุณสามารถเห็นได้ชัดเจนยิ่งขึ้นว่ามันทำงานอย่างไรที่ด้านล่าง

...

href = article.at_css("h2.post-title a")[:href]

...

เพื่อให้ได้ URL ที่สมบูรณ์และมีประโยชน์ ฉันได้บันทึกโดเมนรากในตัวแปรและสร้าง URL แบบเต็มสำหรับแต่ละตอน

...

podcast_url = "https://betweenscreens.fm/"

puts "This is the raw link: #{podcast_url}#{link[:href]}\n\n"

...

มาดูผลลัพธ์กันอย่างรวดเร็ว:

ผลลัพธ์

This is the raw header:   <h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
This is the raw date:     <span class="post-date">Oct 25 | 2016</span>
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>
This is the raw link:     <a href="episodes/143/">Jason Long</a>

This is the text header: Jason Long
This is the text date:   Oct 25 | 2016
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
This is the href:     https://betweenscreens.fm/episodes/143/

This is the raw header:   <h2 class="post-title"><a href="episodes/142/">David Heinemeier Hansson</a></h2>
This is the raw date:     <span class="post-date">Oct 18 | 2016</span>
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>
This is the raw link:     <a href="episodes/142/">David Heinemeier Hansson</a>

This is the text header: David Heinemeier Hansson
This is the text date:   Oct 18 | 2016
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
This is the href:     https://betweenscreens.fm/episodes/142/

This is the raw header:   <h2 class="post-title"><a href="episodes/141/">Zach Holman</a></h2>
This is the raw date:     <span class="post-date">Oct 12 | 2016</span>
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>
This is the raw link:     <a href="episodes/141/">Zach Holman</a>

This is the text header: Zach Holman
This is the text date:   Oct 12 | 2016
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
This is the href:     https://betweenscreens.fm/episodes/141/

This is the raw header:   <h2 class="post-title"><a href="episodes/140/">Joel Glovier</a></h2>
This is the raw date:     <span class="post-date">Oct 10 | 2016</span>
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>
This is the raw link:     <a href="episodes/140/">Joel Glovier</a>

This is the text header: Joel Glovier
This is the text date:   Oct 10 | 2016
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
This is the href:     https://betweenscreens.fm/episodes/140/

This is the raw header:   <h2 class="post-title"><a href="episodes/139/">João Ferreira</a></h2>
This is the raw date:     <span class="post-date">Aug 26 | 2015</span>
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>
This is the raw link:     <a href="episodes/139/">João Ferreira</a>

This is the text header: João Ferreira
This is the text date:   Aug 26 | 2015
This is the text subtitle: Masters @ Work | Subvisual | Deadlines | Design personality | Design problems | Team | Pushing envelopes | Delightful experiences | Perfecting details | Company values
This is the href:     https://betweenscreens.fm/episodes/139/

This is the raw header:   <h2 class="post-title"><a href="episodes/138/">Corwin Harrell</a></h2>
This is the raw date:     <span class="post-date">Aug 06 | 2015</span>
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>
This is the raw link:     <a href="episodes/138/">Corwin Harrell</a>

This is the text header: Corwin Harrell
This is the text date:   Aug 06 | 2015
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 |
This is the href:     https://betweenscreens.fm/episodes/138/

This is the raw header:   <h2 class="post-title"><a href="episodes/137/">Roberto Machado</a></h2>
This is the raw date:     <span class="post-date">Aug 03 | 2015</span>
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>
This is the raw link:     <a href="episodes/137/">Roberto Machado</a>

This is the text header: Roberto Machado
This is the text date:   Aug 03 | 2015
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
This is the href:     https://betweenscreens.fm/episodes/137/

เรียบร้อยใช่มั้ย คุณสามารถทำเช่นเดียวกันเพื่อแยก [:class] ของตัวเลือก

require 'nokogiri'

require "open-uri"

url = 'https://betweenscreens.fm/'

page = Nokogiri::HTML(open(url))

body_classes = page.at_css("body")[:class]

หากโหนดนั้นมีมากกว่าหนึ่งคลาส คุณจะได้รับรายการทั้งหมด

การนำทางโหนด

  • ผู้ปกครอง
  • เด็กๆ
  • previous_sibling
  • next_sibling

เราใช้ในการจัดการกับโครงสร้างต้นไม้ใน CSS หรือแม้แต่ jQuery คงจะเป็นเรื่องที่เจ็บปวดหาก Nokogiri ไม่ได้เสนอ API ที่สะดวกในการเคลื่อนย้ายภายในต้นไม้ดังกล่าว

some_scraper.rb

require 'nokogiri'

require "open-uri"

url = 'https://betweenscreens.fm/'

page = Nokogiri::HTML(open(url))

header = page.at_css("h2.post-title")
header_children = page.at_css("h2.post-title").children
header_parent = page.at_css("h2.post-title").parent
header_prev_sibling = page.at_css("h2.post-title").previous_sibling

puts "#{header}\n\n"
puts "#{header_children}\n\n"
puts "#{header_parent}\n\n"
puts "#{header_prev_sibling}\n\n"

ผลลัพธ์

#header
<h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>

#header_children
<a href="episodes/143/">Jason Long</a>

#header_parent
<article class="index-article">
  <span class="post-date">Oct 25 | 2016</span><h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
    <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>
    <div class="soundcloud-player-small">  
    </div>
</article>

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

อย่างที่คุณเห็นเอง นี่คือสิ่งที่ทรงพลังมาก โดยเฉพาะอย่างยิ่งเมื่อคุณเห็นอะไร .parent สามารถสะสมได้ในครั้งเดียว แทนที่จะกำหนดโหนดจำนวนมากด้วยมือ คุณสามารถรวบรวมโหนดแบบขายส่งได้

คุณยังสามารถเชื่อมโยงพวกมันเพื่อสำรวจเส้นทางที่เกี่ยวข้องได้มากขึ้น คุณสามารถใช้สิ่งนี้ซับซ้อนเท่าที่คุณต้องการ แต่ฉันขอเตือนคุณให้ทำสิ่งต่าง ๆ ให้เรียบง่าย มันอาจจะค่อนข้างเทอะทะและเข้าใจยากอย่างรวดเร็ว จำไว้ว่า "พูดง่ายๆ ว่าโง่!"

...

header_parent_parent = page.at_css("h2.post-title").parent.parent
header_prev_sibling_parent_children = page.at_css("h2.post-title").previous_sibling.parent.children

...

some_scraper.rb

require 'nokogiri'

require "open-uri"

url = 'https://betweenscreens.fm/'

page = Nokogiri::HTML(open(url))

header = page.at_css("h2.post-title")
header_prev_sibling_children = page.at_css("h2.post-title").previous_sibling.children
header_parent_parent = page.at_css("h2.post-title").parent.parent
header_prev_sibling_parent = page.at_css("h2.post-title").previous_sibling.parent
header_prev_sibling_parent_children = page.at_css("h2.post-title").previous_sibling.parent.children

puts "#{header}\n\n"
puts "#{header_prev_sibling_children}\n\n"
puts "#{header_parent_parent}\n\n"
puts "#{header_prev_sibling_parent}\n\n"
puts "#{header_prev_sibling_parent_children}\n\n"

ผลลัพธ์

#header
<h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>

#header_previous_sibling_children
Oct 25 | 2016

#header_parent_parent
<li>
  <article class="index-article">
  <span class="post-date">Oct 25 | 2016</span><h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
    <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>
    <div class="soundcloud-player-small">  
    </div>
  </article>
</li>

#header_previous_sibling_parent
<article class="index-article">
  <span class="post-date">Oct 25 | 2016</span><h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
    <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>
    <div class="soundcloud-player-small">  
    </div>
</article>

#header_previous_sibling_parent_children
  <span class="post-date">Oct 25 | 2016</span><h2 class="post-title"><a href="episodes/143/">Jason Long</a></h2>
    <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>
    <div class="soundcloud-player-small">  
    </div>

Final Thoughts

Nokogiri is not a huge library, but it has a lot to offer. I recommend you play with what you have learned thus far and expand your knowledge through its documentation when you hit a wall. But don’t get yourself into trouble!

This little intro should get you well on your way to understanding what you can do and how it works. I hope you will explore it a bit more on your own and have some fun with it. As you will find out on your own, it’s a rich tool that keeps on giving.