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

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

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

หัวข้อ

  • ขูดพอดแคสต์ของฉัน
  • แงะ
  • มีดโกน
  • วิธีการช่วยเหลือ
  • เขียนกระทู้

ขูดพอดคาสต์ของฉัน

นำสิ่งที่เราได้เรียนรู้มาปฏิบัติจริง ด้วยเหตุผลหลายประการ การออกแบบใหม่สำหรับพอดแคสต์ของฉัน ระหว่าง | หน้าจอค้างนานเกินไป มีปัญหาที่ทำให้ฉันกรีดร้องเมื่อตื่นนอนตอนเช้า ดังนั้นฉันจึงตัดสินใจตั้งค่าไซต์สแตติกใหม่ทั้งหมด สร้างด้วย Middleman และโฮสต์ด้วย GitHub Pages

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

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

ด้านล่างนี้เป็นภาพหน้าจอสองภาพจากพอดแคสต์ของฉัน

สกรีนช็อตเก่าพอดคาสต์

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

สกรีนช็อตพอดแคสต์ใหม่

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

มาทำลายสิ่งที่เราต้องการทำให้สำเร็จ เราต้องการดึงข้อมูลต่อไปนี้จาก 139 ตอนที่กระจายไปทั่วไซต์ดัชนีที่มีเลขหน้า 21 แห่ง:

  • ชื่อเรื่อง
  • ผู้ให้สัมภาษณ์
  • หัวข้อย่อยที่มีรายการหัวข้อ
  • หมายเลขแทร็กของ SoundCloud สำหรับแต่ละตอน
  • วันที่
  • หมายเลขตอน
  • ข้อความจากบันทึกการแสดง
  • ลิงค์จากบันทึกการแสดง

เราวนซ้ำผ่านการแบ่งหน้าและให้ Mechanize คลิกทุกลิงก์ของตอน ในหน้ารายละเอียดต่อไปนี้ เราจะพบข้อมูลทั้งหมดจากด้านบนที่เราต้องการ การใช้ข้อมูลที่คัดลอกมานั้น เราต้องการเติมข้อมูลส่วนหน้าและ "เนื้อหา" ของไฟล์มาร์กดาวน์สำหรับแต่ละตอน

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

def compose_markdown

def compose_markdown(options={})<<-HEREDOC--- title:#{options[:interviewee]}ผู้สัมภาษณ์:#{options[:interviewee]}topic_list:#{options[:title]}tags:#{ตัวเลือก[:แท็ก]}soundcloud_id:#{ตัวเลือก[:sc_id]}วันที่:#{ตัวเลือก[:วันที่]}หมายเลขตอน:#{ตัวเลือก[:episode_number]}---#{ตัวเลือก[:ข้อความ]}HEREDOCend 

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

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

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

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

โค้ดเต็ม

ต้องการ 'Mechanize'require 'Pry'require 'date'# Helper Methods# (Extraction Methods)def extract_interviewee(detail_page) interviewee_selector ='.episode_sub_title span' detail_page.search(interviewee_selector).text.stripenddef_title(detail_page) title =".episode_title" detail_page.search(title_selector).text.gsub(/[?#]/, '')enddef extract_soundcloud_id(detail_page) sc =detail_page.iframes_with(href:/soundcloud.com/).to_s sc.scan (/\d{3,}/).firstenddef extract_shownotes_text(detail_page) shownote_selector ="#shownote_container> p" detail_page.search(shownote_selector)enddef extract_subtitle(detail_page) subheader_selector =".episode_sub_title" detail_page.search(subheader_selector) (episode_subtitle) number =/[#]\d*/.match(episode_subtitle) clean_episode_number(number)end# (วิธียูทิลิตี้)def clean_date(episode_subtitle) string_date =/[^|]*([,])(... ..)/.match(episode_subtitle).to_s Date.parse(string_date)สิ้นสุดวันที่ f build_tags(หัวเรื่อง, ผู้ให้สัมภาษณ์) extracted_tags =strip_pipes(หัวเรื่อง) "#{interviewee}"+ ", #{extracted_tags}"enddef strip_pipes(text) tags =text.tr('|', ',') tags =tags gsub(/[@?#&]/, '') tags.gsub(/[w\/]{2}/, 'with')enddef clean_episode_number(number) number.to_s.tr('#', '' )enddef dasherize(ข้อความ) text.lstrip.rstrip.tr(' ', '-')enddef extract_data(detail_page) ผู้สัมภาษณ์ =extract_interviewee(detail_page) title =extract_title (detail_page) sc_id =extract_soundcloud_id (detail_page) text =extract_shownotes_text (detail_page) episode_subtitle =extract_subtitle (detail_page) episode_number =extract_episode_number (episode_subtitle) วันที่ =clean_date (episode_subtitle) tags =build_tags (ชื่อผู้สัมภาษณ์) ตัวเลือก ={ ผู้สัมภาษณ์:ผู้สัมภาษณ์, ชื่อ:title, sc_id:sc_id, ข้อความ:ข้อความ, แท็ก:แท็ก, วันที่ :date, episode_number:episode_number }enddef compose_markdown(options={})<<-HEREDOC--- title:#{ตัวเลือก s[:interviewee]}ผู้สัมภาษณ์:#{options[:interviewee]}topic_list:#{options[:title]}tags:#{options[:tags]}soundcloud_id:#{options[:sc_id]}วันที่:#{ options[:date]}episode_number:#{options[:episode_number]}---#{options[:text]}HEREDOCenddef write_page(link) detail_page =link.click extracted_data =extract_data(detail_page) markdown_text =compose_markdown(extracted_data) วันที่ =extracted_data[:date] ผู้ให้สัมภาษณ์ =extracted_data[:interviewee] episode_number =extracted_data[:episode_number] File.open("#{date}-#{dasherize(interviewee)}-#{episode_number}.html.erb.md", 'w') { |ไฟล์| file.write(markdown_text) }enddef ขูด link_range =1 ตัวแทน ||=Mechanize.new จนถึง link_range ==21 หน้า =agent.get("https://between-screens.herokuapp.com/?page=#{link_range} ") link_range +=1 page.links[2..8].map do |link| write_page(ลิงค์) สิ้นสุด endendscrape

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

แงะ

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

หากคุณวาง Pry.start(binding) ทุกที่ในรหัสของคุณ คุณสามารถตรวจสอบใบสมัครของคุณได้ ณ จุดนั้น คุณสามารถงัดวัตถุที่จุดเฉพาะในแอปพลิเคชัน สิ่งนี้มีประโยชน์มากในการสมัครของคุณทีละขั้นตอนโดยไม่สะดุดเท้าของคุณเอง ตัวอย่างเช่น ให้วางไว้หลัง write_page . ของเรา และตรวจสอบว่า link คือสิ่งที่เราคาดหวัง

แงะ

...def ขูด link_range =1 ตัวแทน ||=Mechanize.new จนถึง link_range ==21 หน้า =agent.get("https://between-screens.herokuapp.com/?page=#{link_range}" ) link_range +=1 page.links[2..8].map do |link| write_page(ลิงก์) Pry.start(การผูก) ปลายสิ้นสุด...

หากคุณเรียกใช้สคริปต์ เราจะได้รับสิ่งนี้

ผลลัพธ์

»$ ruby ​​noko_scraper.rb 321:def scrape 322:link_range =1 323:agent ||=Mechanize.new 324:326:จนถึง link_range ==21 327:หน้า =agent.get("https://between -screens.herokuapp.com/?page=#{link_range}") 328:link_range +=1 329:330:page.links[2..8].map do |link| 331:write_page(link) => 332:Pry.start(binding) 333:end 334:end 335:end[1] pry(main)>

เมื่อเราถามหา link วัตถุ เราสามารถตรวจสอบว่าเราอยู่ในเส้นทางที่ถูกต้องหรือไม่ก่อนที่เราจะไปยังรายละเอียดการใช้งานอื่น ๆ

เทอร์มินัล

[2] pry(main)> link=> #

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

เครื่องขูด

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

podcast_scraper.rb

...def write_page(link) detail_page =link.click extracted_data =extract_data(detail_page) markdown_text =compose_markdown(extracted_data) date =extracted_data[:date] ผู้สัมภาษณ์ =extracted_data[:interviewee] episode_number =extracted_data[:episode_number] file_name ="#{วันที่}-#{dasherize(ผู้สัมภาษณ์)}-#{episode_number}.html.erb.md" File.open(file_name, 'w') { |file| file.write(markdown_text) }enddef ขูด link_range =1 ตัวแทน ||=Mechanize.new จนถึง link_range ==21 หน้า =agent.get("https://between-screens.herokuapp.com/?page=#{link_range} ") link_range +=1 page.links[2..8].map do |link| write_page(ลิงค์) สิ้นสุด สิ้นสุด...

จะเกิดอะไรขึ้นใน scrape กระบวนการ? ก่อนอื่น ฉันวนซ้ำทุกหน้าดัชนีในพอดคาสต์เก่า ฉันใช้ URL เก่าจากแอป Heroku เนื่องจากไซต์ใหม่ออนไลน์อยู่ที่ betweenscreens.fm แล้ว ฉันมี 20 ตอนที่ฉันต้องวนซ้ำ

ฉันคั่นการวนซ้ำผ่าน link_range ตัวแปรซึ่งฉันอัปเดตด้วยแต่ละลูป การผ่านการแบ่งหน้านั้นง่ายพอๆ กับการใช้ตัวแปรนี้ใน URL ของแต่ละหน้า เรียบง่ายและมีประสิทธิภาพ

ขูดหินปูน

page =agent.get("https://between-screens.herokuapp.com/?page=#{link_range}")

จากนั้น เมื่อใดก็ตามที่ฉันมีหน้าใหม่ที่มีอีกแปดตอนให้ขูด ฉันใช้ page.links เพื่อระบุลิงก์ที่เราต้องการคลิกและติดตามไปยังหน้ารายละเอียดสำหรับแต่ละตอน ฉันตัดสินใจเลือกลิงก์ต่างๆ (links[2..8] ) เนื่องจากมีความสอดคล้องกันในทุกหน้า นอกจากนี้ยังเป็นวิธีที่ง่ายที่สุดในการกำหนดเป้าหมายลิงก์ที่ฉันต้องการจากหน้าดัชนีแต่ละหน้า ไม่จำเป็นต้องคลำหาตัวเลือก CSS ที่นี่

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

defwrite_page

extracted_data =extract_data(detail_page)

def extract_data

def extract_data(detail_page) ผู้ให้สัมภาษณ์ =extract_interviewee(detail_page) title =extract_title(detail_page) sc_id =extract_soundcloud_id(detail_page) text =extract_shownotes_text(detail_page) episode_subtitle =extract_subtitle(detail_page) episode_number =extract_episoden (วันที่ย่อย) =extract_episoden แท็ก =build_tags (ชื่อผู้ให้สัมภาษณ์) ตัวเลือก ={ ผู้สัมภาษณ์:ผู้สัมภาษณ์, ชื่อ:ชื่อ, sc_id:sc_id, ข้อความ:ข้อความ, แท็ก:แท็ก, วันที่:วันที่, ตอนที่_number:episode_number }สิ้นสุด

ดังที่คุณเห็นด้านบน เราใช้ detail_page และใช้วิธีการสกัดมากมาย เราแยก interviewee , title , sc_id , text , episode_title และ episode_number . ฉันปรับโครงสร้างวิธีการช่วยเหลือแบบเน้นๆ ขึ้นมาใหม่ ซึ่งมีหน้าที่รับผิดชอบในการดึงข้อมูลเหล่านี้ มาดูกันอย่างรวดเร็ว:

วิธีการช่วยเหลือ

วิธีการสกัด

ฉันแยกตัวช่วยเหล่านี้ออกเพราะมันทำให้ฉันมีวิธีโดยรวมที่เล็กกว่า การห่อหุ้มพฤติกรรมของพวกเขาก็มีความสำคัญเช่นกัน รหัสอ่านได้ดีขึ้นเช่นกัน ส่วนใหญ่ใช้ detail_page เป็นข้อโต้แย้งและดึงข้อมูลเฉพาะบางอย่างที่เราต้องการสำหรับการโพสต์คนกลางของเรา

def extract_interviewee(detail_page) interviewee_selector ='.episode_sub_title span' detail_page.search(interviewee_selector).text.stripend

เราค้นหาหน้าสำหรับตัวเลือกเฉพาะและรับข้อความโดยไม่มีช่องว่างที่ไม่จำเป็น

def extract_title(detail_page) title_selector =".episode_title" detail_page.search(title_selector).text.gsub(/[?#]/, '')end

เราใช้ชื่อและลบ ? และ # เนื่องจากสิ่งเหล่านี้ไม่ได้เล่นได้ดีกับประเด็นหน้าในโพสต์สำหรับตอนของเรา ข้อมูลเพิ่มเติมเกี่ยวกับเบื้องหน้าด้านล่าง

def extract_soundcloud_id(detail_page) sc =detail_page.iframes_with(href:/soundcloud.com/).to_s sc.scan(/\d{3,}/).firstend

ที่นี่เราต้องทำงานหนักขึ้นเล็กน้อยเพื่อแยก SoundCloud id สำหรับแทร็กที่โฮสต์ของเรา ก่อนอื่น เราต้องการ Mechanize iframes ด้วย href ของ soundcloud.com และทำเป็นสตริงสำหรับสแกน...

"[#\n]"

จากนั้นจับคู่นิพจน์ทั่วไปสำหรับตัวเลขของรหัสแทร็ก—soundcloud_id ของเรา "221003494" .

def extract_shownotes_text(detail_page) shownote_selector ="#shownote_container> p" detail_page.search(shownote_selector) สิ้นสุด

การแยกบันทึกการแสดงนั้นค่อนข้างตรงไปตรงมาอีกครั้ง เราต้องค้นหาเฉพาะย่อหน้าของบันทึกย่อในหน้ารายละเอียด ไม่มีความประหลาดใจที่นี่

def extract_subtitle(detail_page) subheader_selector =".episode_sub_title" detail_page.search(subheader_selector).textend

เช่นเดียวกับคำบรรยาย ยกเว้นว่าเป็นเพียงการเตรียมการแยกหมายเลขตอนออกจากมันอย่างหมดจด

def extract_episode_number(episode_subtitle) number =/[#]\d*/.match(episode_subtitle) clean_episode_number(number)end

ที่นี่เราต้องการนิพจน์ทั่วไปอีกรอบ มาดูก่อนและหลังเราใช้ regex กัน

episode_subtitle

" João Ferreira | 12 Minutes | 26 ส.ค. 2015 | ตอนที่ #139 

หมายเลข

"#139"

อีกก้าวเดียวก็จะได้เลขเด็ดแล้ว

def clean_episode_number(number) number.to_s.tr('#', '')end

เราใช้ตัวเลขนั้นพร้อมแฮช # และเอาออก เย้ๆ เรามีเลขตอนแรก 139 สกัดเช่นกัน ฉันแนะนำให้เราดูวิธียูทิลิตี้อื่น ๆ ด้วยก่อนที่เราจะนำมารวมกัน

วิธีอรรถประโยชน์

หลังจากทั้งหมดธุรกิจการสกัด เราก็มีบางอย่างที่ต้องทำ เราสามารถเริ่มเตรียมข้อมูลสำหรับเขียน markdown ได้แล้ว ตัวอย่างเช่น ฉันแบ่ง episode_subtitle บางอย่างเพื่อให้ได้วันที่สะอาดและสร้าง tags ด้วย build_tags กระบวนการ.

def clean_date

def clean_date(episode_subtitle) string_date =/[^|]*([,])(.....)/.match(episode_subtitle).to_s Date.parse(string_date)สิ้นสุด

เราเรียกใช้ regex อื่นที่ค้นหาวันที่เช่นนี้ "  Aug 26, 2015" . อย่างที่คุณเห็น สิ่งนี้ยังช่วยไม่ได้มาก จาก string_date ได้มาจากซับไตเติ้ล เราต้องสร้าง Date . ที่แท้จริง วัตถุ. มิฉะนั้นจะไม่มีประโยชน์สำหรับการสร้างโพสต์คนกลาง

string_date

" 26 ส.ค. 2558"

ดังนั้นเราจึงนำสตริงนั้นมาทำ Date.parse . ผลลัพธ์ดูมีแนวโน้มมากขึ้น

วันที่

2015-08-26

def build_tags

def build_tags(ชื่อผู้ให้สัมภาษณ์) extracted_tags =strip_pipes(title) "#{interviewee}"+ ", #{extracted_tags}"end

นี่ใช้ title และ interviewee เราได้สร้างขึ้นภายใน extract_data เมธอดและลบอักขระไปป์และขยะทั้งหมด เราแทนที่อักขระไปป์ด้วยเครื่องหมายจุลภาค @ , ? , # และ & ด้วยสตริงว่าง และสุดท้ายดูแลตัวย่อสำหรับ with .

def strip_pipes

แท็ก def strip_pipes(text) =text.tr('|', ',') tags =tags.gsub(/[@?#&]/, '') tags.gsub(/[w\/] {2}/, 'with')สิ้นสุด

ในตอนท้าย เราจะรวมชื่อผู้ให้สัมภาษณ์ในรายการแท็กด้วย และแยกแต่ละแท็กด้วยเครื่องหมายจุลภาค

ก่อนหน้านั้น

"ปรมาจารย์ @ ทำงาน | บรรยายย่อย | กำหนดเวลา | บุคลิกภาพด้านการออกแบบ | ปัญหาด้านการออกแบบ | ทีม | ผลักดันซองจดหมาย | ประสบการณ์ที่น่ายินดี | รายละเอียดที่สมบูรณ์แบบ | ค่านิยมของบริษัท"

หลัง

"João Ferreira, Masters Work , Subvisual , Deadlines , Design Personality , Design problems , Team , Pushing Envelope , Delightful experiences , Perfecting details , Company values"

แต่ละแท็กเหล่านี้จะกลายเป็นลิงก์ไปยังชุดของโพสต์สำหรับหัวข้อนั้น ทั้งหมดนี้เกิดขึ้นภายใน extract_data กระบวนการ. มาดูกันว่าเราอยู่ที่ไหน:

def extract_data

def extract_data(detail_page) ผู้ให้สัมภาษณ์ =extract_interviewee(detail_page) title =extract_title(detail_page) sc_id =extract_soundcloud_id(detail_page) text =extract_shownotes_text(detail_page) episode_subtitle =extract_subtitle(detail_page) episode_number =extract_episoden (วันที่ย่อย) =extract_episoden แท็ก =build_tags (ชื่อผู้ให้สัมภาษณ์) ตัวเลือก ={ ผู้สัมภาษณ์:ผู้สัมภาษณ์, ชื่อ:ชื่อ, sc_id:sc_id, ข้อความ:ข้อความ, แท็ก:แท็ก, วันที่:วันที่, ตอนที่_number:episode_number }สิ้นสุด

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

การเขียนกระทู้

def compose_markdown

def compose_markdown(options={})<<-HEREDOC--- title:#{options[:interviewee]}ผู้สัมภาษณ์:#{options[:interviewee]}topic_list:#{options[:title]}tags:#{ตัวเลือก[:แท็ก]}soundcloud_id:#{ตัวเลือก[:sc_id]}วันที่:#{ตัวเลือก[:วันที่]}หมายเลขตอน:#{ตัวเลือก[:episode_number]}---#{ตัวเลือก[:ข้อความ]}HEREDOCend 

สำหรับการเผยแพร่ตอนของพอดแคสต์บนไซต์ Middleman ของฉัน ฉันเลือกที่จะนำระบบบล็อกมาใช้ใหม่ แทนที่จะสร้างโพสต์บล็อกที่ "บริสุทธิ์" ฉันสร้างบันทึกย่อสำหรับตอนของฉันที่แสดงตอนที่โฮสต์ SoundCloud ผ่าน iframe ในไซต์ดัชนี ฉันแสดงเฉพาะ iframe บวกกับชื่อและเนื้อหาเท่านั้น

รูปแบบที่ฉันต้องการสำหรับการทำงานนี้ประกอบด้วยสิ่งที่เรียกว่าเรื่องหน้า นี่เป็นที่เก็บคีย์/ค่าสำหรับไซต์สแตติกของฉัน กำลังแทนที่ความต้องการฐานข้อมูลของฉันจากเว็บไซต์ Sinatra เก่าของฉัน

ข้อมูล เช่น ชื่อผู้ให้สัมภาษณ์ วันที่ รหัสแทร็ก SoundCloud หมายเลขตอน และอื่นๆ จะอยู่ระหว่างขีดกลางสามขีด (--- ) ที่ด้านบนของไฟล์ตอนของเรา ด้านล่างนี้เป็นเนื้อหาสำหรับแต่ละตอน เช่น คำถาม ลิงก์ เนื้อหาสปอนเซอร์ ฯลฯ

เบื้องหน้า

---key:valuekey:valuekey:valuekey:value---เนื้อหาตอนอยู่ที่นี่

ใน compose_markdown วิธี ฉันใช้ HEREDOC เพื่อเขียนไฟล์นั้นโดยมีส่วนหน้าสำหรับแต่ละตอนที่เราวนซ้ำ จากตัวเลือกแฮชที่เราป้อนวิธีนี้ เราดึงข้อมูลทั้งหมดที่เรารวบรวมใน extract_data วิธีการช่วยเหลือ

def compose_markdown

...<<-HEREDOC--- title:#{options[:interviewee]}ผู้สัมภาษณ์:#{options[:interviewee]}topic_list:#{options[:title]}tags:#{options[:tags]}soundcloud_id:#{options[:sc_id]}วันที่:#{options[:date]}episode_number:#{options[:episode_number]}---#{options[:text]}HEREDOC... 

นี่คือพิมพ์เขียวสำหรับตอนพอดคาสต์ใหม่ที่นั่น นี่คือสิ่งที่เรามาเพื่อ บางทีคุณอาจสงสัยเกี่ยวกับไวยากรณ์เฉพาะนี้: #{options[:interviewee]} . ฉันสอดแทรกสตริงตามปกติ แต่เนื่องจากฉันอยู่ใน <<-HEREDOC แล้ว ฉันสามารถทิ้งเครื่องหมายคำพูดคู่ไว้ได้

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

สำหรับขั้นตอนสุดท้ายนั้น เราเพียงแค่ต้องเตรียมส่วนผสมต่อไปนี้:วันที่ ชื่อผู้ให้สัมภาษณ์ และหมายเลขตอน บวกกับ markdown_text แน่นอน ซึ่งเราเพิ่งได้มาจาก compose_markdown .

defwrite_page

...markdown_text =compose_markdown(extracted_data)date =extracted_data[:date]interviewee =extracted_data[:interviewee]episode_number =extracted_data[:episode_number]file_name ="#{date}-#{dasherize(interviewee)}-# {episode_number}.html.erb.md" ...

แล้วเราก็แค่เอา file_name และ markdown_text และเขียนไฟล์.

defwrite_page

...File.open(file_name, 'w') { |file| file.write(markdown_text) }...

มาทำลายสิ่งนี้ด้วย สำหรับแต่ละโพสต์ ฉันต้องการรูปแบบเฉพาะ:เช่น 2016-10-25-Avdi-Grimm-120 . ฉันต้องการเขียนไฟล์ที่ขึ้นต้นด้วยวันที่และระบุชื่อผู้ให้สัมภาษณ์และหมายเลขตอน

เพื่อให้ตรงกับรูปแบบที่ Middleman คาดหวังสำหรับการโพสต์ใหม่ ฉันต้องใช้ชื่อผู้สัมภาษณ์และใช้วิธีช่วยเหลือของฉันเพื่อ dasherize ชื่อของฉันจาก Avdi Grimm ถึง Avdi-Grimm . ไม่มีอะไรวิเศษ แต่ควรค่าแก่การดู:

def dasherize

def dasherize(text) text.lstrip.rstrip.tr(' ', '-')end

โดยจะลบช่องว่างออกจากข้อความที่เราคัดลอกสำหรับชื่อผู้ให้สัมภาษณ์ และแทนที่ช่องว่างระหว่าง Avdi และ Grimm ด้วยเส้นประ ชื่อไฟล์ที่เหลือจะถูกขีดรวมกันในสตริง: "date-interviewee-name-episodenumber" .

defwrite_page

..."#{date}-#{dasherize(interviewee)}-#{episode_number}.html.erb.md"...

เนื่องจากเนื้อหาที่แยกมาจากไซต์ HTML ฉันจึงไม่สามารถใช้ .md . ได้ง่ายๆ หรือ .markdown เป็นนามสกุลไฟล์ ฉันตัดสินใจใช้ .html.erb.md . สำหรับตอนต่อๆ ไปที่ฉันแต่งโดยไม่มีการขูด ฉันสามารถละทิ้ง .html.erb ส่วนหนึ่งและต้องการเพียง .md .

หลังจากขั้นตอนนี้ วนซ้ำใน scrape ฟังก์ชันสิ้นสุดลงและเราควรมีตอนเดียวที่มีลักษณะดังนี้:

2014-12-01-Avdi-Grimm-1.html.erb.md

--- title:Avdi Grimminterviewee:Avdi Grimmtopic_list:Rake คืออะไร | ต้นกำเนิด | จิม ไวริช | กรณีใช้งานทั่วไป | ข้อดีของ Raketags:Avdi Grimm, Rake คืออะไร , Origins , Jim Weirich , กรณีใช้งานทั่วไป , ข้อดีของ Rakesoundcloud_id:179619755date:2014-12-01episode_number:1---คำถาม:- Rake คืออะไร- คุณช่วยบอกเราเกี่ยวกับอะไรได้บ้าง ต้นกำเนิดของ Rake?- คุณช่วยบอกอะไรเราเกี่ยวกับ Jim Weihrich ได้บ้าง- อะไรคือกรณีการใช้งานที่พบบ่อยที่สุดสำหรับ Rake- อะไรคือข้อดีที่โดดเด่นที่สุดของ Rake?Links:In">https://www.youtube.com /watch?v=2ZHJSrF52bc">ในความทรงจำของ Jim WeirichRake ผู้ยิ่งใหญ่">https://github.com/jimweirich/rake">Rake บน GitHubJim">https://github.com/jimweirich">Jim Weirich บน GitHubBasic ">https://www.youtube.com/watch?v=AFPWDzHWjEY">พูดคราดพื้นฐานโดยจิม ไวริชพาวเวอร์">https://www.youtube.com/watch?v=KaEqZtulOus">พูดคราดพลังโดยจิม ไวริชเรียนรู้ ">https://devblog.avdi.org/2014/04/30/learn-advanced-rake-in-7-episodes/">เรียนรู้ขั้นสูง Rake ใน 7 ตอน - จาก Avdi Grimm ( ฟรี )Avdi">https://about.avdi.org/">ภาพหน้าจอของ Avdi GrimmAvdi Grimm:Ruby">https://www.rubytapas.com/">Ruby TapasRuby">htt p://devchat.tv/ruby-rogues/">พอดคาสต์ Ruby Rogues พร้อม Avdi GrimmGreat ebook:Rake">https://www.amazon.com/Rake-Management-Essentials-Andrey-Koleshko/dp/1783280778"> Rake Task Management Essentials จากhttps://twitter.com/ka8725"> Andrey Koleshko

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

ก่อนหน้านี้ทั้งหมดนั้นถูกล็อกในฐานข้อมูลของแอป Sinatra ของฉัน—หมายเลขตอน วันที่ ชื่อผู้ให้สัมภาษณ์ และอื่นๆ ตอนนี้เราได้เตรียมที่จะเป็นส่วนหนึ่งของไซต์ Middleman แบบคงที่ใหม่ของฉัน ทุกอย่างที่อยู่ใต้ขีดสามสองตัว (--- ) เป็นข้อความจากบันทึกการแสดง:คำถามและลิงก์เป็นส่วนใหญ่

ความคิดสุดท้าย

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

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

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

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