Web Scraping (Python) ด้วย beautifulsoup และ requests

Web Scraping เป็นอีกหนึ่งวิธีการที่ได้รับความนิยมในการดึงหรือดูดข้อมูลจากหน้าเว็บไซต์ ซึ่ง Python เป็นหนึ่งในภาษายอดนิยมในการใช้งานทำ Web Scraping

Web Scraping (Python) ด้วย beautifulsoup และ requests

Web Scraping เป็นอีกหนึ่งทักษะที่ถูกพูดถึงบ่อย ๆ สำหรับสายงานด้านโปรแกรมมิ่งและด้าน วิเคราะห์ข้อมูลยิ่งถ้าเหล่าสาวก Python นั้น จะได้ยินคำนี้บ่อย ๆ โดยบทความนี้เราจะมา set zero และเรียนรู้ สอนใช้งานและทำความเข้าใจไปพร้อม ๆ กันว่า จริง ๆ แล้ว Web Scraping มันคืออะไร เอาไปใช้งานยังไง ทำได้อย่างไร กฏหรือข้อจำกัดในการ scrape ข้อมูลมีอะไรบ้าง ทำแล้วจะโดนเจ้าของเว็บไซต์บล็อกหรือไม่ เอาให้เข้าใจกันแบบหมดจดในเกือบทุกมิติ

Web Scraping คืออะไร ?

Web Scraping คือวิธีการในการดึงข้อมูลจากหน้าเว็บเพจหรือเว็บไซต์ โดยใช้ภาษาโปรแกรมมิ่งเป็นเครื่องมือ (ในที่นี้คือภาษา Python) ในการเขียนสคริปต์ในการดึงข้อมูลจากหน้าเว็บไซต์นั้น ๆ โดยภาษาที่นิยมก็อย่างเช่น Scripting Language เช่น ไพธอน ซึ่งเมื่อทำการดึงข้อมูลเสร็จแล้ว ก็จะมีขั้นตอนในการสกัด (Extract) เอาเฉพาะข้อมูลที่ต้องการ โดยเก็บไว้ในฟอร์แมตรูปแบบต่าง ๆ เพื่อนำไปใช้งานต่อไป โดยปกตินั้นวิธีการในการดึงข้อมูลจาก Data Sources หรือแหล่งข้อมูลต่าง ๆ มีอยู่หลัก ๆ ดังนี้

ปกติการดึงข้อมูลนั้นมีอยู่ด้วยกัน 2 วิธีหลัก ๆ คือ

  1. ดึงจาก API
  2. ทำ web scraping

1. ดึงจาก****API

การดึงข้อมูลโดยใช้ API (Application Programming Interface) นั้นเป็นวิธีที่หลาย ๆ คนคงจะเคยได้ยินและคุ้นเคยเป็นอย่างดี (ถึงแม้จะเคยทำหรือไม่ แต่ส่วนใหญ่ก็คงจะได้ยินและรู้จัก API กันหมด) ซึ่งการดึงข้อมูลโดยวิธีนี้ก็จะมี API Web Service ที่เป็นแหล่งของข้อมูลนั้น ๆ และเปิดเป็นแบบ Open API ให้เราใช้งาน ซึ่งมีทั้งฟรีและเสียตังค์ อาจจะขึ้นอยู่กับจำนวน Requests ตัวอย่างการดึงข้อมูลแบบ API เช่น ดึงข้อมูลสภาพอากาศจากทั่วโลกโดยใช้ openweathermap.org มาแสดงผลไว้ที่หน้าเว็บไซต์ของเรา หรือเช่น กรมควบคุมโรค กระทรวงสาธารณะสุขเปิด Open API ให้มีสามารถดึงข้อมูล Covid-19 ได้ เป็นต้น เหล่านี้ก็คือตัวอย่างภาพรวมแบบคร่าว ๆ ของการใช้งาน API

****

2. ทำ****web scraping

ซึ่งการทำ Web Scraping นั้นก็คือวิธีการที่เราจะมาทำความเข้าใจและเขียนโค้ดเพื่อใช้งานในวันนี้กัน โดยใน Part 1 นี้จะเป็น Overview หรือเน้นให้เห็นภาพรวมของการทำ Web Scraping ในทำนอง Web Scraping 101 - Introduction ประมาณนี้ ซึ่งหลังจากจบ Part นี้แล้ว ก็จะเป็น Part 2 และ 3 กันต่อ เริ่มจาก Beginner ไปจนถึงขั้น Intermediate เช่นการเข้าถึง คลาส CSS ต่าง ๆ ที่เริ่มซับซ้อน และการประยุกต์ใช้ Regular Expression หรือที่มักเรียกกันสั้น ๆ ว่า Regex เข้ามาเพื่อช่วยให้สามารถค้นหาข้อมูลได้สะดวกยิ่งขึ้น

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

แนะนำบทความ:Web Scraping ด้วย Python(สำหรับเว็บที่ต้อง login)

ตัวละครเอกในเรื่องนี้

จุดประสงค์

  1. เข้าใจและอธิบายได้ว่า web scraping คืออะไร
  2. เข้าใจและสามารถอธิบายได้ว่าทำไมต้องมีการทำ web scraping
  3. เข้าใจและอธิบายประโยชน์ในการทำ web scraping ได้
  4. สามารถนำการทำ web scraping ไปประยุกต์ใช้งานได้
  5. เข้าใจและอธิบายได้ว่าเว็บไซต์หรือแหล่งข้อมูลนั้นมีข้อจำกัดหรือข้อกำหนดการใช้งานข้อมูลของเว็บนั้น
  6. เข้าใจและอธิบายได้ว่าเครื่องมือหรือไลบรารีที่ใช้สำหรับการทำ Web Scraping มีอะไรบ้าง
  7. สามารถใช้งาน beautifulsoup library ได้

Software & Tools


ทำไมต้องทำ web scraping ?

ในโลกแห่งความเป็นจริง ข้อมูลไม่ได้ถูกจัดฟอร์แมตมาให้พร้อมใช้งานเสมอไปหรือเป็นข้อมูลที่ไม่ได้มีโครงสร้าง (Unstructured Data) ดังนั้นข้อมูลจึงมีอยู่กระจัดกระจายทั่วไปตามเว็บ และเว็บไซต์ส่วนใหญ่ก็คงไม่ได้ใจดีถึงขนาดทำเป็นไฟล์ในฟอร์แมตต่าง ๆ เช่น CSV, JSON, Text, Excel, SQL, etc ไว้ให้เราได้ทำการดาวน์โหลดมาใช้ฟรี ๆ ดังนั้น web scraping ก็คือพระเอกที่จะมาช่วยจัดการปัญหาเหล่านี้

ข้อดีของการทำ web scraping

  1. ดึงข้อมูลได้ฟรี มีแหล่งข้อมูลมากมายบนโลกนี้ที่เปิดให้ดึงข้อมูล
  2. สามารถนำข้อมูลที่ได้ไปวิเคราะห์และใช้งานได้ต่อไป
  3. สามารถรับงานเป็นจ็อบ ๆ ในการดึงข้อมูลได้
  4. ถึงแม้ web scraping จะไม่ใช่งานหรืออาชีพโดยตรง แต่ถ้ามีสกิลด้านนี้ จะทำให้เราเป็นหนึ่งในตัวเลือก (Candidate) ในการสมัครงาน ได้เป็นอย่างดี

ข้อจำกัดของการทำ web scraping

  1. ถ้าเว็บไซต์ที่เราทำการดึงข้อมูลเปลี่ยนโครงสร้างหน้าเว็บ จะทำให้การ Scrape ข้อมูลหยุดชะงักลงทันที และต้องมีการเขียนเพื่อแก้สคริปต์เข้าไปใหม่ (แต่จริง ๆ แล้วไม่ค่อยเปลี่ยนกันกระทันหันหรอกครับ)
  2. ข้อมูลหลายส่วนถูกจำกัด หลาย ๆ เว็บก็ไม่สามารถที่จะ Scrape ข้อมูลได้ ซึ่งสุดท้ายถ้าข้อมูลนั้นไม่เปิดให้ทำ Web Scraping ก็จะต้องเรียกใช้บริการ API แทน

งาน web scraping

ถึงแม้งานด้าน web scraping จะได้มีตำแหน่งงานสำหรับ web scraper ที่ระบุชัดเจน และผู้เขียนได้ทำการทดสอบพิมพ์ใน Google ด้วยคีย์เวิร์ดคำว่า “งาน web scraping” และก็อย่างที่คิด คือไม่พบตำแหน่งงานด้านนี้ที่ระบุชัดเจน แต่ไปเจองานในหน้าเว็บหางาน Freelance ที่หลาย ๆ คนคงรู้จักกันดี น้่นก็คือ Fastwork และพบว่าใน Fastwork มีผู้ที่รับงานเกี่ยวกับการทำ web scraping อยู่ประมาณ 11 คน เรตราคาก็เริ่มต้องแต่ 1,500 - 3,000 บาท ต่องาน น่าสนใจไม่น้อย รายได้ก็ถือว่าโอเครเลย หรือถ้าท่านใดอยากจ้างผู้เขียนก็ติดต่อเข้ามาได้ครับ (เนียน ๆ)

ลองเข้าดูใน fastwork-web-scraping

งาน web scraping ในเว็บไซต์ Fastwork


web scraping มีแค่เฉพาะภาษาไพธอน ?

ยังมีหลายคนที่ยังเข้าใจว่า web scraping นั้น ทำได้เฉพาะภาษาไพธอน ซึ่งจริง ๆ แล้วการทำ web scraping นั้น ไม่ได้จำกัดอยู่แค่ในภาษาไพธอน ยังสามารถทำได้ในภาษาโปรแกรมมิ่งอื่น ๆ ไม่ว่าจะเป็น R, JavaScript, Java, Go, PHP, etc เพียงแต่ว่า ภาษาไพธอนเป็นที่นิยมที่สุด ในการทำงานด้าน web scraping

สิ่งที่ต้องรู้ก่อนทำ web scraping

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

โดย สิ่งที่ควรรู้ในการทำ Web Scraping ก็คือ

  1. เป้าหมายของการทำ web scraping
  2. เว็บไซต์ไหนที่สามารถ Scrape ข้อมูลได้บ้าง
  3. พื้นฐาน Python เบื้องต้น
  4. พื้นฐาน HTML เบื้องต้น ****

1. เป้าหมายของการทำ web scraping

อันนี้แทบจะเรียกได้ว่ามาอันดับแรกสุด ถ้าไม่มีเป้าหมาย ก็ไม่รู้ว่าจะทำไปทำไม ใช่หรือไม่ ? ดังนั้นจึงต้องตั้งเป้าหมายกันก่อนว่าจะเอาไปทำอะไร เช่น เอาข้อมูลที่ได้ไปทำ Data Analysis, Data Visualization, Dataset สำหรับทดสอบโมเดล Machine Learning, etc

2. เว็บไซต์ไหนที่สามารถ scrape ข้อมูลได้บ้าง ?

แน่นอนว่ามันก็มีวิธีการสังเกตอยู่ว่าเว็บไหนที่เราสามารถทำ web scraping ได้ โดยเบื้องต้นให้สังเกตที่ Terms of Service, Privacy Policy, etc เหล่านี้คือคีย์เวิร์ดที่เป็นที่สังเกตและเราต้องเข้าไปอ่านข้อกำหนดของเว็บต่าง ๆ เหล่านี้ให้ดี


3. พื้นฐาน Python เบื้องต้น

ข้อนี้คงไม่มีปัญหา เชื่อว่าหลาย ๆ คนที่ได้อ่านบทความนี้ส่วนใหญ่ก็คงจะผ่านการเรียน Python กันมาเรียบร้อยแล้ว ยกตัวอย่างโค้ดด้านล่างแบบง่าย ๆ ธรรมดา ๆ ถ้าสามารถอ่านโค้ดและรู้ output คุณได้ไปต่อ !

print("Hello, world")
# Output 1 ?

num1 = 20
num2 = "20"
num3 = num1 + num2
print(num3)
# Output 2 ?

def test_basic():
    print(Hello, world)
    
test_basic()
# Output 3 ?

4. พื้นฐาน HTML เบื้องต้น

HTML(Hyper Text Markup Language) คือ ภาษาที่ใช้สำหรับแสดงผลหน้าเว็บไซต์ ก่อนที่จะทำ web scraping ได้อย่างไม่ติดขัดนั้น ความรู้เกี่ยวกับ HTML เบื้องต้นก็มีความจำเป็น หลายคนที่ไม่เคยสัมผัสกับภาษา HTML มาก่อน อาจจะมีความรู้สึกว่าจะอ่านหรือเรียนตามบทความนี้รู้เรื่องไหม คำตอบคือ ไม่น่าจะมีปัญหามากเท่าไหร่ เพราะภาษา HTML เป็นภาษาที่ง่ายกว่าไพธอนค่อนข้างเยอะ และแน่นอนว่าเราไม่จำเป็นต้องรู้ทั้งหมด รู้เพียงแค่บางส่วน มองภาพรวมออกก็ถือว่าโอเครแล้ว ดังนั้นจึงขออธิบาย HTML Tags ต่าง ๆ ในเบื้องต้นที่ควรรู้กันครับ จะเน้นให้มองภาพรวมออก ให้ไปศึกษาเพิ่มเติม

ตัวอย่างไฟล์และ syntax ของ HTML เบื้องต้น ที่มีชื่อว่า index.html โดยสามารถสร้างไฟล์ในโปรเจคท์ได้ตามปกติเหมือนที่สร้าง Python File เพียงแต่เปลี่ยนมาเป็น HTML File

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Web Scraping with Python</title>
</head>
<body>
    <div>
        <h1>h1 is the biggest heading tag</h1>
        <p>This is a paragraph tag</p>
    </div>
</body>
</html>

คลิ๊กรันใน PyCharm ได้ทันทีที่สัญลักษณ์ Web Browser โดยสามารถเลือกรันในแต่ละเว็บบราวเซอร์ได้ตามต้องการ ซึ่งมีทั้ง Google Chorme, Mozilla Firefox, Safari, Opera, Internet Explorer, Microsoft Edge

Output

ถ้ายังไม่ได้ติดตั้ง PyCharm สามารถเข้าไปดาวน์โหลดได้ที่หน้าเว็บ PyCharm Community หรือสามารถดูวิดีโอการติดตั้งได้ในคลิป ติดตั้ง PyCharm เพื่อเขียนไพธอน

Output

ซึ่งส่วนหลัก ๆ ก็จะประกอบไปด้วย tags ต่าง ๆ ที่สำคัญดังนี้

--> คือ HTML5 (HTML เวอร์ชันล่าสุด) --> คือ แท็กที่เป็น Root ของหน้าเว็บเพจ --> คือ แท็กที่ครอบ meta tags ต่าง ๆ ไว้ เช่น title, description, encoding, etc --> คือ meta title ที่แสดงอยู่บนสุดของหน้าเว็บเพจ <body> --> คือ ส่วนของเนิ้อหาของหน้าเว็บ เนื้อหา (Content) ทั้งหมดจะถูกเขียนอยู่ภายใต้แท็กนี้ <h1> --> คือ แท็กหัวเรื่อง (Heading) โดยแท็กนี้จะใหญ่สุดในบรรดา heading tags ทุกตัว (h1 - h6) ไล่เรียงกันไป <p> --> คือ แท็กพารากราฟ เป็นแท็กที่ใช้สำหรับแสดงเนื้อหาข้อความปกติ ซึ่งส่วนใหญ่เนื้อหาของหน้าเว็บ เช่น บล็อก บทความต่าง ๆ จะถูกเขียนในแท็กนี้ <p>ศึกษาเพิ่มเติม <a href="https://www.w3schools.com/html/html_intro.asp">HTML Introduction - w3school</a></p> <h3 id="ไลบรารียอดนิยมของไพธอนสำหรับงานweb">**ไลบรารียอดนิยมของไพธอนสำหรับงาน****web</h3> <p>scraping**</p> <p>ไพธอนมีไลบรารียอดนิยมอยู่หลายตัวที่ใช้สำหรับทำ web scraping ไม่ว่าจะเป็น <a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/">beautifulsoup</a>, <a href="https://docs.scrapy.org/en/latest/">scrapy</a>, <a href="https://selenium-python.readthedocs.io/">selenium</a>, etc ทั้งนี้การเลือกใช้ไลบรารีแต่ละตัวก็ขึ้นอยู่กับว่างานที่กำลังทำมีระดับความยากง่ายแตกต่างกันอย่างไร โดยแนะนำโปรเจคท์เล็ก ๆ การดึงแบบไม่ยุ่งยากซับซ้อน แนะนำให้ใช้ beautifulsoup เพราะว่ามีความเรียบง่าย เขียนโค้ดเพียงไม่กี่บรรทัดก็สามารถดึงข้อมูลได้แล้ว ถ้าเป็นระดับการดึงหรือ scrape ข้อมูลที่มีความซับซ้อนมากขึ้น ตัวเลือกที่น่าจะเหมาะสมที่สุดก็คงเป็น scrapy ครับ เพราะ scrapy คือ เฟรมเวิร์คย่อม ๆ ในการทำ web scraping ดี ๆ นี่เอง</p> <hr> <h2 id="เริ่มทำ-web-scraping">เริ่มทำ web scraping</h2> <p>เมื่อเราได้รู้จักภาพรวมของการทำ web scraping กันไปแล้ว ก็มาถึงขั้นตอนการลงมือปฏิบัติกันแล้วครับ แน่นอนว่าในบทความนี้เราจะใช้ตัวหนึ่งในไลบรารี่ที่ง่ายและสะดวกที่สุดในการทำ web scraping นั่นก็คือ BeautifulSoup ครับ โดยเป็นหนึ่งในคลาสที่อยู่ในโมดูล bs4</p> <hr> <h3 id="โดยแนวคิดในการทำ-web-scraping-มีดังต่อไปนี้">โดยแนวคิดในการทำ web scraping มีดังต่อไปนี้</h3> <ul> <li>เขียนโค้ดเพื่อทำการ request ไปที่ URL ของเว็บไซต์หรือหน้าเว็บเพจที่ต้องการ scrape ข้อมูล Client ทำการ request ไปที่ Server ปลายทาง</li> <li>Server ตอบกลับข้อมูลต่าง ๆ มาในหน้าเว็บเพจ โดยไฟล์ต่าง ๆ ที่ถูก render ออกมาจากฝัง server ไม่ว่าจะเป็น HTML, CSS, JavaScript หรือรูปภาพหรือมีเดียต่าง ๆ</li> <li>เมื่อได้ข้อมูลทั้งหมดที่เป็น HTML เรียบร้อย ทำการเลือกข้อมูลที่ต้องการในหน้าเว็บ ผ่านการ inspect ดูบนเว็บบราวเซอร์</li> <li>เลือก tag ที่ข้อมูลนั้นถูกเก็บอยู่ จากนั้นทำการ extract (สกัด, ดึง) ข้อมูลออกมา</li> <li>ทำการคลีนข้อมูล (Cleaning Data) เพื่อให้ได้ข้อมูลที่นำไปใช้ได้</li> <li>เก็บไว้ในฟอร์แมตหรือในชุดข้อมูลที่มีโครงสร้างชัดเจน (Structured Data) เป็นข้อมูลสุดท้ายที่พร้อมใช้งาน</li> </ul> <p>ซึ่งด้านบนก็คือขั้นตอนหรือแนวคิดในการทำ Web Scraping ในบทความนี้ เมื่อเข้าใจคอนเซ็ปต์เรียบร้อย มองภาพรวมออกชัดเจน ก็ถึงเวลาที่จะมาเขียนโค้ดกันแล้ว</p> <hr> <h3 id="1-ติดตั้งและใช้งานrequests"><strong>1. ติดตั้งและใช้งาน****requests</strong></h3> <h3 id="ทำการเลือกเครื่องมือเพื่อใช้จับปลา"><em>ทำการเลือกเครื่องมือเพื่อใช้จับปลา</em></h3> <h3 id="requests-คือ-python-library-ที่เอาไว้ใช้สำหรับจัดการเกี่ยวกับการ-request">******Requests คือ Python library ที่เอาไว้ใช้สำหรับจัดการเกี่ยวกับการ request</h3> <p>ข้อมูลจากหน้าเว็บหรือเว็บบราวเซอร์ โดยไลบรารีตัวนี้แทบจะเรียกได้ว่าเป็นหนึ่งในไลบรารีที่ได้รับความนิยมสูงสุดในภาษาไพธอนกันเลยครับ โดยอ้างอิงจาก <a href="https://pypi.org/project/requests/">pypi.org</a>สถิติการดาวน์โหลดกว่า 14 ล้านครั้งต่อสัปดาห์ และจำนวน Stars ใน<a href="https://github.com/psf/requests">GitHub</a> ก็ปาเข้าไปแล้ว 44.1 k เข้าไปแล้ว (สถิติล่าสุดในวันจันทร์ที่ 7 ธันวาคม 2563) ซึ่งในการทำ web scraping นั้น ก็มีความจำเป็นที่จะต้องเรียกใช้งานไลบรารีตัวนี้ เรียกได้ว่า requests แทบจะเป็นอีกหนึ่งพระเอก ที่มีความสำคัญในการทำ web scraping จะเห็นได้ว่า ส่วนใหญ่จะมีการนำไลบรารีตัวนี้เข้าไปเอี่ยวหรือเกี่ยวข้องกับการ scrape ข้อมูลหลาย ๆ งานครับ โดยการติดตั้ง requests ก็ทำได้ปกติทั่วไป</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">pip</span><span style="color:#9ECBFF"> install</span><span style="color:#9ECBFF"> requests</span></span></code></pre> <h3 id="2-ติดตั้งและใช้งานbeautifulsoup"><strong>2. ติดตั้งและใช้งาน****beautifulsoup</strong></h3> <p>BeautifulSoup คือ Python Module ที่ใช้สำหรับการดึงข้อมูลออกมาจาก HTML และ XML หรืออีกทางหนึ่งที่มักเรียกกันก็คือการสกัด (Extract) ข้อมูลออกมา</p> <p>โดยแรงบันดาลใจในการตั้งชื่อไลบรารีของผู้สร้างนั้นไม่อาจทราบได้ว่าทำไมใช้ชื่อนี้ ซึ่งถ้าแปลตามตัวเลยก็คือ “ซุปสวยงาม”</p> <p>ถ้าหากถามถึงไลบรารีของไพธอนที่ใช้สำหรับงาน web scraping นั้น beautifulsoup นั้น มันจะเป็นตัวเลือกแรก ๆ ด้วยความนิยมและความง่ายนั่นเอง</p> <p>ทำการติดตั้ง beautifulsoup4</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">pip</span><span style="color:#9ECBFF"> install</span><span style="color:#9ECBFF"> beautifulsoup4</span></span></code></pre> <hr> <h3 id="3-อิมพอร์ตไลบรารีเข้ามาใช้งานและกำหนด-url">3. อิมพอร์ตไลบรารีเข้ามาใช้งานและกำหนด URL</h3> <h3 id="ทำการเลือกเครื่องมือเข้ามาเพื่อใช้จับปลา"><em>ทำการเลือกเครื่องมือเข้ามาเพื่อใช้จับปลา</em></h3> <p>หลังจากติดตั้งทั้ง requests และ beautifulsoup เสร็จแล้ว ให้ทำการอิมพอร์ตเข้ามาใช้งาน</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#F97583">from</span><span style="color:#E1E4E8"> bs4 </span><span style="color:#F97583">import</span><span style="color:#E1E4E8"> BeautifulSoup</span></span> <span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> requests</span></span></code></pre> <p><img src="/media/django-summernote/2020-12-04/5bc627ec-e041-442c-aa6d-b9212cc0715e.jpg" alt=""></p> <p>เลือกเครื่องมือจับปลาเข้ามาพร้อมใช้ (photo: <a href="https://www.canva.com/th_th/">canva</a>)</p> <p>จากนั้นกำหนด url ที่ต้องการโดยเก็บค่าไว้ในตัวแปร url ซึ่งวิธีการนี้เราสามารถนำตัวแปร url ไปใช้ได้ทั่วทั้งโปรเจคท์ของเรา เผื่อในอนาคตได้นำไปใช้ต่อไป ซึ่งถ้าต้องการเปลี่ยนลิ้งค์ก็แก้เพียงแค่ตรงนี้ ไม่ต้อง hardcode แก้เข้าไปทุกที่</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#E1E4E8">url </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> "https://stackpython.co/courses"</span></span></code></pre> <p>ทำการดึงข้อมูลของ url โดยทำการ parse ตัว url เข้าไปใน ฟังก์ชัน requests.get( ) โดยใช้เมธอด get คือใช้ดึงข้อมูล โดยที่ resource ต้นทางไม่มีการเปลี่ยนแปลงของข้อมูล เสร็จแล้วทำการแสดงผลออกทางหน้าจอ โดยใช้ฟังก์ชัน print( ) ตามปกติ</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#E1E4E8">res </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> requests.get(url)</span></span> <span class="line"><span style="color:#E1E4E8">res.encoding </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> "utf-8"</span></span> <span class="line"><span style="color:#79B8FF">print</span><span style="color:#E1E4E8">(res)</span></span></code></pre> <p>โค้ดทั้งหมดในส่วนแรก</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#F97583">from</span><span style="color:#E1E4E8"> bs4 </span><span style="color:#F97583">import</span><span style="color:#E1E4E8"> BeautifulSoup</span></span> <span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> requests</span></span> <span class="line"></span> <span class="line"></span> <span class="line"><span style="color:#E1E4E8">url </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> "https://stackpython.co/courses"</span></span> <span class="line"></span> <span class="line"><span style="color:#E1E4E8">res </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> requests.get(url)</span></span> <span class="line"><span style="color:#E1E4E8">res.encoding </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> "utf-8"</span></span> <span class="line"><span style="color:#79B8FF">print</span><span style="color:#E1E4E8">(res)</span></span></code></pre> <p>Output</p> <p><img src="/media/django-summernote/2020-12-04/2f8b52a3-5e2c-4675-a957-a94a20bba677.png" alt=""></p> <p>request สำเร็จ ไม่มีปัญหา</p> <p>จะได้ output ก็คือ <strong>HTTP Status Code</strong> ในที่นี้คือ 200 แสดงว่าการ request นั้นสำเร็จ โดยขออธิบาย status codes ต่าง ๆ ที่ควรทราบเบื้องต้นดังนี้</p> <ul> <li>200 –> OK : การ request สำเร็จ (Success)</li> <li>301 –> Move Permanently: มีการ Redirect จาก URL เดิมไปที่ URL ใหม่</li> <li>404 –> Not Found: ไม่มีหน้าเว็บหรือ URL นี้อยู่ (Page not found)</li> <li>500 –> Internal Server Error: การข้อผิดพลาดจาก Server ภายใน</li> </ul> <p>ซึ่งนอกเหนือจากนี้ ก็มีวิธีการสังเกตในเบื้องต้นแบบง่าย ๆ ว่า HTTP Status Code ที่เห็นอยู่ในหมวดไหน ซึ่งสามารถสังเกตได้จากเลขตัวหน้าสุด</p> <ul> <li>2 –> Successful Status</li> <li>3 –> Redirection Status</li> <li>4 –> Client Error Status</li> <li>5 –> Server Error Status</li> </ul> <p>ศึกษา <a href="https://developer.mozilla.org/th/docs/Web/HTTP/Status">status code</a> เพิ่มเติม</p> <p>ซึ่งเราสามารถที่จะนำ status code มาทำการกำหนดเงื่อนไขได้</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#F97583">if</span><span style="color:#E1E4E8"> res.status_code </span><span style="color:#F97583">==</span><span style="color:#79B8FF"> 200</span><span style="color:#E1E4E8">:</span></span> <span class="line"><span style="color:#79B8FF"> print</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">"Successful"</span><span style="color:#E1E4E8">)</span></span> <span class="line"><span style="color:#F97583">elif</span><span style="color:#E1E4E8"> res.status_code </span><span style="color:#F97583">==</span><span style="color:#79B8FF"> 404</span><span style="color:#E1E4E8">:</span></span> <span class="line"><span style="color:#79B8FF"> print</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">"Error 404 page not found"</span><span style="color:#E1E4E8">)</span></span> <span class="line"><span style="color:#F97583">else</span><span style="color:#E1E4E8">:</span></span> <span class="line"><span style="color:#79B8FF"> print</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">"Not both 200 and 404"</span><span style="color:#E1E4E8">)</span></span></code></pre> <h3 id="-1">****</h3> <h3 id="-2"><img src="/media/django-summernote/2020-12-04/c0c69ec8-eced-4e1e-a2bf-08c89cce31b2.png" alt="">****</h3> <p>request สำเร็จ ไม่มีปัญหา</p> <h3 id="-3">****</h3> <h3 id="4-สร้างตัวแปรเพื่อเก็บ-object-ของ-beautifulsoup">4. สร้างตัวแปรเพื่อเก็บ object ของ BeautifulSoup</h3> <h3 id="ขั้นตอนการลากอวนหรือหว่านแหหาปลา"><em>ขั้นตอนการลากอวนหรือหว่านแหหาปลา</em></h3> <p>ทำการสร้างตัวแปรเพื่อทำการเก็บ object ของ <em>BeautifulSoup</em></p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#6A737D"> # soup = BeautifulSoup(res.text)</span></span> <span class="line"><span style="color:#E1E4E8"> soup </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> BeautifulSoup(res.text, </span><span style="color:#9ECBFF">'html.parser'</span><span style="color:#E1E4E8">)</span></span> <span class="line"><span style="color:#79B8FF"> print</span><span style="color:#E1E4E8">(soup)</span></span></code></pre> <h3 id="-4">****</h3> <p>จะได้ข้อมูลของหน้าเว็บเพจออกมาทั้งหมด</p> <h3 id="output-before">Output (Before)****</h3> <h3 id="-5"><img src="/media/django-summernote/2020-12-06/28342efc-ac20-4750-81e9-79aad4d19de2.png" alt="">****</h3> <p>ได้ข้อมูลในหน้าเว็บออกมาทั้งหมด</p> <p>ข้อมูล HTML ที่ได้แสดงออกมาทั้งหมดและค่อนข้างที่จะดูยาก ดังนั้นมีคำสั่งที่ช่วยจัดฟอร์แมตของแท็กเหล่านี้ให้เป็นระเบียบเรียบร้อย ดูง่าย</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#6A737D"> # ทำให้ข้อมูลเป็นระเบียบ ดูง่าย ด้วยคำสั่ง prettify()</span></span> <span class="line"><span style="color:#79B8FF"> print</span><span style="color:#E1E4E8">(soup.prettify())</span></span></code></pre> <hr> <p><strong>Output (After)</strong></p> <h3 id="-6"><img src="/media/django-summernote/2020-12-06/e9eaeaaa-8121-4935-a03b-addbba00f84e.png" alt="">****</h3> <p>ได้รูปแบบ HTML ที่เป็นระเบียบ ดูง่าย</p> <h3 id="-7">****</h3> <p>Note: ถ้าไม่ใส่ ‘html.parse’ จะได้คำเตือนใน terminal ของ IDE ตามด้านล่าง</p> <h3 id="-8">```</h3> <p>GuessedAtParserWarning: No parser was explicitly specified, so I’m using the best available HTML parser for this system (“html.parser”). This usually isn’t a problem, but if you run this code on another system, or in a different virtual environment, it may use a different parser and behave differently. The code that caused this warning is on line 19 of the file C:/Users/User/PycharmProjects/test-flask/new_scrape.py. To get rid of this warning, pass the additional</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span></span></span> <span class="line"><span>ในขั้นตอนนี้จะเห็นว่าเราได้ทำการดึงข้อมูลมาในหน้าเว็บทั้งหมด ซึ่งเราจะได้ทั้งแท็กและคลาสต่าง ๆ ติดมาผสมปนเปเข้ามากับข้อมูลที่เราต้องการ ซึ่งก็เปรียบเสมือนภาพด้านล่าง ซึ่งถ้าหากข้อมูล ของเราคือ ปลา เราก็ต้องมาทำการคัดเลือกปลาต่อไป</span></span> <span class="line"><span></span></span> <span class="line"><span>![](/media/django-summernote/2020-12-04/6082ab54-e653-4cd6-9cc5-d8257b70e9b1.jpg)</span></span> <span class="line"><span></span></span> <span class="line"><span>ได้กุ้ง หอย ปู ปลา มาแล้วมากมาย แต่ยังไม่ได้เลือกเอาปลาออกมา (photo: [canva](https://www.canva.com/th_th/))</span></span> <span class="line"><span></span></span> <span class="line"><span>###</span></span> <span class="line"><span></span></span> <span class="line"><span>### 5. การเข้าถึงข้อมูลใน HTML tags ต่าง ๆ</span></span> <span class="line"><span></span></span> <span class="line"><span>การเข้าถึงข้อมูลในแท็กต่าง ๆ นั้นมีคำสั่งที่สามารถเข้าถึงได้สะดวกรวดเร็ว ไม่ว่าจะเป็น tag ต่าง ๆ เช่น title, h1, p, header, a, etc ตามด้านล่างนี้ โดยทำการสร้างไฟล์ HTML แบบง่าย ๆ ขึ้นมา 1 ไฟล์ ชื่อว่า example.html เพื่อทดสอบ</span></span> <span class="line"><span></span></span> <span class="line"><span>**example.html**</span></span> <span class="line"><span></span></span> <span class="line"><span>```markup</span></span> <span class="line"><span><!DOCTYPE html></span></span> <span class="line"><span><html lang="en"></span></span> <span class="line"><span><head></span></span> <span class="line"><span> <meta charset="UTF-8"></span></span> <span class="line"><span> <title>Web Scraping Tutorial</title></span></span> <span class="line"><span></head></span></span> <span class="line"><span><body></span></span> <span class="line"><span> <div></span></span> <span class="line"><span> <h1>Heading tag</h1></span></span> <span class="line"><span> <p>Paragraph tag</p></span></span> <span class="line"><span> </div></span></span> <span class="line"><span></body></span></span> <span class="line"><span></html></span></span></code></pre> <hr> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#6A737D"># เข้าถึงข้อมูลในแท็ก title</span></span> <span class="line"><span style="color:#E1E4E8">soup.title</span></span></code></pre> <p><strong>Output</strong></p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span><title>Web Scraping Tutorial</title></span></span></code></pre> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#6A737D"># เข้าถึงข้อมูลในแท็ก h1</span></span> <span class="line"><span style="color:#E1E4E8">soup.h1</span></span></code></pre> <p>Output</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span><h1>Heading tag</h1></span></span></code></pre> <h3 id="python">```python</h3> <h1 id="เข้าถึงข้อมูลในแท็ก-p">เข้าถึงข้อมูลในแท็ก p</h1> <p>soup.p</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span></span></span> <span class="line"><span>### Output****</span></span> <span class="line"><span></span></span> <span class="line"><span>### ```</span></span> <span class="line"><span><p>Paragraph tag</p></span></span></code></pre> <h3 id="-9">****</h3> <p>การเข้าถึงข้อมูลในแท็กตามตัวอย่างด้านบนจะเห็นว่า จะได้ HTML tags ติดมากับข้อมูลที่ต้องการด้วย ดังนั้นจึงจำเป็นต้องลบแท็กออก สามารถทำได้อย่างง่ายดาย โดยใช้คำสั่ง string ต่อท้ายแท็ก</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#6A737D"># เข้าถึงข้อมูลในแท็ก title และทำการดึงออกมาเฉพาะข้อมูลที่ไม่ติดแท็ก</span></span> <span class="line"><span style="color:#E1E4E8">soup.title.string</span></span></code></pre> <h3 id="output">Output</h3> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>Web Scraping Tutorial</span></span></code></pre> <p>ซึ่งการเข้าถึงข้อมูลในแท็กเหล่านี้โดยตรง นับได้ว่าเป็นวิธีที่ค่อนข้างง่าย สะดวกรวดเร็ว แต่ในทำนองเดียวกันก็มีข้อจำกัด คือสามารถเข้าถึงข้อมูลลำดับแรกของแท็กนี้เท่านั้น แน่นอนว่าในแต่ละเว็บเพจไม่ได้มีแท็กเหล่านี้เพียงแค่แท็กเดียว ถ้าหากเราต้องการเข้าถึงข้อมูลที่ซับซ้อนมากขึ้นและค้นหาทั้งหมด ก็จะมีเมธอดหรืออีกคำสั่งหนึ่งให้ใช้ก็คือ find_all( )</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#6A737D"># ค้นหาข้อมูลทั้งหมดที่อยู่ในแท็ก a</span></span> <span class="line"><span style="color:#E1E4E8">soup.find_all(</span><span style="color:#9ECBFF">'a'</span><span style="color:#E1E4E8">)</span></span></code></pre> <h3 id="6-extracting-andcleaning-data"><strong>6.</strong> <strong>Extracting and****Cleaning data</strong></h3> <p><em><strong>ขั้นตอนเลือกเอาปลาที่ต้องการ</strong></em></p> <p>เมื่อทำการ scrape ข้อมูลมาจากหน้าเว็บเพจเรียบร้อยแล้ว แต่ก็ยังไม่เพียงพอที่จะนำข้อมูลนั้นไปใช้ครับ ดังนั้นจึงต้องมีขึ้นตอนที่เรียกว่า การทำความสะอาดข้อมูล (Cleaning Data) นั่นเองครับ เพื่อให้ข้อมูลอยู่ในฟอร์แมตที่พร้อมใช้งานต่อไป</p> <p><strong>ลิ้งค์เป้าหมาย:</strong><a href="https://stackpython.co/courses">Python Courses - คอร์สเรียนไพธอน</a></p> <h2 id="google-dev-tools">Google Dev Tools</h2> <p>เราสามารถเรียกดูแท็กต่าง ๆ ได้ผ่านหน้าเว็บเพจโดยผ่านเครื่องมือตัวหนึ่งที่มีชื่อว่า “Google Dev Tools” สามารถใช้งานโดยทำการ <strong>คลิ๊กขวา</strong>ที่หน้าเว็บเพจ –><strong>Inspect</strong></p> <p><img src="/media/django-summernote/2020-12-06/e46a633d-65db-48b1-8d7e-d4e2c3701552.png" alt=""></p> <p>Google Dev Tools เพื่อหาแท็ก</p> <p>ปลา (เป้าหมายของเรา) จะอยู่ในแท็กนี้</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span><h2 class="title-single title-a>Python Web Development with Flask</h2></span></span></code></pre> <p>เมื่อทราบเรียบร้อยว่าข้อมูลที่ต้องการอยู่ในแท็กอะไร ซึ่งในหน้าเว็บนี้ก็คือ “<strong>h2</strong>” ก็ถึงเวลาที่จะทำการดึงข้อมูลนั้นออกมา</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#6A737D"># เข้าถึงรายชื่อของคอร์สโดยผ่านแท็ก h2</span></span> <span class="line"><span style="color:#E1E4E8">courses </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> soup.find_all(</span><span style="color:#9ECBFF">'h2'</span><span style="color:#E1E4E8">)</span></span></code></pre> <p>จะได้ออปเจคท์ซึ่งจะเป็นฟอร์แมตในรูปแบบของ List</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>[<h2 class="title-single title-a">คอร์สเรียนทั้งหมด</h2>, <h2 class="title-single title-a">Python Web Development with Flask</h2>, <h2 class="title-single title-a">Python Web Development with Django</h2>, <h2 class="title-single title-a">Introduction to Python Programming</h2>, <h2 class="title-single title-a">Basic Machine Learning with Python</h2>, <h2 class="title-single title-a">Buy 2 get 2 Course</h2>, <h2 class="title-single title-a">Full Stack Vue.js with Flask (REST Api)</h2>, <h2 class="title-single title-a">All in one Course (5 in 1)</h2>, <h2 class="title-single title-a">Django Wagtail CMS</h2>]</span></span></code></pre> <p>ทำการลูปข้อมูลที่อยู่ในลิสต์ออกมา พร้อมทั้งเก็บเข้าไปในตัวแปรลิสต์ที่ว่างเปล่า จะได้ final object หรือชุดข้อมูลสุดท้ายที่ต้องการ</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#6A737D"># Create an empty list</span></span> <span class="line"><span style="color:#E1E4E8">course_list </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> []</span></span> <span class="line"></span> <span class="line"><span style="color:#F97583">for</span><span style="color:#E1E4E8"> course </span><span style="color:#F97583">in</span><span style="color:#E1E4E8"> courses:</span></span> <span class="line"><span style="color:#E1E4E8"> </span></span> <span class="line"><span style="color:#6A737D"> # Create a new variable --> obj to store </span></span> <span class="line"><span style="color:#6A737D"> # only course name getting rid of unwanted tags</span></span> <span class="line"><span style="color:#E1E4E8"> obj </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> course.string</span></span> <span class="line"><span style="color:#E1E4E8"> </span></span> <span class="line"><span style="color:#6A737D"> # Append each course into a course_list variable</span></span> <span class="line"><span style="color:#E1E4E8"> course_list.append(obj)</span></span></code></pre> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#6A737D"># ปริ้นซ์ข้อมูลในออปเจคท์ออกมาดู</span></span> <span class="line"><span style="color:#79B8FF">print</span><span style="color:#E1E4E8">(course_list)</span></span></code></pre> <p>Output</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>['คอร์สเรียนทั้งหมด', 'Python Web Development with Flask', 'Python Web Development with Django', 'Introduction to Python Programming', 'Basic Machine Learning with Python', 'Buy 2 get 2 Course', 'Full Stack Vue.js with Flask (REST Api)', 'All in one Course (5 in 1)', 'Django Wagtail CMS']</span></span></code></pre> <p><img src="/media/django-summernote/2020-12-04/55b0f22f-20bb-4b08-bed1-69508c7b7186.jpg" alt=""></p> <p>เลือกออกมาเรียบร้อย สิ่งที่ต้องการคือปลาแซลมอน (photo: <a href="https://www.canva.com/th_th/">canva</a>)</p> <h3 id="7-บันทึกไฟล์เป็นcsv">**7. บันทึกไฟล์เป็น****CSV</h3> <p>format**</p> <p><em>ขั้นตอนเก็บปลาใส่ในภาชนะที่ต้องการ</em>****</p> <h3 id="-10">****</h3> <p>หลังจากที่เราได้ทำการ scrape และ clean ข้อมูลจนได้ข้อมูลที่ต้องการแล้วเรียบร้อย ขั้นตอนสุดท้ายก็คือการบันทึกข้อมูลเก็บไว้ใช้งานต่อไป โดยในบทความนี้จะทำการบันทึกในรูปแบบของ CSV ไฟล์ ซึ่งเป็นหนึ่งในฟอร์แมตที่ได้รับความนิยมอย่างสูง และใน Python มี Built-in Library ที่มีชื่อว่า csv ให้สามารถเรียกใช้งานเกี่ยวกับการจัดการ CSV ไฟล์ต่าง ๆ โดยอิมพอร์ตเข้ามาใช้งานได้เลย</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> requests</span></span> <span class="line"><span style="color:#F97583">from</span><span style="color:#E1E4E8"> bs4 </span><span style="color:#F97583">import</span><span style="color:#E1E4E8"> BeautifulSoup</span></span> <span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> csv </span><span style="color:#6A737D"># New</span></span></code></pre> <p>จากนั้นทำการสร้างตัวแปรที่มีชื่อว่า csv_col โดยในตัวแปรนี้จะทำการเก็บข้อมูลในรูปแบบ Nested List (ลิสต์ซ้อนลิสต์) โดย</p> <ul> <li>‘title’ index 0 (ตำแหน่งแรก) จะเป็น ชื่อคอลัมน์ ที่เรากำหนดขึ้นมาเอง</li> <li>course_list index 1 (ตำแหน่งที่ 2) จะเป็น ข้อมูลที่อยู่ในคอลัมน์ นั้น โดยข้อมูลนี้มาจากออปเจคท์ที่เรา scrape ข้อมูลโดยใช้ beautifulsoup นั่นเอง</li> </ul> <p><code># Define row and column (DataFrame) csv_col = [['title'], [course_list]]</code></p> <p>ทำการกำหนดตัวแปร f เพื่อเก็บข้อมูลในฟังก์ชัน open( ) นี่คือ Built-in function ของไพธอน ที่ใช้สำหรับเปิดไฟล์ โดย</p> <ul> <li>course_titles ชื่อไฟล์ที่ต้องการสร้าง</li> <li>w โหมดของไฟล์นี้ โดย w = write คือเขียนไฟล์ ถ้าเป็นอ่านไฟล์จะใช้ r นั่นก็คือ read นั่นเอง</li> </ul> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#6A737D"># Name a file, and put w as an argument to tell this is "writer" file</span></span> <span class="line"><span style="color:#E1E4E8">f </span><span style="color:#F97583">=</span><span style="color:#79B8FF"> open</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">'course_titles.csv'</span><span style="color:#E1E4E8">, </span><span style="color:#9ECBFF">'w'</span><span style="color:#E1E4E8">)</span></span></code></pre> <p>โดยโมดูล CSV จะมีเมธอดที่มีชื่อว่า <em>writer( )</em> ซึ่งเอาไว้ใช้สำหรับเขียนไฟล์ ในทางกลับกันถ้าอ่านไฟลจะใช้เมธอด <em>reader( )</em> ซึ่งการเรียกใช้เมธอดก็ทำได้ปกติโดยผ่านตัวโมดูลก็คือ <em>csv</em> ก็จะสามารถเรียกใช้คำสั่งอ่านหรือเขียน CSV ไฟล์ ได้</p> <p>เมื่อทำการกำหนดตัวแปร writer เรียบร้อยแล้ว โดยจะเก็บออปเจคท์ของ <em>csv.writer(f)</em> ซึ่งในบรรทัดสุดท้ายจะทำให้สามารถเข้าถึงเมธอด <em>writerow( )</em> ได้ โดย <em>writerow( )</em> นั้นจะทำการเขียน <em>row</em> ทั้งหมดที่ได้ถูก for loop ออกมาเก็บไว้ในไฟล์ course_titles.csv ที่ได้กำหนดไว้ในเมธอด <em>open( )</em></p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#F97583">with</span><span style="color:#E1E4E8"> f:</span></span> <span class="line"><span style="color:#E1E4E8"> writer </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> csv.writer(f)</span></span> <span class="line"></span> <span class="line"><span style="color:#F97583"> for</span><span style="color:#E1E4E8"> row </span><span style="color:#F97583">in</span><span style="color:#E1E4E8"> csv_col:</span></span> <span class="line"><span style="color:#E1E4E8"> writer.writerow(row)</span></span></code></pre> <p><strong>โค้ดเขียนไฟล์ CSV</strong></p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#6A737D"># Define row and column (Dataframe)</span></span> <span class="line"><span style="color:#E1E4E8">col_csv </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> [[</span><span style="color:#9ECBFF">'title'</span><span style="color:#E1E4E8">], [index_sel_tag]]</span></span> <span class="line"></span> <span class="line"><span style="color:#6A737D"># Name a file, and put w as an argument to tell this is "writer" file</span></span> <span class="line"><span style="color:#E1E4E8">f </span><span style="color:#F97583">=</span><span style="color:#79B8FF"> open</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">'filename.csv'</span><span style="color:#E1E4E8">, </span><span style="color:#9ECBFF">'w'</span><span style="color:#E1E4E8">)</span></span> <span class="line"><span style="color:#F97583">with</span><span style="color:#E1E4E8"> f:</span></span> <span class="line"><span style="color:#E1E4E8"> writer </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> csv.writer(f)</span></span> <span class="line"></span> <span class="line"><span style="color:#F97583"> for</span><span style="color:#E1E4E8"> row </span><span style="color:#F97583">in</span><span style="color:#E1E4E8"> csv_col:</span></span> <span class="line"><span style="color:#E1E4E8"> writer.writerow(row)</span></span></code></pre> <p><img src="/media/django-summernote/2020-12-07/cd1809a6-feb6-4b6c-8b3e-62d4b9fa0fe2.jpg" alt=""></p> <p>เก็บปลาลงในถัง (CSV) เรียบร้อย (photo: <a href="https://www.canva.com/th_th/">canva</a>)</p> <h2 id="requests-limitation">Requests limitation</h2> <p>การที่เราทำ web scraping นั้น นั่นก็หมายถึงเรากำลังทำการ request ข้อมูลไปที่ server ของเว็บนั้น ๆ แน่นอนว่ามันจะเกิดการ request ไปที่เซิร์ฟเวอร์นั้น ๆ มากจนเกินไป อาจทำให้ IP ของเราโดนบล็อกจากเจ้าของเว็บไซต์ (Website Owner) นั้นได้ ดังนั้นเราก็มีวิธีแก้ปัญหาได้เบื้องต้น เช่น ทำการหน่วงเวลาการ scrape ข้อมูลสัก 10 - 20 วินาที เป็นต้น โดยการหน่วงเวลาหรือ delay นี้ ในไพธอนจะมี built-in library คือ time ซึ่งสามารถอิมพอร์ตเข้ามาใช้ได้ทันที และสามารถเรียกใช้เมธอดที่มีชื่อว่า sleep( ) โดยถ้าอยากหน่วง 10 วินาที ก็สามารถทำได้โดย sleep(10) อันนี้แค่เกริ่นคร่าว ๆ รายละเอียดเพิ่มเติมจะอยู่ใน Part 2</p> <h2 id="การนำข้อมูลที่ได้จากการทำweb">**การนำข้อมูลที่ได้จากการทำ****web</h2> <p>scraping ไปใช้งาน**</p> <p><em>ขั้นตอนนำปลาไปปรุงอาหาร</em> ****</p> <p>หลังจากที่เราได้ทำการ scrape ข้อมูลในหน้า webpage ออกมาและทำการบันทึกข้อมูลในรูปแบบ CSV เรียบร้อย จากนั้นก็ขึ้นอยู่กับว่าจะนำข้อมูลไปทำอะไรต่อไป เช่น นำไปวิเคราะห์ (Data Analysis), นำไปแสดงผลในรูปแบบต่าง ๆ (Data Visualization), นำไปเป็น Dataset เพื่อใช้กับโปรเจคท์ Machine Learning, ฯลฯ เป็นต้น</p> <p><img src="/media/django-summernote/2020-12-04/54894369-735f-4b77-a59f-397f9c9f3561.jpg" alt=""></p> <p>จะนำไปทำอะไร ก็สุดแล้วแต่ต้องการ ในภาพคือกำลังจะนำไปทำลาบ ;)(photo: <a href="https://www.canva.com/th_th/">canva</a>)</p> <p><img src="/media/django-summernote/2020-12-07/be54910b-e73e-4cfa-a115-b2eac3f86ca1.png" alt=""></p> <p>เอาไปทำเกี่ยวกับงาน Data Visualiztion เช่นกราฟต่าง ๆ (Photo: <a href="https://matplotlib.org/gallery/lines_bars_and_markers/categorical_variables.html#sphx-glr-gallery-lines-bars-and-markers-categorical-variables-py">matplotlib.org</a>)</p> <p>Final Code</p> <p>scraping.py</p> <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#F97583">from</span><span style="color:#E1E4E8"> bs4 </span><span style="color:#F97583">import</span><span style="color:#E1E4E8"> BeautifulSoup</span></span> <span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> requests</span></span> <span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> csv</span></span> <span class="line"></span> <span class="line"></span> <span class="line"><span style="color:#E1E4E8">url </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> "https://stackpython.co/courses"</span></span> <span class="line"></span> <span class="line"><span style="color:#E1E4E8">res </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> requests.get(url)</span></span> <span class="line"><span style="color:#E1E4E8">res.encoding </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> "utf-8"</span></span> <span class="line"><span style="color:#79B8FF">print</span><span style="color:#E1E4E8">(res)</span></span> <span class="line"></span> <span class="line"><span style="color:#E1E4E8">soup </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> BeautifulSoup(res.text, </span><span style="color:#9ECBFF">'html.parser'</span><span style="color:#E1E4E8">)</span></span> <span class="line"><span style="color:#6A737D"># print(soup)</span></span> <span class="line"><span style="color:#6A737D"># print(soup.prettify())</span></span> <span class="line"></span> <span class="line"><span style="color:#E1E4E8">courses </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> soup.find_all(</span><span style="color:#9ECBFF">'h2'</span><span style="color:#E1E4E8">)</span></span> <span class="line"><span style="color:#79B8FF">print</span><span style="color:#E1E4E8">(courses)</span></span> <span class="line"></span> <span class="line"><span style="color:#6A737D"># Create an empty list</span></span> <span class="line"><span style="color:#E1E4E8">course_list </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> []</span></span> <span class="line"></span> <span class="line"><span style="color:#F97583">for</span><span style="color:#E1E4E8"> course </span><span style="color:#F97583">in</span><span style="color:#E1E4E8"> courses:</span></span> <span class="line"></span> <span class="line"><span style="color:#6A737D"> # Create new variable --> obj to store</span></span> <span class="line"><span style="color:#6A737D"> # only course name getting rid of unwanted tags</span></span> <span class="line"><span style="color:#E1E4E8"> obj </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> course.string</span></span> <span class="line"></span> <span class="line"><span style="color:#6A737D"> # Append each course into a course_list variable</span></span> <span class="line"><span style="color:#E1E4E8"> course_list.append(obj)</span></span> <span class="line"></span> <span class="line"></span> <span class="line"><span style="color:#79B8FF">print</span><span style="color:#E1E4E8">(course_list)</span></span> <span class="line"></span> <span class="line"><span style="color:#6A737D"># Define row and column (DataFrame)</span></span> <span class="line"><span style="color:#E1E4E8">csv_col </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> [[</span><span style="color:#9ECBFF">'title'</span><span style="color:#E1E4E8">], [course_list]]</span></span> <span class="line"></span> <span class="line"><span style="color:#6A737D"># Name a file, and put w as an argument to tell this is "writer" file</span></span> <span class="line"><span style="color:#E1E4E8">f </span><span style="color:#F97583">=</span><span style="color:#79B8FF"> open</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">'filename.csv'</span><span style="color:#E1E4E8">, </span><span style="color:#9ECBFF">'w'</span><span style="color:#E1E4E8">)</span></span> <span class="line"><span style="color:#F97583">with</span><span style="color:#E1E4E8"> f:</span></span> <span class="line"><span style="color:#E1E4E8"> writer </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> csv.writer(f)</span></span> <span class="line"></span> <span class="line"><span style="color:#F97583"> for</span><span style="color:#E1E4E8"> row </span><span style="color:#F97583">in</span><span style="color:#E1E4E8"> csv_col:</span></span> <span class="line"><span style="color:#E1E4E8"> writer.writerow(row)</span></span> <span class="line"></span> <span class="line"><span style="color:#6A737D"># Display type of this object (Of course, it's "list")</span></span> <span class="line"><span style="color:#79B8FF">print</span><span style="color:#E1E4E8">(</span><span style="color:#79B8FF">type</span><span style="color:#E1E4E8">(course_list))</span></span> <span class="line"></span> <span class="line"><span style="color:#6A737D"># Test accessing position 1 of the list</span></span> <span class="line"><span style="color:#79B8FF">print</span><span style="color:#E1E4E8">(course_list[</span><span style="color:#79B8FF">1</span><span style="color:#E1E4E8">])</span></span> <span class="line"></span> <span class="line"><span style="color:#6A737D"># To count how many courses in the list</span></span> <span class="line"><span style="color:#79B8FF">print</span><span style="color:#E1E4E8">(</span><span style="color:#79B8FF">len</span><span style="color:#E1E4E8">(course_list))</span></span></code></pre> <h2 id="สรุป"><strong>สรุป</strong></h2> <p>ข้อสรุปโดยรวมที่ได้หลังจากอ่านบทความนี้จบ</p> <ul> <li>ควรรู้พื้นฐานภาษาโปรแกรมมิ่งที่เกี่ยวข้องเบื้องต้น เช่น Python และ HTML ก่อนเรียน Web Scraping พร้อมทั้งตั้งเป้าหมาย</li> <li>ควรศึกษาข้อกำหนดของเว็บที่ต้องการจะดึงข้อมูลให้มั่นใจเสียก่อน เพื่อที่จะได้ไม่ขัดหรือล่วงละเมิดต่อข้อกำหนดของเว็บนั้น ๆ ทำอย่างไรถึงจะทำ web scraping แล้วจะไม่โดนแบนหรือบล็อกจาก website หรือ web server ปลายทาง</li> <li>การทำ Web Scraping นั้นไม่ได้มีอาชีพที่ชื่อว่า web scraping โดยตรง เหมือนกับอาชีพอื่น ๆ เช่น Backend/Frontend Developer, Data Scientist, Machine Learning Engineer, etc แต่ว่าการที่รู้และสามารถทำ Web Scraping ได้ ก็เท่ากับว่าเป็นการเพิ่มสกิลให้กับตัวเอง เผื่อเป็นอีกหนึ่งทักษะที่สามารถนำไปทำมาหากินหรือประยุกต์เข้ากับงานอื่น ๆ ได้</li> </ul> <p>ก็จบลงไปเรียบร้อยกับบทความ Web Scraping โดยการใช้ BeautifulSoup จากทาง STACKPYTHON ผู้เขียนหวังว่า ผู้อ่านทุกท่านที่ได้อ่านบทความนี้จนจบ (ขอขอบคุณสำหรับท่านที่อ่านจนจบ) จะได้ทำความรู้จักและเข้าใจเกี่ยวกับการทำ Web Scraping ในเกือบจะทุก ๆ มิติ และยังได้ทดสอบทำการ Scrape ข้อมูลและทำการบันทึกเก็บลงในฟอร์แมตยอดนิยมอย่าง CSV เพื่อนำไปใช้งานต่อไป ซึ่งนี่เรียกได้ว่าความสำเร็จก้าวแรกกันแล้ว ซึ่งแน่นอนว่า เราจะต้องต่อยอดขึ้นไปในระดับที่สูงและซับซ้อนมากยิ่งขึ้น โดยจะมีการทำเป็นคลิปของซีรียนี้ลงในช่อง <a href="https://www.youtube.com/c/stackpython/videos">YouTube</a> ของเรา ท่านใดที่ยังไม่ได้กด subscribe ก็กดไว้ได้เลยครับ มีเนื้อหาดี ๆ น่าสนใจอยู่หลากหลายเนื้อหาในนั้น</p> <p><strong>“ถ้ามีคำถามหรือข้อเสนอแนะหรือฟีดแบ็คตรงส่วนไหน สามารถคอมเมนต์เข้ามาที่คอมเมนต์ด้านล่างบทความนี้กันได้เลย ซึ่งสิ่งเหล่านี้มีความหมายต่อการเขียนบทความมาก”</strong></p> <p>ขอขอบคุณทุกท่านที่อ่านจนจบ พบกันอีกครั้งในบทความถัดไป ขอให้มีความสุขและสนุกในการเรียนรู้ เข้าหน้าหนาวแล้ว รักษาสุขภาพกันด้วยนะครับ</p> <p><strong>| Like | Comment | Share | >> STACKPYTHON</strong></p> <blockquote> <blockquote> <p>📒<a href="https://stackpython.co/courses">Python Web Courses</a></p> </blockquote> </blockquote> <p>Reference</p> <p><a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/">Beautiful Soup Documentation</a></p> <h3 id="-11">****</h3> </article></main><footer class="site-footer"><div class="shell footer-grid"><div><strong>STACKPYTHON</strong><p>Full Stack Python Developers.</p></div><div><strong>Focusing On</strong><ul><li><a href="/category/web-development/">Web Development</a></li><li><a href="/category/python-fundamentals/">Python Fundamentals</a></li><li><a href="/programming-news/">Programming News</a></li></ul></div></div></footer></body></html>