Playwright: สกิมเว็บแบบไม่ปวดหัวเรื่องไดรเวอร์!
สวัสดีคร้าบ! วันนี้จะมาแนะนำเครื่องมือสำหรับทำเว็บสแครปปิ้ง (Web Scraping) ที่ส่วนตัวผมรู้สึกว่ามันสะดวกกว่า Selenium เยอะเลย โดยเฉพาะเรื่องการจัดการ browser driver เนี่ยะ คือมันจบในตัวเลย ไม่ต้องมานั่งหาเวอร์ชั่นให้ตรงกัน ไม่ต้องลง WebDriver Manager ให้วุ่นวาย
เครื่องมือนั้นก็คือ Playwright นั่นเองครับ!
เอาจริง ๆ Playwright มันถูกสร้างมาเพื่อทำ End-to-End Testing แหละ แต่มันทำงานกับเบราว์เซอร์จริง ๆ ได้ดีมาก ทำให้เอามาประยุกต์ใช้กับงานสแครปปิ้งได้โคตรจะเทพ เพราะมันรองรับ Chrome, Firefox, Safari ได้หมดเลยในโค้ดชุดเดียว
เริ่มต้นใช้งาน
ก่อนอื่นก็ติดตั้งก่อนเลยครับ:
pip install playwright
playwright install
ขั้นตอน playwright install นี่สำคัญมากนะ! ย้ำว่าสำคัญมาก! เพราะถ้าไม่รันตัวนี้ คุณจะเจอ error แบบว่า playwright.sync_api._generated.PlaywrightException: BrowserType.launch: Executable doesn't exist at ... คือมันจะฟ้องว่าหาไฟล์ browser ไม่เจอไง
ตอนแรกผมก็งงๆ ว่าทำไมรันไม่ได้ หาใน Stack Overflow อ๋อออออ... ลืมรันตัวนี้แหละครับ ง่ายๆ เลยแต่พลาดประจำ 😅
มาลองเขียนโค้ดสแครปกัน
ผมจะลองสแครปเว็บ http://quotes.toscrape.com/js/ ซึ่งเป็นเว็บตัวอย่างที่โหลด quote มาแบบ JavaScript นะครับ ถ้าใช้แค่ requests ปกติจะไม่ได้ข้อมูลตรงนี้มา
เปิดไฟล์ .py ขึ้นมาแล้วแปะโค้ดนี้เลย
from playwright.sync_api import sync_playwright
def scrape_quotes():
print("-- เริ่มสแครปเว็บ quotes.toscrape.com/js/ ---")
with sync_playwright() as p:
# เปิด browser (chromium, firefox, webkit)
# headless=True คือไม่เปิดหน้าต่าง browser ให้เห็น ถ้าอยากดูให้เปลี่ยนเป็น False
browser = p.chromium.launch(headless=True)
page = browser.new_page()
# ไปที่ URL เป้าหมาย
page.goto("http://quotes.toscrape.com/js/")
print(f"เปิดหน้าเว็บ: {page.url}")
# รอให้เนื้อหาโหลดเสร็จ (รอ selector ของ quote class โหลด)
# อันนี้สำคัญมากสำหรับเว็บที่โหลด content ด้วย JS
page.wait_for_selector(".quote")
quotes_data = []
# วนลูปหา quote ทั้งหมดในหน้านั้น
quotes = page.locator(".quote").all()
for quote in quotes:
text = quote.locator(".text").inner_text()
author = quote.locator(".author").inner_text()
# tags นี่อาจจะยากหน่อย เพราะมันมีหลายอัน เราต้องใช้ .all_inner_texts()
tags_elements = quote.locator(".tag")
tags = tags_elements.all_inner_texts() # ได้เป็น list ของ tag strings
quotes_data.append({
"text": text.strip(),
"author": author.strip(),
"tags": tags
})
browser.close()
print("-- สแครปเสร็จแล้ว! --- ")
return quotes_data
if __name__ == "__main__":
data = scrape_quotes()
for q in data:
print(f"\nQuote: {q['text']}")
print(f"Author: {q['author']}")
print(f"Tags: {', '.join(q['tags'])}")
# print(f"ข้อมูลที่ได้ทั้งหมด: {data}")
อธิบายโค้ดนิดหน่อย
with sync_playwright() as p:: นี่คือจุดเริ่มต้นของการใช้งาน Playwright ครับ. ตัวpนี่แหละที่เราจะใช้ไปเปิด browser.p.chromium.launch(headless=True): เราสั่งให้มันเปิด browser Chromium ขึ้นมาครับ ถ้าheadless=Trueก็คือมันจะทำงานเบื้องหลัง ไม่เปิดหน้าต่าง browser ให้เราเห็น (ซึ่งเหมาะกับงานสแครปปิ้งมาก).page.goto("URL"): ให้ browser ไปที่ URL ที่เราต้องการpage.wait_for_selector(".quote"): อันนี้คือพระเอกเลย สำหรับเว็บที่โหลดข้อมูลด้วย JavaScript! เราสั่งให้ Playwright รอจนกว่า element ที่มี class.quoteจะปรากฏบนหน้าจอ ถ้าไม่ใส่ตรงนี้ บางทีข้อมูลอาจจะยังไม่โหลดมาครบ เราก็จะสแครปพลาดได้นะpage.locator(".quote").all(): อันนี้คล้ายๆ กับfind_elements_by_class_nameใน Selenium แหละ แต่ Playwright ใช้locatorซึ่งผมว่ามันอ่านง่ายดีกว่าinner_text()/all_inner_texts(): ใช้ดึงข้อความจาก element ครับ
ความรู้สึกส่วนตัวนะ
ตั้งแต่ผมลองใช้ Playwright มาเนี่ยะ ผมรู้สึกว่ามันค่อนข้างเสถียรมาก และที่สำคัญคือมันเร็ว! แถมยังมีฟังก์ชัน wait_for_selector ที่ทำให้จัดการเว็บที่โหลดข้อมูลด้วย AJAX หรือ JavaScript ได้ง่ายขึ้นเยอะ
ส่วนตัวผมชอบกว่า Selenium (สำหรับงานสแครปปิ้งนะ) เพราะเรื่อง driver มันจบจริงๆ ไม่ต้องมานั่งลุ้นว่าวันนี้ไดรเวอร์จะหมดอายุไหม หรือเวอร์ชั่นเบราว์เซอร์อัปเดตแล้วต้องมาหาไดรเวอร์ใหม่มั้ย
ลองเอาไปใช้กันดูนะครับ หวังว่าจะช่วยให้ชีวิตการสแครปของคุณง่ายขึ้น!