🎯 Trình duyệt đám mây tùy chỉnh, chống phát hiện được hỗ trợ bởi Chromium tự phát triển, thiết kế dành cho trình thu thập dữ liệu webtác nhân AI. 👉Dùng thử ngay
Quay lại blog

Cách thu thập localStorage với Playwright và Scrapeless

Ava Wilson
Ava Wilson

Expert in Web Scraping Technologies

30-Jul-2026

Một trình duyệt có thể giữ trạng thái trang hữu ích bên ngoài DOM. Hướng dẫn này sử dụng Playwright để kiểm tra localStorage trên một demo công khai của MDN, thay đổi ba sở thích thực tế thông qua giao diện người dùng, ghi lại các sự kiện lưu trữ kết quả trong một tab thứ hai, và chứng minh rằng các giá trị tồn tại sau khi tải lại trước khi di chuyển cùng một logic đến Scrapeless Scraping Browser.

Những gì Web Storage Thêm vào Quy Trình Scraping

API Web Storage cung cấp cho một nguồn gốc hai kho lưu trữ có khóa kiểu chuỗi:

  • localStorage được chia sẻ bởi các tài liệu cùng nguồn gốc và tồn tại qua việc tải lại trang thông thường và khởi động lại trình duyệt khi hồ sơ được duy trì.
  • sessionStorage được hạn chế trong một ngữ cảnh duyệt web cấp cao nhất và kéo dài cho phiên trang đó.

Không kho nào là một bình chứa cookie. Giá trị Web Storage không tự động được đính kèm vào các yêu cầu HTTP, và mỗi cặp khóa/giá trị đều là kiểu chuỗi. Hướng dẫn API Web Storage của MDN định nghĩa các ranh giới phạm vi và tính bền vững.

Đối với việc scraping, lưu trữ có thể chứa sở thích giao diện người dùng, danh tính đã lưu, trạng thái chức năng, hoặc dữ liệu công khai mà ứng dụng đã tải trước đó. Hãy coi nó như là trạng thái trình duyệt để xác thực, không phải là lý do để thu thập mã thông báo xác thực hoặc dữ liệu người dùng riêng tư.

Tại Sao Sử Dụng Playwright Với Scrapeless

Playwright có thể đánh giá JavaScript trong nguồn gốc trang, mở hai trang trong cùng một BrowserContext, và quan sát sự kiện lưu trữ của chính trình duyệt. Scrapeless Scraping Browser cung cấp một phiên Chromium được lưu trữ trong khi vẫn giữ các API Playwright đó.

Kết nối trình duyệt sử dụng connect_over_cdp. Khi một page tồn tại, việc kiểm tra lưu trữ thì giống nhau bất kể Chromium là cục bộ hay được lưu trữ.

Điều Kiện Tiên Quyết

  • Python 3.10 hoặc phiên bản mới hơn.
  • playwright 1.59.0 hoặc phiên bản tương thích hiện tại.
  • Chrome/Chromium cục bộ cho ví dụ có thể chạy hoàn chỉnh.
  • Một tài khoản Scrapeless đã được nạp tiền và SCRAPELESS_API_KEY cho kết nối đám mây. Các phiên trình duyệt mới trên tài khoản xác thực trả về mã 14500, vì vậy khối kết nối trở thành một lỗ hổng điều kiện tiên quyết rõ ràng.

Cài Đặt

bash Copy
python -m pip install "playwright==1.59.0"

Kết Nối Đến Scrapeless Scraping Browser

Lưu ý: Khối này yêu cầu số dư Scraping Browser đã được nạp tiền. Tài khoản xác thực cuối cùng trả về số dư không đủ, vui lòng nạp tiền trước. Chạy nó với khóa nạp tiền của riêng bạn; quy trình lưu trữ hoàn chỉnh dưới đây đã chạy trong Chrome cục bộ trên cùng một trang công khai.

python Copy
import os
from urllib.parse import urlencode
from playwright.sync_api import sync_playwright

params = urlencode({
    "token": os.environ["SCRAPELESS_API_KEY"],
    "sessionTTL": 120,
    "proxyCountry": "US",
})
cdp_url = f"wss://browser.scrapeless.com/api/v2/browser?{params}"

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(cdp_url)
    context = browser.contexts[0]
    page = context.pages[0]
    # Chạy các bước lưu trữ bên dưới với context và page.
    browser.close()

Sử dụng tài liệu dành cho nhà phát triển Scrapeless để biết các thông số kết nối hiện tại.

Kiểm Tra Từng Khóa localStorage

Demo công khai của MDN lưu trữ một màu nền, phông chữ, và lựa chọn hình ảnh:

python Copy
TARGET_URL = "https://mdn.github.io/dom-examples/web-storage/"

page.goto(TARGET_URL, wait_until="domcontentloaded")
stored = page.evaluate(
    "Object.fromEntries(Object.entries(localStorage))"
)
print("lưu trữ ban đầu:", stored)
print("lưu trữ phiên:", page.evaluate("sessionStorage.length"))
text Copy
lưu trữ ban đầu: {'font': 'sans-serif', 'image': 'images/firefoxos.png', 'bgcolor': 'FF0000'}
lưu trữ phiên: 0

Đọc tất cả các mục sẽ tránh làm cho trình trích xuất bị ràng buộc vào một khóa. Giữ nguyên nguồn gốc trong đầu ra vì cùng một tên khóa có thể mang ý nghĩa khác nhau trên một trang khác.

Ghi Nhận Thay Đổi Trong Một Tab Thứ Hai

Sự kiện storage được kích hoạt trong các tài liệu cùng nguồn gốc khác chia sẻ kho lưu trữ đã thay đổi. Nó không được kích hoạt trong tab đã thực hiện thay đổi.

python Copy
observer_page = context.new_page()
observer_page.goto(TARGET_URL, wait_until="domcontentloaded")
observer_page.evaluate("""
    window.capturedStorageEvents = [];
    addEventListener('storage', event => {
        capturedStorageEvents.push({
            key: event.key,
            oldValue: event.oldValue,
            newValue: event.newValue,
        });
    });
""")

Cả hai trang phải chia sẻ một ngữ cảnh và nguồn gốc trình duyệt. Một ngữ cảnh thứ hai có lưu trữ riêng và sẽ không nhận được những sự kiện này.

Thay Đổi Các Điều Khiển Giao Diện Thực Tế

Thay đổi điều khiển của bản demo thay vì viết trực tiếp các phím:

python Copy
page.evaluate("""
    bgcolor.value = '00FF00';
    bgcolor.dispatchEvent(new Event('change', {bubbles: true}));
""")
page.select_option("#font", "serif")
page.select_option("#image", "images/crocodile.png")
page.wait_for_timeout(500)

print("lưu trữ đã cập nhật:", page.evaluate(
    "Object.fromEntries(Object.entries(localStorage))"
))
print("sự kiện:", observer_page.evaluate("capturedStorageEvents"))
text Copy
lưu trữ đã cập nhật: {'font': 'serif', 'image': 'images/crocodile.png', 'bgcolor': '00FF00'}
sự kiện: [{'key': 'bgcolor', 'oldValue': 'FF0000', 'newValue': '00FF00'}, {'key': 'font', 'oldValue': 'sans-serif', 'newValue': 'serif'}, {'key': 'image', 'oldValue': 'images/firefoxos.png', 'newValue': 'images/crocodile.png'}]

Kết quả đó chứng minh ba điều cùng một lúc: giao diện người dùng đã ghi vào lưu trữ, tab thứ hai nhận đúng ba thay đổi, và mỗi sự kiện giữ nguyên giá trị trước đó.

Sẵn sàng kiểm tra trạng thái trong một phiên được lưu trữ? Tạo một tài khoản Scrapeless miễn phí và chỉ cần thay thế phần tạo trình duyệt.

Chứng minh rằng các giá trị tồn tại sau khi tải lại

python Copy
page.reload(wait_until="domcontentloaded")
reloaded = page.evaluate(
    "Object.fromEntries(Object.entries(localStorage))"
)
controls = {
    "bgcolor": page.locator("#bgcolor").input_value(),
    "font": page.locator("#font").input_value(),
    "image": page.locator("#image").input_value(),
}

print("lưu trữ đã tải lại:", reloaded)
print("giá trị điều khiển:", controls)
text Copy
lưu trữ đã tải lại: {'font': 'serif', 'image': 'images/crocodile.png', 'bgcolor': '00FF00'}
giá trị điều khiển: {'bgcolor': '00FF00', 'font': 'serif', 'image': 'images/crocodile.png'}

Khớp giữa các điều khiển hiển thị với trạng thái lưu trữ mạnh mẽ hơn là chỉ kiểm tra lưu trữ. Nó chứng minh rằng ứng dụng đã tiêu thụ các giá trị đã lưu sau khi điều hướng.

Kịch bản có thể chạy hoàn chỉnh

python Copy
from playwright.sync_api import sync_playwright

TARGET_URL = "https://mdn.github.io/dom-examples/web-storage/"

with sync_playwright() as p:
    browser = p.chromium.launch(
        executable_path="/usr/bin/google-chrome",
        headless=True,
    )
    context = browser.new_context()
    page = context.new_page()
    observer_page = context.new_page()

    observer_page.goto(TARGET_URL, wait_until="domcontentloaded")
    observer_page.evaluate("""
        window.capturedStorageEvents = [];
        addEventListener('storage', event => {
            capturedStorageEvents.push({
                key: event.key,
                oldValue: event.oldValue,
                newValue: event.newValue,
            });
        });
    """)
    page.goto(TARGET_URL, wait_until="domcontentloaded")

    initial = page.evaluate(
        "Object.fromEntries(Object.entries(localStorage))"
    )
    page.evaluate("""
        bgcolor.value = '00FF00';
        bgcolor.dispatchEvent(new Event('change', {bubbles: true}));
    """)
    page.select_option("#font", "serif")
    page.select_option("#image", "images/crocodile.png")
    page.wait_for_timeout(500)

    updated = page.evaluate(
        "Object.fromEntries(Object.entries(localStorage))"
    )
    events = observer_page.evaluate("capturedStorageEvents")
    page.reload(wait_until="domcontentloaded")
    reloaded = page.evaluate(
        "Object.fromEntries(Object.entries(localStorage))"
    )
    controls = {
        "bgcolor": page.locator("#bgcolor").input_value(),
        "font": page.locator("#font").input_value(),
        "image": page.locator("#image").input_value(),
    }

    assert len(events) == 3
    assert updated == reloaded == controls
    assert page.evaluate("sessionStorage.length") == 0

    print("tiêu đề:", page.title())
    print("lưu trữ ban đầu:", initial)
    print("lưu trữ đã cập nhật:", updated)
    print("khóa sự kiện:", [event["key"] for event in events])
    print("số lượng sự kiện:", len(events))
    print("lưu trữ đã tải lại:", reloaded)
    print("giá trị điều khiển:", controls)
    print("mục nhập session storage:", page.evaluate("sessionStorage.length"))
    browser.close()

Chương trình chạy trả về ba khóa ban đầu, ba khóa đã cập nhật, ba sự kiện giữa các tab, các điều khiển đã tải lại khớp nhau và số mục trong sessionStorage là không.

localStorage, sessionStorage và Cookies

localStorage

Chia sẻ bởi các tài liệu cùng nguồn gốc, chỉ chuỗi và tồn tại vĩnh viễn cho đến khi được xóa. Sử dụng nó khi ứng dụng cố ý giữ lại trạng thái qua các lần truy cập.

sessionStorage

Tách biệt cho mỗi phiên trang cấp cao. Nhân bản hoặc mở một tab có thể tạo ra một vòng đời riêng biệt ngay cả trên cùng một nguồn gốc. Kiểm tra nó từ trang chính xác mà trạng thái quan trọng.

Cookies

Gửi cùng với các yêu cầu HTTP phù hợp theo quy tắc cookie. Sử dụng API cookie trong ngữ cảnh của Playwright thay vì nhầm lẫn chúng với Web Storage.

Ranh giới trích xuất an toàn

Lưu trữ có thể chứa thông tin xác thực, định danh người dùng hoặc trạng thái riêng tư. Hãy hạn chế các ví dụ chỉ trên các trang demo công khai, chỉ thu thập các trường cần thiết cho nhiệm vụ đã nêu, và không bao giờ công bố token hoặc tài liệu phiên. Việc truy cập từ nguồn gốc qua trình duyệt không cho phép bạn tái sử dụng mọi giá trị mà bạn có thể đọc.

Kết luận

Việc trích xuất Lưu trữ Web là hữu ích khi trình duyệt có trạng thái mà DOM hiển thị không thể giải thích được. Đọc bản đồ hoàn chỉnh, giữ nguyên gốc với bản ghi, quan sát các thay đổi giữa các tab khi bạn cần nguồn gốc, và xác minh rằng ứng dụng tiêu thụ các giá trị đã lưu sau khi điều hướng. Di chuyển quy trình làm việc sang Scrapeless sẽ thay đổi kết nối trình duyệt, chứ không phải logic lưu trữ.

Bắt đầu với Scrapeless, xem giá Scrapeless, và đọc những gì CDP phơi bày trước khi di chuyển các phiên trạng thái lên đám mây.

Câu hỏi thường gặp

H: Có thể Playwright đọc localStorage không?

Có. Đánh giá Object.fromEntries(Object.entries(localStorage)) bên trong một trang trên nguồn gốc mục tiêu.

H: Tại sao không sử dụng context.storage_state() cho mọi thứ?

Trạng thái lưu trữ hữu ích để xuất khẩu trạng thái xác thực được hỗ trợ, nhưng đánh giá trang trực tiếp cho phép bạn kiểm tra bản đồ khóa trực tiếp và liên hệ nó với các thay đổi UI và sự kiện lưu trữ.

H: localStorage có sống sót qua việc tải lại không?

Có, trừ khi ứng dụng hoặc trình duyệt xóa nó. Ba giá trị đã thay đổi trong demo của MDN đã sống sót qua lần tải lại được thử nghiệm và đã nạp lại các điều khiển.

H: Tab thay đổi localStorage có nhận được sự kiện lưu trữ không?

Không. Sự kiện được gửi tới các tài liệu cùng nguồn gốc khác chia sẻ cùng lưu trữ, đó là lý do tại sao ví dụ lắng nghe trong một trang thứ hai.

H: sessionStorage có được chia sẻ giữa các tab không?

Không. Nó chỉ giới hạn trong một ngữ cảnh duyệt web cấp cao và các ngữ cảnh con cùng nguồn gốc của nó, vì vậy hãy kiểm tra nó từ phiên trang cụ thể.

H: Các giá trị Web Storage có luôn là JSON không?

Không. Mỗi giá trị được lưu trữ dưới dạng chuỗi. Chỉ phân tích JSON khi định dạng của ứng dụng đã được xác nhận, và xử lý JSON không hợp lệ một cách rõ ràng.

H: Có an toàn để trích xuất lưu trữ của trình duyệt không?

Chỉ trong phạm vi quyền của mục tiêu và các nghĩa vụ xử lý dữ liệu của bạn. Tránh thông tin xác thực và trạng thái người dùng riêng tư, giữ việc thu thập có giới hạn, và xem xét điều khoản của trang web và chính sách robots khi có thể.

Tại Scrapless, chúng tôi chỉ truy cập dữ liệu có sẵn công khai trong khi tuân thủ nghiêm ngặt các luật, quy định và chính sách bảo mật trang web hiện hành. Nội dung trong blog này chỉ nhằm mục đích trình diễn và không liên quan đến bất kỳ hoạt động bất hợp pháp hoặc vi phạm nào. Chúng tôi không đảm bảo và từ chối mọi trách nhiệm đối với việc sử dụng thông tin từ blog này hoặc các liên kết của bên thứ ba. Trước khi tham gia vào bất kỳ hoạt động cạo nào, hãy tham khảo ý kiến ​​cố vấn pháp lý của bạn và xem xét các điều khoản dịch vụ của trang web mục tiêu hoặc có được các quyền cần thiết.

Bài viết phổ biến nhất

Danh mục