Scarnox · Blog

Cách scrape các website được render bằng JavaScript

Nhiều website hiện đại gửi một tài liệu HTML gần như trống và xây dựng nội dung trong trình duyệt bằng JavaScript. Nếu scraper của bạn tải trang và không thấy sản phẩm, giá hay nội dung bài viết nào, thì nội dung vẫn ở đó, chỉ là đến muộn hơn. Hướng dẫn này chỉ cách nhận biết bạn đang gặp loại trang nào, cách tìm một đường nhanh hơn trình duyệt khi có, và cách scrape trang đã render bằng Playwright với Python. Cuối bài có một lưu ý về việc phải làm gì khi trang đã render hiển thị captcha.

Bước 1: kiểm tra nội dung có nằm trong HTML không

Mở trang bằng view-source: trong trình duyệt của bạn, hoặc tải nó bằng một request HTTP đơn giản, rồi tìm trong mã nguồn một đoạn văn bản bạn thấy trên màn hình. Có ba kết quả thường gặp:

Bước 2: gọi endpoint JSON nếu có

Khi trang lấy dữ liệu từ một endpoint, gọi trực tiếp endpoint đó thường là lựa chọn tốt nhất. Nó nhỏ hơn, nhanh hơn và ổn định hơn trang đã render. Sao chép URL request, kiểm tra header nào trang yêu cầu, và thử từ một script. Chỉ làm điều này khi điều khoản của trang cho phép, và tôn trọng mọi giới hạn tốc độ hoặc xác thực mà trang mong đợi. Một endpoint không được tài liệu hóa có thể thay đổi mà không báo trước, nên hãy viết bộ phân tích của bạn để báo lỗi rõ ràng khi cấu trúc phản hồi thay đổi.

Bước 3: render trang khi bắt buộc

Nếu nội dung thực sự cần trình duyệt, hãy điều khiển một headless browser. Playwright là lựa chọn tốt cho Python. Ví dụ dưới đây mở một danh sách sản phẩm, chờ nội dung xuất hiện, và đọc văn bản từ mỗi thẻ:

from playwright.sync_api import sync_playwright

URL = "https://example.com/products"  # một trang bạn được phép 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)
    # Chờ phần tử chứng minh dữ liệu đã về.
    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)

Chờ một selector cụ thể đáng tin hơn nhiều so với sleep cố định. Một khoảng dừng cố định hoặc quá ngắn vào một ngày chậm, hoặc lãng phí thời gian vào một ngày nhanh. Hãy chọn phần tử chỉ xuất hiện khi dữ liệu đã tải xong.

Bước 4: xử lý cuộn vô hạn và phân trang

Một số trang tải thêm mục khi bạn cuộn. Cuộn xuống đáy, chờ số mục tăng, và dừng khi nó không tăng nữa. Các trang có phân trang đánh số đơn giản hơn: tìm liên kết trang tiếp theo, theo đó, và dừng ở trang cuối. Luôn đặt số trang hoặc số lần cuộn tối đa, để một lỗi không khiến crawler của bạn chạy mãi.

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)  # cho lô tiếp theo thời gian tải
    return previous

Bước 5: giữ trình duyệt tiết kiệm

Render rất tốn kém. Chặn ảnh, font và media mà bạn không cần, và dùng lại một trình duyệt cho nhiều trang thay vì khởi động một trình duyệt mới mỗi lần. Đóng trang và context khi xong, để bộ nhớ không tăng qua một lần chạy dài.

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

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

Bước 6: khi trang đã render hiển thị captcha

Đôi khi trang đã render trình bày một captcha trước khi hiển thị bất kỳ nội dung nào. Nếu captcha đó là PopularCaptcha, loại captcha đang hoạt động tại Scarnox, bạn đọc sitekey từ trang, yêu cầu một token, và đặt token vào trường form mà trang mong đợi. Hướng dẫn Python cho PopularCaptcha đi qua bước đó. Các widget khác chưa hoạt động, nên hãy kiểm tra các loại captcha được giải thích trước khi lên kế hoạch dựa vào một loại nào đó.

Hãy cẩn thận với chính trình duyệt. Một headless browser trông rõ ràng là tự động hóa có thể kích hoạt thêm kiểm tra, không phải ít hơn. Đọc phát hiện headless browser để biết các tín hiệu cần chú ý, và ưu tiên tải trang chậm hơn, ít lần hơn.

Scrape có trách nhiệm

Bước tiếp theo

Bắt đầu với tín dụng dùng thử miễn phí, không cần thẻ: tạo tài khoản và thử luồng PopularCaptcha trên một trang bạn sở hữu. Xem giá hiện tại tại trang giá.