ทำ web scraping บน Python ด้วยไลบรารี่ Scrapy บน Google Colab

Jirasak Buranathawornsom (Wan)
Super AI Engineer
Published in
3 min readFeb 1, 2021

สวัสดีครับท่านผู้อ่านทุกคน วันนี้ผมจะมาเล่าเรื่องการทำ web scraping ด้วย library ที่ชื่อ Scrapy ครับ ก่อนอื่นจะขอแนะนำคร่าวๆก่อนนะครับว่า web scraping คืออะไร และมีความสำคัญอย่างไรในการทำ data science

Web scraping คือการใช้ script (หรือใช้ computer นั้นเอง) ในการดึงข้อมูลบนอินเตอร์เน็ตที่ต้องการมาเก็บไว้ ไม่ว่าจะเป็นข้อความ ตัวเลข รูปภาพ หรือเสียงก็สามารถทำได้ ซึ่งส่วนมากมักจะทำจะทำในกรณีที่ต้องการข้อมูลในปริมาณมาก และ การค่อยๆ ใช้คนในการดึงข้อมูลเหล่านั้น ไม่ใช่ทางเลือกที่ดีนั่นเอง เพราะคนไม่สามารถที่จะดึงข้อมูลเหล่านั้นได้อย่างมีประสิทธิภาพเท่าการใช้ script ทำให้เสียเวลามาก (ลองจินตนาการว่าเราต้องการรูปแมวในปริมาณมหาศาล การค้นหา google ว่า แมว แล้วค่อยๆ save รูปทีละรูป จะเสียเวลาขนาดไหน)

ในการทำ data science หรือ สร้างโมเดล machine learning นั้น สิ่งแรกๆที่เราต้องทำเลยก็คือการได้มาซึ่งข้อมูล และบ่อยครั้งที่เราไม่มีข้อมูลเหล่านั้นอยู่ในมือ การทำ web scraping จึงมาอุดช่องว่างในจุดนี้

ในปัจจุบัน เครื่องมือที่เป็นที่นิยมสำหรับทำ web scraping บน python มี อยู่หลักๆ 3 ตัว ได้แก่ BeautifulSoup, Selenium, Scrapy ซึ่ง 2 ตัวแรกจะมีข้อดีตรงที่ใช้งานง่ายกว่า แต่ข้อเสียคือ ช้ากว่า และไม่เหมาะแก่การใช้เป็นกิจจลักษณะเท่าตัว Scrapy

เกริ่นกันมาพอสมควรแล้ว ทีนี้เราจะมาเริ่มกันเลยครับ โดย environment ที่ผมจะทำก็คือ Google Colab ซึ่งขอบอกก่อนว่าไม่เหมาะนักกับการใช้ Scrapy แต่เนื่องจากเป็น environment ที่ใครก็สามารถนำไปลองทำได้โดยไม่ต้อง ติดตั้งอะไรบนเครื่องเพิ่มเติม ผมจึงเลือกที่จะใช้ environment ตัวนี้ครับ

สิ่งที่เราจะทำวันนี้คือการดึงข้อมูลวัตถุดิบจากเว็บไซต์ https://www.yummly.com/recipes ซึ่งเป็นเว็บไซต์รวบรวมเมนูอาหาร วัตถุดิบ และวิธีทำ ในครั้งนี้ เราจะทำการดึงชื่ออาหาร และวัตถุดิบของอาหารนั้นๆครับ

ก่อนอื่นก็ต้องสร้างไฟล์ .py ขึ้นมาก่อน ซึ่งใน colab ไม่เหมาะนักกับการสร้างไฟล์ดังกล่าว ผมจึง มีการเพิ่ม magic command %%writefile crawler.py ไว้บนสุดทุกครั้ง เพื่อเป็นการ save บล็อคดังกล่าวเป็นไฟล์ชื่อ crawler.py นั่นเอง

หลังจากที่เรารันโค้ดชุดนี้แล้ว เราจะได้ไฟล์ชื่อ crawler.py ขึ้นมาจากคำสั่ง %%writefile crawler.py ด้านบน

ไฟล์ crawler.py ถูกสร้างขึ้นมา

หลังจากนั้นเราก็รัน command ด้านล่างนี้ (หากไม่ได้รันบน Google Colab ให้นำเครื่องหมาย ! ออก และนำไปรันใน Terminal)

!scrapy runspider crawler.py
เกิด error ขึ้น เนื่องจากไม่ได้สร้างฟังค์ชั่น parse

จะเห็นได้ว่าเกิด error ขึ้น เนื่องจากเรายังไม่ได้สร้างฟังค์ชั่น parse นั้นเอง ดังนั้นเราจะมาสร้างฟังค์ชั่น parse กันก่อนครับ

ผลจากการ inspect หน้าเว็บไซต์ เพื่อได้มาซึ่งลิ้งค์ (ทำได้โดยคลิ๊กขวาแล้วเลือก inspect หรือ “สำรวจ” บน Google Chrome หรือ browser อื่นๆ)

การที่เราจะสามารถได้มาซึ่งรายการวัตถุดิบมานั้น เราต้องหาลิ้งค์ในการเข้าไปดูอาหารแต่ละเมนู ซึ่งเราสามารถ inspect ดูเพื่อที่จะทราบได้ จากรูป เราจะเห็นได้ว่า class ที่จะนำไปสู่ลิ้งค์ของอาหารแต่ละชนิดชื่อ link-overlay และ href คือสิ่งที่นำไปสู่สู่ลิ้งค์ของอาหาร เราจึงสามารถเขียน selector (พูดง่ายๆคือ ตัวเลือกสำหรับการเลือกลิ้งค์ประเภทนี้) ดังนี้

ทำการดึงข้อมูลลิ้งค์ไปยังรายการวัตถุดิบ

หลังจากเราสร้างฟังค์ชั่นสำหรับ parse ลิ้งค์ของอาหารแต่ละเมนูแล้ว เราจะมาสร้างตัว parse รายชื่อวัตถุดิบของอาหารแต่ละประเภทกัน ซึ่งก่อนอื่นเราจะทำการสำรวจก่อนเหมือนที่เราทำก่อนหน้านี้

ผลจากการ inspect หน้าเว็บไซต์ เพื่อได้มาซึ่งชื่ออาหาร และ รายการวัตถุดิบ

จะเห็นได้ว่าวัตถุดิบที่เราต้องการนั้น อยู่ใน class ingrediant ซึ่งเราสามารถทำการดึง text ดังกล่าวออกมาดังนี้

ฟังค์ชั่นสำหรับทำการดึงชื่ออาหารและวัตถุดิบ

โดยรวมแล้ว class RecipeSpider ของเราจะมีหน้าตาดังนี้

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

อย่างไรก็ตามเมื่อลองสังเกตุดูจะพบว่าเราสามารถดึงมาได้แค่ 36 เมนูเท่านั้น

ดึงข้อมูลมาได้เพียง 36 รายการ

ที่เป็นเช่นนี้เพราะหน้าเว็บไซต์นี้ เป็นแบบ infinite scrolling นั่นเอง (ต้องเลื่อนลงไปจนสุดล่างจอก่อน ถึงจะโหลดเมนูอาหารเพิ่มมาให้ดู) ถ้าเป็นแบบนี้ เราก็ไม่สามารถดึงข้อมูลในปริมาณมากๆได้

วิธีแก้ของเราก็คือ การไปหาว่า มีการเคลื่อนไหว network อย่างไรเมื่อเรา scroll ไปถึงจุดล่างสุดของหน้า

การเคลื่อนไหวของ Network เมื่อเลื่อนไปถึงล่างสุดของจอ

เราจะได้ url ที่เกิดขึ้นตอน scroll ไปที่ท้ายสุดของเพจ

https://mapi.yummly.com/mapi/v19/content/search?solr.seo_boost=new&start=36&maxResult=36&fetchUserCollections=false&allowedContent=single_recipe&allowedContent=suggested_search&allowedContent=related_search&allowedContent=article&allowedContent=video&allowedContent=generic_cta&guided-search=true&solr.view_type=search_internal

จะเห็นได้ว่ามีจุดหนึ่งใน url ที่เขียนว่า maxResult=36 อยู่ทำให้เรารู้ได้ว่าเราสามารถเปลี่ยนตัวเลข max result ได้ตามที่เราต้องการ แต่เราต้องมีการแก้ไขโค้ดเล็กน้อย เพราะเมื่อเราเข้าไปในลิ้งค์ดังกล่าว ข้อมูลถูกเก็บในรูปแบบไฟล์ json เราจะอ่านจากไฟล์ json แทน

เขียนโค้ดใหม่ เพื่อให้ดึงข้อมูลมาได้มากขึ้น (ในกรณีนี้คือ 500 รายการ) และรองรับการอ่านไฟล์ json

สุดท้าย เราทำการแก้ฟังค์ชั่น parse เล็กน้อยเพื่อให้ได้ไฟล์สามารถเก็บข้อมูลเป็นไฟล์ csv ออกมา

เพิ่มการดึงไฟล์ csv รายชื่ออาหารและวัตถุดิบออกมา

เราจะได้ ข้อมูลที่มีหน้าตาดังรูป

ผลลัพธ์จากการดึงข้อมูล

ทุกท่านสามารถไปลองเล่นและศึกษาการทำ Web scraping ที่ได้ทำในบทความนี้ด้วยลิ้งค์ Google Colab นี้ครับ

ก็จบไปแล้วครับสำหรับการทำ web scraping ด้วย Scrapy หวังว่าท่านผู้อ่านทุกคนจะได้ความรู้ไม่มากก็น้อยจากบทความนี้นะครับ แล้วพบกันใหม่ในบทความหน้าครับผม :)

Reference

บทความนี้ผมได้ทำตามตัวอย่างจาก https://medium.com/analytics-vidhya/web-crawling-with-scrapy-f4d93c1bfcc7 และทำการ implement ลงใน Google Colab และเพิ่มเติมด้วยการดึงข้อมูลลงไฟล์ csv

--

--