Scarnox · Blog

วิธี scrape เว็บไซต์ที่เรนเดอร์ด้วย JavaScript

เว็บไซต์สมัยใหม่จำนวนมากส่ง HTML เกือบว่างเปล่ามาให้ และสร้างเนื้อหาในเบราว์เซอร์ด้วย JavaScript หาก scraper ของคุณดึงหน้าแล้วไม่พบสินค้า ราคา หรือเนื้อหาบทความ เนื้อหาจริงมีอยู่ แต่มาถึงทีหลัง คู่มือนี้แสดงวิธีแยกว่าหน้าเป็นแบบไหน วิธีหาเส้นทางที่เร็วกว่าเบราว์เซอร์เมื่อมีอยู่ และวิธี scrape หน้าที่เรนเดอร์แล้วด้วย Playwright ใน Python คู่มือจบด้วยหมายเหตุว่าควรทำอย่างไรเมื่อหน้าที่เรนเดอร์แล้วแสดง captcha

ขั้นตอนที่ 1: ตรวจว่าเนื้อหาอยู่ใน HTML หรือไม่

เปิดหน้าด้วย view-source: ในเบราว์เซอร์ของคุณ หรือดึงด้วย HTTP request ธรรมดา แล้วค้นหาข้อความที่คุณเห็นบนหน้าจอในซอร์ส มีสามผลลัพธ์ที่พบบ่อย:

ขั้นตอนที่ 2: เรียก JSON endpoint หากมี

เมื่อหน้าดึงข้อมูลจาก endpoint การเรียก endpoint นั้นโดยตรงมักเป็นตัวเลือกที่ดีที่สุด เพราะมีขนาดเล็ก เร็ว และเสถียรกว่าหน้าที่เรนเดอร์แล้ว คัดลอก URL ของ request ตรวจว่าเว็บไซต์ต้องการ header ใดบ้าง แล้วลองจากสคริปต์ ทำแบบนี้เฉพาะเมื่อข้อกำหนดของเว็บไซต์อนุญาต และเคารพ rate limit หรือการยืนยันตัวตนที่เว็บไซต์คาดหวัง endpoint ที่ไม่ได้เปิดเผยเป็นทางการอาจเปลี่ยนโดยไม่แจ้งล่วงหน้า ดังนั้นให้เขียน parser ของคุณให้ล้มดังชัดเจนเมื่อโครงสร้างของการตอบกลับเปลี่ยน

ขั้นตอนที่ 3: เรนเดอร์หน้าเมื่อจำเป็นจริง ๆ

หากเนื้อหาต้องใช้เบราว์เซอร์จริง ให้ควบคุม headless browser Playwright เป็นตัวเลือกที่ดีสำหรับ Python ตัวอย่างด้านล่างเปิดหน้ารายการสินค้า รอให้เนื้อหาปรากฏ และอ่านข้อความจากการ์ดแต่ละใบ:

from playwright.sync_api import sync_playwright

URL = "https://example.com/products"  # หน้าที่คุณได้รับอนุญาตให้ scrape

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto(URL, wait_until="domcontentloaded", timeout=60_000)
    # รอ element ที่พิสูจน์ว่าข้อมูลมาถึงแล้ว
    page.wait_for_selector(".product-card", timeout=30_000)
    titles = page.locator(".product-card h2").all_inner_texts()
    browser.close()

for title in titles:
    print(title)

การรอ selector ที่เฉพาะเจาะจงเชื่อถือได้มากกว่า sleep แบบคงที่มาก การหยุดคงที่สั้นเกินไปในวันที่ช้า หรือเสียเวลาในวันที่เร็ว เลือก element ที่ปรากฏเฉพาะเมื่อข้อมูลโหลดเสร็จแล้ว

ขั้นตอนที่ 4: จัดการ infinite scroll และการแบ่งหน้า

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

def scroll_until_done(page, selector: str, max_rounds: int = 20) -> int:
    previous = -1
    for _ in range(max_rounds):
        count = page.locator(selector).count()
        if count == previous:
            break
        previous = count
        page.mouse.wheel(0, 4000)
        page.wait_for_timeout(1500)  # ให้เวลาชุดถัดไปโหลด
    return previous

ขั้นตอนที่ 5: ใช้เบราว์เซอร์อย่างประหยัด

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

def block_heavy_assets(route):
    if route.request.resource_type in ("image", "font", "media"):
        route.abort()
    else:
        route.continue_()

page.route("**/*", block_heavy_assets)

ขั้นตอนที่ 6: เมื่อหน้าที่เรนเดอร์แล้วแสดง captcha

บางครั้งหน้าที่เรนเดอร์แล้วแสดง captcha ก่อนที่จะแสดงเนื้อหาใด ๆ หาก captcha นั้นเป็น PopularCaptcha ซึ่งเป็น captcha ที่ใช้งานได้จริงบน Scarnox ให้อ่าน sitekey จากหน้า ขอ token และวาง token ลงในฟิลด์ฟอร์มที่เว็บไซต์คาดหวัง คู่มือ PopularCaptcha ด้วย Python จะพาคุณผ่านขั้นตอนนั้น widget อื่นยังไม่พร้อมใช้งาน ดังนั้นให้ตรวจ ประเภทของ captcha ที่ควรรู้ ก่อนวางแผนใช้งานตัวใดตัวหนึ่ง

ระวังเรื่องตัวเบราว์เซอร์ด้วย เบราว์เซอร์ headless ที่ดูเป็นระบบอัตโนมัติอย่างชัดเจนอาจกระตุ้นการตรวจเพิ่มเติม แทนที่จะลดลง อ่าน การตรวจจับ headless browser เพื่อดูสัญญาณที่ต้องระวัง และเลือกการโหลดหน้าที่ช้าลงและน้อยลง

Scrape อย่างมีความรับผิดชอบ

ขั้นตอนถัดไป

เริ่มต้นด้วยเครดิตทดลองใช้ฟรี ไม่ต้องใช้บัตรเครดิต: สร้างบัญชี แล้วทดสอบ flow ของ PopularCaptcha บนหน้าที่คุณเป็นเจ้าของ ดูอัตราค่าบริการปัจจุบันได้ที่ หน้าราคา