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 & 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 & Chaos | Drawing | Web Design | HospitalRun | Diversity | Startup Culture | Improving Lives | CURE International | Ember | Offline First | Hospital Information System | Designers & 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&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> 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 & 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 & 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 & 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 & Chaos | Drawing | Web Design | HospitalRun | Diversity | Startup Culture | Improving Lives | CURE International | Ember | Offline First | Hospital Information System | Designers & 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&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> 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 & 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>
ความคิดสุดท้าย
Nokogiri ไม่ใช่ห้องสมุดขนาดใหญ่ แต่มีหลายสิ่งให้คุณเลือก ฉันแนะนำให้คุณเล่นกับสิ่งที่คุณได้เรียนรู้ไปแล้วและขยายความรู้ของคุณผ่านเอกสารประกอบเมื่อคุณชนกำแพง แต่อย่าทำให้ตัวเองเดือดร้อน!
บทนำเล็กๆ นี้จะช่วยให้คุณเข้าใจถึงสิ่งที่คุณทำได้และวิธีการทำงาน ฉันหวังว่าคุณจะสำรวจมันด้วยตัวเองอีกสักหน่อยและสนุกไปกับมัน คุณจะค้นพบด้วยตัวเองว่าเป็นเครื่องมือมากมายที่มอบให้เสมอ