Web Scrape ไม่ใช่ Crepe.
Requirements
- ทักษะการเขียนโปรแกรมด้วยภาษา Python
- ความรู้ด้านการจัดการกับชุดข้อมูลด้วย Pandas
Web Scraping คืออะไร?
นึกย้อนกลับไปตอนที่เราอยู่ชั้นประถม ตอนที่ความหมายของอินเทอร์เน็ตคือ sanook และ kapook ดอทคอม ตอนที่ความหมายของการทำรายงานคือการเข้ากูเกิล แล้วก๊อปปี้อะไรก็ตามที่เกี่ยวข้องกับหัวข้อนั้นๆ จากไม่กี่เว็บเพจ มาต่อๆกันเพื่อให้ได้จำนวนหน้าที่ต้องการ เวลาผ่านไปก็มีแพลตฟอร์มใหม่ๆเกิดขึ้นมามากมาย ปริมาณข้อมูลในอินเทอร์เน็ตเพิ่มมากขึ้นจนเกินจินตนาการ ความรับผิดชอบที่มากขึ้น รูปแบบความต้องการข้อมูลจากอินเทอร์เน็ตของเราก็เปลี่ยนไป แต่พวกเราส่วนใหญ่ยังสามารถเปิดดูข้อมูลจากเว็บไซต์ได้ทีละหน้าไม่ต่างจากตอนเด็กๆ
ปัญหานี้สามารถแก้ได้ง่ายๆ โดยอาศัยทักษะ Python พื้นฐาน ด้วยวิธีการที่เรียกว่า Web Scraping ซึ่งคือกระบวนการในการใช้บอทดึงข้อมูลบางอย่างออกมาจากเว็บไซต์ นักกฎหมายอาจต้องการคำพิพากษาศาลฎีกาตั้งแต่ปี 2463 จนถึงปัจจุบัน นักการตลาดอาจต้องการข้อมูล ความคิดเห็นของลูกค้าต่อผลิตภัณฑ์คู่แข่งเท่าที่จะมากได้ บ่าวสาวที่กำลังจะแต่งงานอาจกำลังมองหาเรือนหอหลังใหม่ อยากได้ข้อมูลบ้านทุกแบบ จากทุกโครงการที่กำลังประกาศขาย ก่อนที่จะตกลงปลงใจเป็นหนี้ร่วมกันไปอีก 30 ปี ซึ่งการได้มาซึ่งข้อมูลเหล่านี้ ถ้าต้องนั่งไล่เปิดเว็บไปทีละหน้า ก๊อบปี้ข้อมูลลง Spreadsheet ด้วยตนเองอาจจะใช้เวลาเป็นวันหรือหลายวัน แต่ Web Scraping สามารถทำให้เราได้ข้อมูลทั้งหมดที่ว่ามานี้ในเวลาแค่ไม่กี่นาที!
หลักการพื้นฐานของ Web Scraping คืออะไร?
โดยปกติแล้วเว็บไซต์ที่เราเห็นๆกันไม่ว่ามันจะมาในรูปแบบใด มีลูกเล่นมากน้อยแค่ไหน ทั้งหมดถูกสร้างขึ้นจากไฟล์ HTML ซึ่งมีหน้าตาดังภาพที่ 1
ซึ่งเมื่อนำไฟล์นี้ไปเปิด หรือที่เรียกว่าการนำไป “Render” บนบราวเซอร์ ก็จะได้หน้าเว็บดังภาพที่ 2 ออกมา
ซึ่งเจ้าไฟล์ HTML นี้จะประกอบด้วยส่วนประกอบ หรือ “Tag” ต่างๆ ซึ่งโดยปกติแล้วผู้พัฒนาเว็บไซต์ก็จะสร้างให้แต่ละ Tag เก็บข้อมูลต่างชนิดกัน
จากในตัวอย่างข้างต้น ส่วนที่เป็นหัวข้อจะถูกเก็บไว้ในแท็ก <title> และส่วนที่เป็นเนื้อความก็จะถูกเก็บไว้ในแท็ก <p>
จากพื้นฐานนี้ เมื่อเราต้องการดึงข้อมูลส่วนหนึ่งส่วนใดออกมาจากหน้าเว็บ สิ่งที่เราต้องทำก็แค่…
- ให้บอทไปดึง HTML มาจากเว็บเป้าหมาย
- ดูว่าข้อมูลที่เราต้องการอยู่ในแท็กใด แล้วสั่งให้บอทไปดึงข้อมูลจากแท็กนั้น
- บันทึกข้อมูลที่ได้ลงฐานข้อมูล
เพียงแค่นี้เราก็สามารถดึงข้อมูลที่เราต้องการออกมาได้แล้วครับ
ทุกเว็บนี่ใช้วิธีดึงข้อมูลแบบเดียวกันหมดเลยไหม?
ปกติแล้วรูปแบบการ Render หน้าเว็บมีอยู่ด้วยกัน 3 รูปแบบครับ
- static site rendering เช่น เว็บที่เราเห็นเมื่อสิบปีก่อน
- server side rendering เช่น sanook.com
- client side rendering เช่น ไทยชนะ.com
ซึ่งเครื่องมือในการ Scraping ก็มีหลักๆ 3 ตัว ได้แก่ Selenium, Scrapy, และ BeautifulSoup ซึ่งในบทความนี้เราจะใช้ BeautifulSoup ซึ่งใช้งานง่ายที่สุด และสามารถดึงข้อมูลได้ดีจากทั้งเว็บประเภท static site rendering และ server side rendering ต่อไปเรามาลองลงมือทำกันเลยครับ
โจทย์ของเราคืออะไร และข้อมูลที่เราต้องการมีอะไรบ้าง?
คำถามที่เรากำลังลองพยายามหาคำตอบคือ “ข้าราชการทหารตำรวจระดับสูงมีความสัมพันธ์กับกลุ่มธุรกิจต่างๆอย่างไร?” โดยใช้ข้อมูลสาธารณะจากตลาดหลักทรัพย์แห่งประเทศไทย
ข้อมูลที่เราต้องการได้แก่
- รายชื่อบริษัททุกบริษัท ที่จดทะเบียนอยู่ใน SET/MAI, อักษรย่อ, ราคาปัจจุบัน, มูลค่าบริษัทตามราคาตลาด, ประเภทธุรกิจ
- รายชื่อกรรมการบริหารของบริษัท
- รายชื่อผู้ถือหุ้นใหญ่พร้อมทั้งจำนวนหุ้นที่ถืออยู่
การดึงรายชื่อบริษัททุกบริษัท ที่จดทะเบียนอยู่ใน SET/MAI
ก่อนที่เราจะดึงข้อมูลอะไรก็ตามออกมา อันดับแรกต้องทำความเข้าใจโครงสร้างของเว็บไซต์นั้นๆ เพื่อดูว่าเราจะสามารถหาข้อมูลแต่ละชนิดที่ต้องการได้จาก URL ใด เมื่อเข้าไปที่ ลิงค์นี้ เราก็จะพบรายชื่อบริษัทต่างๆ ที่อยู่ในหมวดอักษร “A”
ในกรณีนี้ที่เราต้องการรายชื่อบริษัทจากทุกหมวดอักษร สิ่งที่ต้องทำก็เพียงแค่ เขียนลูปเพื่อสร้าง URL ของแต่ละหมวดอักษรขึ้นมาดังภาพที่ 4
ต่อมาสำหรับการดึงรายชื่อของหุ้นแต่ละตัวออกมาจาก URLs ข้างต้น อย่างที่กล่าวไปว่าเราจำเป็นที่จะต้องหาว่าข้อมูลที่เราต้องการอยู่ใน TAG ใด สำหรับผู้ใช้ Chrome สามารถหาอย่างง่ายดายโดยทำการเลือกข้อมูลส่วนที่เราต้องการจากนั้นคลิ๊กขวาเลือก Inspect ดังภาพที่ 5 ด้านบน
เมื่อคลิ๊ก Inspect ก็จะมีหน้า Developer Tools แทรกขึ้นมาดังภาพที่ 6 ที่จะแสดงว่าข้อมูลที่เราเลือกทำการ Inspect นั้นอยู่ในแท็กไหน อย่างเช่นกรณีนี้ชื่อของบริษัทก็จะอยู่ในแท็ก <td> เราก็จะเก็บข้อมูลตรงนี้ไว้เพื่อเป็นเป้าหมายให้ BeautifulSoup ของเราทำการค้นหาต่อไป
เมื่อเรารู้แล้วว่าข้อมูลที่เราต้องการอยู่ในแท็กไหน ก็ลองเขียนโค้ดดึงข้อมูลดูได้เลยครับ จากภาพด้านบนในบรรทัดที่ 4 เป็นการใช้ requests เพื่อดึงไฟล์ HTML มาจาก URL จากนั้นทำการ parsing และดึงข้อมูลออกมาจากแท็กที่เราต้องการในบรรทัดที่ 5–6 จะเห็นได้ว่าข้อมูลที่ออกมา ค่อนข้างน่าพอใจ BeautifulSoup สามารถดึงข้อมูลออกมาจากแท็กที่เรากำหนดไว้ได้
อย่างไรก็ตามสิ่งที่เราต้องการจริงๆ มีเพียงแค่ข้อมูลที่อยู่ข้างในแท็ก ตรงนี้เราสามารถใช้เมธอด .get_text() ดึงเฉพาะตัวข้อมูลออกมาได้ดังภาพที่ 8
ซึ่งจากภาพด้านบนจะเห็นได้ว่าชื่อย่อ ชื่อเต็ม และตลาดที่แต่ละบริษัทจดทะเบียนอยู่มันเรียงกันตามแพทเทินบางอย่าง ตรงนี้เราสามารถใช้ทักษะ Python พื้นฐานมาจัดกลุ่มให้มันอยู่ด้วยกันดังภาพที่ 9 ได้เลยครับ
เมื่อนำโค้ดทั้งหมดมาประกอบร่างกัน ผลลัพท์ที่ได้ก็จะเป็นดังภาพด้านล่างครับ
ใช้เวลาประมวลผลแค่ไม่กี่วินาที ก็ได้รายชื่อบริษัททั้งหมดกว่า 800 บริษัทในตลาดหลักทรัพย์มาแล้ว อะไรจะง่ายปานนั้น ^^
การดึงมูลค่าบริษัทตามราคาตลาด ประเภทธุรกิจ และรายชื่อกรรมการบริหาร
ในการดึงมูลค่าบริษัท และประเภทธุรกิจ เมื่อเปิดเข้าไปในหน้าข้อมูลของแต่ละบริษัท อย่างเช่นในลิงค์นี้ แล้วทำการ Inspect จะพบว่าข้อมูลดังกล่าวอยู่ในแท็ก <div> ในคลาสที่มีชื่อว่า “col-xs-9 col-md-5”
จากข้อมูลดังกล่าวเมื่อเราลองใช้เมธอด find_all() ของ Beautiful Soup ในการดึงข้อมูลจากแท็กและคลาสดังกล่าวก็จะได้ผลดังภาพที่ 12
สังเกตุได้ว่ามูลค่าบริษัทนั้นจะอยู่ใน element ที่ 3 ส่วนประเภทธุรกิจนั้นจะอยู่ใน element ที่ 6 ของ result_by_calss ซึ่งเราสามารถนำข้อมูลตรงนี้ไปใช้งานต่อ เพื่อดึงข้อมูลเฉพาะส่วนที่เราต้องการได้ดังภาพที่ 13
ในหน้า URL เดียวกันเลื่อนมาด้านล่างเราก็จะพบกับข้อมูลรายชื่อกรรมการบริหารเมื่อทำการ Inspect ดูจะพบว่าข้อมูลดังกล่าวอยู่ในแท็ก <div> ในคลาสชื่อ “col-xs-6” ดังภาพที่ 14
และเมื่อลองดึงด้วยเมธอด .find_all() ก็จะได้ผลลัพธ์ออกมาดังภาพที่ 15
อย่างไรก็ตาม สิ่งที่เราต้องการมีเพียงแค่รายชื่อของกรรมการบริหาร เราไม่ได้ต้องการตำแหน่งของแต่ละคน ตรงนี้เราสามารถใช้พื้นฐาน Python เลือกเฉพาะ element ที่เป็นชื่อคน ซึ่งมีคุณลักษณะพิเศษ คือสามารถแบ่งด้วย space ออกมาได้เป็น 3 elements ดังบรรทัดที่ 6 ในภาพที่ 16
และเมื่อนำโค้ดทั้งหมดมาประกอบกันก็จะได้ผลลัพธ์ดังภาพที่ 17
การดึงรายชื่อผู้ถือหุ้นรายใหญ่ จำนวนหุ้นที่ถืออยู่ และราคาหุ้นปัจจุบัน
เหมือนเดิมเลยครับ เพียงแค่เราเปิดไปที่หน้านี้แล้วทำการ Inspect จะพบว่าข้อมูลสองรายการดังกล่าวอยู่ในแท็ก <td> เหมือนกัน ดังภาพที่ 18
แต่ต่างจากในกรณีก่อนๆ ตรงที่ แทนที่เราจะสามารถหาข้อมูลจากคลาสได้ ในกรณีนี้เราจะต้องหาข้อมูลจาก style และ align แทน อย่างในกรณีนี้ ชื่อผู้ถือหุ้นจะอยู่ใน style ที่ชื่อว่า “text-align:left;” ส่วนจำนวนหุ้นที่ท่านนั้นๆถืออยู่จะอยู่ในการ align แบบ “right”
ซึ่งเราก็นำข้อมูลตรงนี้ไปประยุกต์ใช้กับเมธอด .find_all() โดยแทนที่จะระบุ “..class=” อย่างในบรรทัดที่ 10,14 ของภาพที่ 17 เราก็ระบุ style และ align ลงไปแทน อย่างในบรรทัดที่ 9,12 ในภาพที่ 19
เพียงเท่านี้เราก็จะได้รายชื่อผู้ถือหุ้นใหญ่ กับจำนวนหุ้นที่พวกเขาถืออยู่ออกมาแล้ว
สุดท้ายสำหรับราคาหุ้นปัจจุบันก็ทำเหมือนกันเลยครับ แต่เพื่อให้ tutorial นี้สมบูรณ์แบบขึ้นอีกนิด ส่วนราคาหุ้นปัจจุบันนี้ผมขออนุญาตไม่แชร์โค้ด ขอเป็น Challenge ให้ผู้อ่านได้ลองไปทำฝึกฝีมือกันดู ผลลัพธ์สุดท้ายที่ได้ก็จะออกมาหน้าตาประมาณภาพที่ 20 ครับ ^^
มีนายทหาร นายตำรวจคนไหน นั่งเป็นบอร์ด/เป็นผู้ถือหุ้นใหญ่ ในบริษัทใดบ้าง?
ในที่นี้สิ่งที่เราต้องการคือทราบว่ามีนายทหารตำรวจคนไหนมีตำแหน่งเป็นกรรมการ หรือเป็นผู้ถือหุ้นใหญ่ในบริษัทอะไรบ้าง ในกรณีนี้เราสามารถค้นหาจากรายชื่อทั้งสองรายการที่เราได้มา โดยใช้คำนำหน้าชื่อ ยศ ของทหาร,ตำรวจ ได้เลยครับ ซึ่งจากผลที่ออกมาผมพบว่าจากประมาณ 800 กว่าบริษัทในตลาดหลักทรัพย์ มีบริษัทที่มีนายทหาร/นายตำรวจ เป็นกรรมการบริษัทถึงเกือบ 140 บริษัท และจากบริษัทดังกล่าว 10 บริษัทที่มีขนาดใหญ่ที่สุดตามมูลค่าตลาดปัจจุบันก็มีรายการดังภาพที่ 21
ในส่วนของการเป็นผู้ถือหุ้นใหญ่ของบริษัท สิบอันดับคนในเครื่องแบบที่รวยหุ้นมากที่สุดก็เป็นดังภาพที่ 22 จะเห็นได้ว่ามีนายตำรวจท่านหนึ่งมีทรัพย์สินที่เป็นหุ้น มีมูลค่า ณ. วันที่บทความนี้ถูกเขียนขึ้นถึงเกือบหมื่นล้าน โอ้วววว..
สุดท้ายถ้าผู้อ่านท่านใดเห็นว่าสิ่งที่อธิบายไปไม่ถูกต้อง มีข้อเสนอแนะอะไร สงสัยจุดไหน หรือนำข้อมูลที่ได้ไปวิเคราะห์ต่อแล้วได้ insight อะไร ก็คอมเมนท์หรือหลังไมค์มาแชร์กันได้เลยนะครับ แล้วพบกันใหม่โอกาสหน้าครับ.