🎯 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

Nhà soạn kịch + Trình duyệt Ghi lại mà không bị lỗi: Ghi lại và Phát lại một phiên HAR đầy đủ

James Thompson
James Thompson

Scraping and Proxy Management Expert

30-Jul-2026

Tóm tắt:

  • Tệp HAR là một lưu trữ HTTP có cấu trúc, không phải là ảnh chụp màn hình hay video. Mảng log.entries của nó lưu trữ một đối tượng cho mỗi yêu cầu HTTP được ghi lại, bao gồm siêu dữ liệu yêu cầu và phản hồi và, khi có, nội dung được ghi lại.
  • Playwright ghi lại tệp HAR tại cấp độ bối cảnh trình duyệt. Đặt record_har_path khi tạo bối cảnh và gọi context.close() để ghi lại tháng tin vào đĩa.
  • Scrapeless Scraping Browser cung cấp phiên trình duyệt từ xa. Playwright kết nối với nó qua CDP, tải trang, kích hoạt yêu cầu động và lưu lại lưu lượng truy cập vào máy tính.
  • Phân tích HAR không yêu cầu trình duyệt. Sau khi tệp tồn tại, mô-đun json tiêu chuẩn của Python có thể kiểm tra các URL, phương thức, trạng thái, loại MIME, tiêu đề và nội dung phản hồi nhúng.
  • Một yêu cầu đã được ghi lại có thể được phát lại mà không cần Playwright. Ví dụ tái xây dựng một yêu cầu JSON công khai với urllib sau khi loại bỏ các tiêu đề giả HTTP/2 và điều chỉnh lại mã hóa nội dung.
  • Phát lại HAR có giới hạn. Cookie hết hạn, mã thông báo CSRF, thông tin xác thực bearer, khung WebSocket và dữ liệu máy chủ thay đổi có thể ngăn cản một yêu cầu sau đó tạo ra phản hồi gốc.
  • Miễn phí bắt đầu. Các tài khoản Scrapeless mới bao gồm thời gian thực hiện Scraping Browser miễn phí — đăng ký tại app.scrapeless.com.

Giới thiệu: Ghi lại trước, quyết định điều gì quan trọng sau

Tệp HAR là một lưu trữ JSON của các giao dịch HTTP được quan sát trong một phiên trình duyệt. Nó không phải là ảnh chụp màn hình của trang được kết xuất, ảnh chụp DOM, hay video phiên.

Mỗi yêu cầu được ghi lại xuất hiện dưới dạng một đối tượng bên trong:

text Copy
log.entries

Một mục có thể chứa phương thức yêu cầu, URL, tiêu đề, tham số truy vấn, dữ liệu gửi đi, trạng thái phản hồi, tiêu đề phản hồi, thông tin thời gian và nội dung phản hồi đã ghi lại. Nội dung nhị phân có thể được biểu diễn bằng một mã hóa như Base64, trong khi các thân văn bản có thể xuất hiện trực tiếp trong mục.

Hướng dẫn này kết nối Playwright với Scrapeless Scraping Browser qua Giao thức DevTools của Chrome, ghi lại một tải trang hoàn chỉnh và chuỗi cuộn với record_har_path, và đóng trình duyệt.

Nửa sau của quy trình làm việc không cần trình duyệt:

  1. Kiểm tra cấu trúc HAR với json.
  2. Tìm yêu cầu API được ghi lại.
  3. Tái xây dựng các tiêu đề có thể tái sử dụng của nó.
  4. Phát lại nó với urllib.
  5. So sánh phản hồi JSON mới với nội dung được lưu trữ trong lưu trữ.

Mọi kết quả được hiển thị đều đến từ phiên mục tiêu đã được ghi lại.

Những gì bạn có thể làm với tệp HAR

Ghi lại HAR hữu ích khi điểm cuối quan trọng chưa được biết đến trước khi trang được tải.

  • Kiểm toán một tải trang hoàn chỉnh. Xem lại HTML, bảng kiểu, kịch bản, phông chữ, hình ảnh và yêu cầu API từ một phiên.
  • Khám phá các điểm cuối JSON nội bộ. Tìm kiếm trong lưu trữ sau khi ghi lại thay vì dự đoán yêu cầu nào sẽ quan trọng.
  • Gỡ lỗi hành vi trang thất bại. Kiểm tra URL yêu cầu, trạng thái phản hồi, tiêu đề, loại MIME và nội dung sau khi trình duyệt đã đóng.
  • Bảo tồn bằng chứng mạng. Lưu trữ một tác phẩm JSON di động có thể được phân tích sau hoặc chuyển đến một máy khác.
  • So sánh hành vi tải trang. Ghi lại các phiên riêng biệt và so sánh các tập hợp yêu cầu, trạng thái hoặc nội dung phản hồi của chúng.
  • Trích xuất dữ liệu phản hồi đã ghi lại. Đọc các thân JSON hoặc văn bản nhúng mà không cần tải lại trang.
  • Tái tạo các yêu cầu đủ điều kiện. Phát lại các yêu cầu HTTP công khai hoặc vẫn đang xác thực với một khách hàng HTTP tiêu chuẩn.
  • Xây dựng các bài kiểm tra trình duyệt xác định. Sử dụng tính năng riêng biệt route_from_har() của Playwright để phục vụ các phản hồi đã ghi lại trở lại bối cảnh trình duyệt trực tiếp.

Tệp HAR có giá trị nhất khi việc ghi lại rộng rãi hữu ích hơn việc gán một trình nghe cho một điểm cuối đã biết trước.

Ghi lại HAR, ghi video và định tuyến HAR là khác nhau

Ba tính năng trong lĩnh vực này sử dụng ngôn ngữ tương tự nhưng giải quyết các vấn đề khác nhau.

Tính năng Những gì nó ghi lại hoặc thực hiện Có cần trình duyệt sau đó không?
Playwright record_har_path Lưu trữ dữ liệu yêu cầu và phản hồi HTTP Không, để kiểm tra ngoại tuyến
Ghi lại phiên Scrapeless Tạo một phát lại trực quan của phiên đã kết xuất Không, để phát lại trên bảng điều khiển
Playwright route_from_har() Phục vụ phản hồi đã ghi lại cho các yêu cầu được thực hiện bởi bối cảnh trình duyệt
Ví dụ urllib trong hướng dẫn này Tái phát một yêu cầu đã ghi lại chống lại máy chủ trực tiếp Không

Chặn Sống

Chặn sống quan sát các yêu cầu khi chúng xảy ra. Nó hoạt động tốt khi điểm cuối mục tiêu hoặc mẫu phản hồi đã được biết.

Một khi phiên kết thúc, bất cứ thứ gì không được ghi lại bởi trình nghe sẽ bị mất.

Ghi lại HAR

Ghi lại HAR ghi lại lưu lượng HTTP của bối cảnh một cách rộng rãi. Điểm cuối quan trọng có thể được chọn sau khi trình duyệt đóng.

Điều này làm cho ghi lại HAR trở thành phương thức tốt hơn cho:

  • Gỡ lỗi sau phiên
  • Kiểm kê mạng
  • Khám phá API
  • Kiểm toán tất cả các tài nguyên được tải bởi một trang
  • Bảo tồn thân phản hồi để kiểm tra ngoại tuyến

Ghi lại phiên không bị rác

Trình duyệt Ghi lại không bị rác hỗ trợ khả năng ghi lại phiên bản gốc riêng biệt. Điều này tạo ra một bản ghi hình ảnh có thể phát lại của phiên trình duyệt đã được hiển thị.

Nó không thay thế một tệp HAR. Video cho thấy những gì xuất hiện trên màn hình; một HAR tiết lộ các giao dịch HTTP có cấu trúc.

Playwright route_from_har()

route_from_har() của Playwright gửi phản hồi HAR đã lưu trở lại trong các yêu cầu được thực hiện bởi một ngữ cảnh trình duyệt trực tiếp. Nó thường được sử dụng để giả lập hành vi backend trong các bài kiểm tra trình duyệt.

Ví dụ phát lại trong hướng dẫn này làm điều gì đó khác: nó đọc một yêu cầu từ kho lưu trữ và gửi một yêu cầu HTTP trực tiếp mới với urllib.

Tại sao ghi lại HAR thông qua Trình duyệt Ghi lại không bị rác?

Trình duyệt Ghi lại không bị rác cung cấp môi trường trình duyệt từ xa mà Playwright điều khiển qua CDP.

Phiên trình duyệt chạy trên cơ sở hạ tầng đám mây và hỗ trợ lựa chọn proxy địa lý thông qua các tham số kết nối. Playwright vẫn sử dụng trình duyệt, ngữ cảnh, trang, và API HAR bình thường của nó.

Đối với quy trình làm việc này, sự phân chia trách nhiệm là đơn giản:

Thành phần Trách nhiệm
Trình duyệt Ghi lại không bị rác Chạy phiên Chromium từ xa và cung cấp điểm cuối CDP
Playwright Tạo ngữ cảnh, điều khiển trang, và ghi lại HAR
Hệ thống tệp địa phương Lưu trữ session.har
Thư viện tiêu chuẩn Python Kiểm tra kho lưu trữ và phát hành lại yêu cầu đã chọn

Ghi lại HAR bản thân là một tính năng của Playwright. Kết nối Playwright với Ghi lại không bị rác chuyển giai đoạn hiển thị trực tiếp vào một trình duyệt từ xa được quản lý trong khi để lại kho lưu trữ kết quả trên máy chạy kịch bản Python.

Kết nối sử dụng cùng một miền Giao thức DevTools của Chrome mà công cụ trình duyệt sử dụng để quan sát hoạt động mạng.

Hướng dẫn Bắt đầu nhanh với Trình duyệt Ghi lại đề cập đến mô hình kết nối Playwright và Puppeteer rộng hơn.

Điều kiện tiên quyết

Bạn cần:

  • Python 3.9 hoặc mới hơn
  • Playwright 1.59.0 cho lần chạy được tái hiện
  • Một tài khoản Scrapeless và khóa API
  • Quyền ghi vào thư mục nơi session.har sẽ được tạo
  • Truy cập mạng đến trang mục tiêu công khai

Playwright 1.59.0 yêu cầu Python 3.9 hoặc mới hơn. Đặt phiên bản đó đảm bảo cài đặt khớp với kết quả đã ghi lại trong hướng dẫn này.

Không cần cài đặt Chrome cục bộ cho quy trình làm việc này. connect_over_cdp() gắn kết với một trình duyệt đã chạy trên cơ sở hạ tầng Scrapeless.

Các kịch bản kiểm tra và phát hành lại yêu cầu chỉ sử dụng thư viện tiêu chuẩn của Python. Chúng không nhập Playwright hoặc mở kết nối trình duyệt.

Bước 1 — Cài đặt Playwright

Cài đặt phiên bản được sử dụng cho lần chạy đã ghi lại:

bash Copy
pip install "playwright==1.59.0"

Vì kịch bản kết nối với một trình duyệt từ xa hiện có qua CDP, nó không khởi động một tệp thực thi trình duyệt đã được cài đặt cục bộ.

Đặt khóa API Scrapeless trong shell:

bash Copy
export SCRAPELESS_API_KEY="your_scrapeless_api_key"

Mã sẽ đọc khóa từ môi trường thay vì lưu trữ nó trong hệ thống quản lý mã nguồn.

Bước 2 — Xây dựng URL CDP Scrapeless

URL kết nối Trình duyệt Ghi lại mang theo khóa API, tuổi thọ phiên, và vị trí proxy dưới dạng tham số truy vấn:

python Copy
import os
from urllib.parse import urlencode

API_KEY = os.environ["SCRAPELESS_API_KEY"]


def scraping_browser_url(proxy_country="US", session_ttl=180):
    params = urlencode({
        "token": API_KEY,
        "sessionTTL": session_ttl,
        "proxyCountry": proxy_country,
    })
    return f"wss://browser.scrapeless.com/api/v2/browser?{params}"

Hàm này tạo ra một URL theo hình dạng này:

text Copy
wss://browser.scrapeless.com/api/v2/browser?token=...&sessionTTL=180&proxyCountry=US

Ba giá trị đã cấu hình là:

  • token: khóa API Scrapeless
  • sessionTTL: tuổi thọ phiên tối đa
  • proxyCountry: quốc gia proxy đã yêu cầu

Giữ lại việc xây dựng URL trong một hàm cũng dễ dàng hơn để áp dụng cùng một cài đặt kết nối qua nhiều kịch bản ghi lại khác nhau.

Bước 3 — Ghi lại Phiên Trình Duyệt

Cài đặt record_har_path của Playwright thuộc về browser.new_context(), không phải connect_over_cdp().

Kết nối trình duyệt cung cấp quyền truy cập vào Chromium. Ngữ cảnh xác định những gì sẽ được ghi lại.

python Copy
import os
from urllib.parse import urlencode

from playwright.sync_api import sync_playwright


API_KEY = os.environ["SCRAPELESS_API_KEY"]
HAR_PATH = "session.har"


def scraping_browser_url(proxy_country="US", session_ttl=180):
    params = urlencode({
        "token": API_KEY,
        "sessionTTL": session_ttl,
        "proxyCountry": proxy_country,
    })
    return f"wss://browser.scrapeless.com/api/v2/browser?{params}"
python Copy
với sync_playwright() như p:
    trình duyệt = p.chromium.connect_over_cdp(scraping_browser_url())

    ngữ cảnh = trình duyệt.new_context(
        record_har_path=HAR_PATH,
        record_har_content="embed",
    )

    trang = ngữ cảnh.new_page()
    trang.goto(
        "https://quotes.toscrape.com/scroll",
        wait_until="networkidle",
    )

    cho _ trong khoảng(3):
        trang.evaluate(
            "window.scrollTo(0, document.body.scrollHeight)"
        )
        trang.wait_for_timeout(800)

    print(
        "các phần tử câu trích dẫn hiển thị sau khi cuộn:",
        trang.locator(".quote").count(),
    )

    ngữ cảnh.close()
    trình duyệt.close()

print(
    "HAR đã được ghi:",
    HAR_PATH,
    "-",
    os.path.getsize(HAR_PATH),
    "bytes",
)

Kết quả của chạy trực tiếp đã in ra:

```text
các phần tử câu trích dẫn hiển thị sau khi cuộn: 40
HAR đã được ghi: session.har - 333269 bytes

Bản thân trang web ban đầu hiển thị mười câu trích dẫn. Mỗi lần cuộn gần cuối trang kích hoạt một yêu cầu /api/quotes?page=N khác, mang tổng số câu trích dẫn hiển thị lên 40 trên bốn trang API.

Kịch bản không cần đoán trước yêu cầu nào sẽ quan trọng sau này. HAR cũng đã ghi lại tài liệu, stylesheet, JavaScript, font, và các cuộc gọi JSON.

Nhận khóa API của bạn trên gói miễn phí: app.scrapeless.com

Tại sao context.close() là cần thiết

HAR sẽ được hoàn thiện khi ngữ cảnh trình duyệt đóng lại.

Playwright ghi nhận record_har_path là cài đặt ngữ cảnh trình duyệt và yêu cầu browser_context.close() để HAR được lưu lại. Việc chỉ đóng kết nối trình duyệt có thể để lại các hiện tượng ngữ cảnh mà không được làm sạch một cách hợp lý.

Thứ tự tắt đúng là:

python Copy
ngữ cảnh.close()
trình duyệt.close()

Do đó, cuộc gọi context.close() là một phần của quy trình ghi lại, không phải là dọn dẹp tùy chọn.

record_har_content="embed" lưu trữ nội dung phản hồi đã ghi lại bên trong HAR thay vì trong các tệp đồng hành riêng biệt. Điều này làm cho session.har trở thành một tệp tự chứa cho việc kiểm tra JSON và so sánh nội dung sau này.

Bản nháp định dạng HAR lịch sử xác định đối tượng log cấp cao nhất và mảng entries là yêu cầu. Mỗi mục nhập đại diện cho một yêu cầu HTTP đã xuất khẩu.

Bước 4 — Kiểm tra HAR mà không cần trình duyệt

Sau khi ngữ cảnh đóng lại, session.har là một tài liệu JSON cục bộ.

Kịch bản sau đây chỉ sử dụng json, collections, và pathlib:

python Copy
import json
from collections import Counter
from pathlib import Path


har = json.loads(Path("session.har").read_text())
entries = har["log"]["entries"]

print("tổng số mục nhập:", len(entries))

by_type = Counter(
    entry["response"]["content"]["mimeType"].split(";")[0]
    cho entry trong entries
)

cho mime_type, count in by_type.most_common():
    print(f"  {mime_type}: {count}")

print()

cho entry trong entries:
    request = entry["request"]
    response = entry["response"]

    print(
        f"{request['method']:4s} "
        f"{response['status']:3d}  "
        f"{request['url']}"
    )

Tệp đã ghi lại chứa:

text Copy
tổng số mục nhập: 10
  application/json: 4
  text/css: 3
  text/html: 1
  application/javascript: 1
  font/woff2: 1

GET  200  https://quotes.toscrape.com/scroll
GET  200  https://quotes.toscrape.com/static/bootstrap.min.css
GET  200  https://quotes.toscrape.com/static/main.css
GET  200  https://quotes.toscrape.com/static/jquery.js
GET  200  https://fonts.googleapis.com/css?family=Raleway:400,700
GET  200  https://fonts.gstatic.com/s/raleway/v37/1Ptug8zYS_SKggPNyC0ITw.woff2
GET  200  https://quotes.toscrape.com/api/quotes?page=1
GET  200  https://quotes.toscrape.com/api/quotes?page=2
GET  200  https://quotes.toscrape.com/api/quotes?page=3
GET  200  https://quotes.toscrape.com/api/quotes?page=4

Mười mục nhập phủ một số năm loại MIME:

  • Một tài liệu HTML
  • Ba phản hồi CSS
  • Một phản hồi JavaScript
  • Một font web
  • Bốn phản hồi JSON

Một trình lắng nghe trực tiếp lọc đến /api/quotes sẽ quan sát bốn yêu cầu JSON nhưng bỏ qua sáu tài nguyên khác. HAR đã bảo tồn cả mười để kiểm tra sau này.

Hiểu cấu trúc mục nhập HAR

Mỗi mục trong har["log"]["entries"] chứa các đối tượng yêu cầu và phản hồi lồng nhau.

Một mục nhập đơn giản có hình thức này:

json Copy
{
  "request": {
    "method": "GET",
    "url": "https://example.com/api/data",
    "headers": []
  },
  "response": {
    "status": 200,
    "headers": [],
    "content": {
      "mimeType": "application/json",
      "text": "{}"
    }
  }
}

Các trường yêu cầu hữu ích bao gồm:

  • method
  • url
  • headers
  • queryString
  • postData

Các trường phản hồi hữu ích bao gồm:

  • status
  • statusText
  • headers
  • content
  • redirectURL
Copy
Nội dung HAR không được đảm bảo sẽ được lưu trữ dưới dạng văn bản có thể đọc được trực tiếp trong mỗi mục. Tùy thuộc vào tài nguyên và bộ ghi, `content.text` có thể không có, văn bản đã giải mã hoặc một bản thể hiện mã hóa mà trường `encoding` của nó xác định định dạng.

## Bước 5 — Xử lý Các Pseudo-Headers của HTTP/2

Các tiêu đề yêu cầu cho cuộc gọi API đã được ghi lại `page=1` bao gồm các tên như sau:

```text
:authority
:method
:path
:scheme

Đây là các trường pseudo-header của HTTP/2.

Chúng mang thông tin điều khiển sẽ xuất hiện trong một dòng yêu cầu HTTP/1.1 hoặc mục tiêu:

  • :method xác định phương thức yêu cầu.
  • :scheme xác định định dạng URI.
  • :authority xác định quyền lực mục tiêu.
  • :path xác định đường dẫn và truy vấn.

Pseudo-headers không phải là các trường tiêu đề HTTP thông thường. Một khách hàng định hướng HTTP/1.1 như urllib không thể chấp nhận một tên tiêu đề có tiền tố hai dấu chấm.

Một kịch bản phát lại phải chuyển đổi ý nghĩa của chúng thành URL và phương thức, sau đó loại bỏ chúng khỏi ánh xạ tiêu đề thông thường.

Bước 6 — Phát lại Một Yêu cầu Đã Ghi Lại với urllib

Yêu cầu đã chọn /api/quotes?page=1 bây giờ là một từ điển bên trong tệp JSON cục bộ.

Kịch bản bên dưới:

  1. Tìm mục đã ghi lại.
  2. Đọc phương thức, URL và tiêu đề của nó.
  3. Loại bỏ các pseudo-header HTTP/2.
  4. Loại bỏ accept-encoding.
  5. Tạo một urllib.request.Request mới.
  6. Phân tích các thân phản hồi tức thì và đã ghi lại.
  7. So sánh hai đối tượng Python.
python Copy
import json
import urllib.error
import urllib.request
from pathlib import Path

har = json.loads(Path("session.har").read_text())
entries = har["log"]["entries"]

target = next(
    entry
    for entry in entries
    if entry["request"]["url"].endswith("page=1")
)

captured_request = target["request"]

# Các pseudo-headers HTTP/2 mô tả định dạng giao thức và không thể
# được truyền như các tiêu đề kiểu HTTP/1.1 thông thường.
#
# accept-encoding cũng được loại bỏ để urllib có thể thương lượng một
# mã hóa mà kịch bản có thể giải mã trực tiếp.
skip_headers = {"accept-encoding"}

headers = {
    header["name"]: header["value"]
    for header in captured_request["headers"]
    if not header["name"].startswith(":")
    and header["name"].lower() not in skip_headers
}

print("số lượng tiêu đề đã phát lại:", len(headers))

request = urllib.request.Request(
    captured_request["url"],
    headers=headers,
    method=captured_request["method"],
)

with urllib.request.urlopen(request, timeout=10) as response:
    if response.status != 200:
        raise urllib.error.HTTPError(
            captured_request["url"],
            response.status,
            "trạng thái không mong đợi",
            response.headers,
            None,
        )

    live_data = json.loads(response.read())

captured_content = target["response"]["content"]
captured_data = json.loads(captured_content["text"])

print("trạng thái:", response.status, "-- không có quá trình trình duyệt đang chạy")
print(
    "tác giả của câu trích dẫn đầu tiên:",
    live_data["quotes"][0]["author"]["name"],
)
print(
    "khớp với thân phản hồi đã được HAR ghi lại:",
    live_data == captured_data,
)

Phát lại mà không cần trình duyệt in ra:

text Copy
số lượng tiêu đề đã phát lại: 12
trạng thái: 200 -- không có quá trình trình duyệt đang chạy
tác giả của câu trích dẫn đầu tiên: Albert Einstein
khớp với thân phản hồi đã được HAR ghi lại: True

Ánh xạ đã lọc chứa 12 tiêu đề thông thường. Các pseudo-headers HTTP/2 và accept-encoding đã bị loại trừ.

accept-encodingmột trường thương lượng nội dung HTTP. Khách hàng phát lại có thể quảng cáo các mã hóa nội dung mà nó hỗ trợ thay vì sao chép sự thương lượng Brotli của trình duyệt một cách mù quáng.

Phản hồi mục tiêu khớp với thân JSON được lưu trữ trong HAR cho phiên này. So sánh đó được thực hiện trên các đối tượng Python đã phân tích thay vì trên định dạng trắng hoặc định dạng khóa của chúng.

Đây là một sự tái cấu trúc yêu cầu ngữ nghĩa, không phải là một sự tái tạo byte cho byte của giao dịch mạng ban đầu. Yêu cầu mới có thể sử dụng một phiên bản HTTP khác, thứ tự tiêu đề, thương lượng nén, kết nối và phiên TLS.

Những Gì Bạn Nhận Được

Quy trình làm việc tạo ra ba kết quả hoặc sản phẩm có thể tái sử dụng:

Giai đoạn Đầu ra Có cần trình duyệt không?
Ghi lại session.har
Kiểm tra Danh sách yêu cầu và tóm tắt loại MIME Không
Phát lại So sánh phản hồi trực tiếp đã phân tích và thân đã ghi lại Không

Phiên ghi lại đã sản xuất:

text Copy
Kích thước HAR: 333269 bytes
Các mục HTTP: 10
Các mục JSON: 4
Số lượng trích dẫn hiển thị sau khi cuộn: 40
Trạng thái yêu cầu đã phát lại: 200
Khớp JSON đã ghi lại/sống: True

Những con số này mô tả phiên mục tiêu cụ thể này. Một trang khác, phiên bản trình duyệt khác, thời gian cuộn, vị trí proxy hoặc phản hồi trang có thể tạo ra một tập yêu cầu và kích thước tệp khác nhau.

Xác Nhận Toàn Bộ Chuỗi trong Một Kịch bản

Việc tách biệt các chương trình thu thập, kiểm tra và phát lại dễ hiểu hơn, nhưng các giai đoạn giống nhau có thể được kết hợp:

python Copy
import json
import os
import urllib.error
import urllib.request
from collections import Counter
from pathlib import Path
from urllib.parse import urlencode

from playwright.sync_api import sync_playwright


API_KEY = os.environ["SCRAPELESS_API_KEY"]
HAR_PATH = "session.har"


def scraping_browser_url(proxy_country="US", session_ttl=180):
    params = urlencode({
        "token": API_KEY,
        "sessionTTL": session_ttl,
        "proxyCountry": proxy_country,
    })
    return f"wss://browser.scrapeless.com/api/v2/browser?{params}"


# Giai đoạn 1: thu thập. Cần có một trình duyệt.
with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(
        scraping_browser_url()
    )

    context = browser.new_context(
        record_har_path=HAR_PATH,
        record_har_content="embed",
    )

    page = context.new_page()
    page.goto(
        "https://quotes.toscrape.com/scroll",
        wait_until="networkidle",
    )

    for _ in range(3):
        page.evaluate(
            "window.scrollTo(0, document.body.scrollHeight)"
        )
        page.wait_for_timeout(800)

    context.close()
    browser.close()

print("=== thu thập ===")
print(
    "HAR đã được ghi:",
    HAR_PATH,
    "-",
    os.path.getsize(HAR_PATH),
    "bytes",
)


# Giai đoạn 2: kiểm tra. Trình duyệt đã đóng.
har = json.loads(Path(HAR_PATH).read_text())
entries = har["log"]["entries"]

print("\n=== kiểm tra (không trình duyệt) ===")
print("tổng số mục:", len(entries))

by_type = Counter(
    entry["response"]["content"]["mimeType"].split(";")[0]
    for entry in entries
)

for mime_type, count in by_type.most_common():
    print(f"  {mime_type}: {count}")


# Giai đoạn 3: phát lại một yêu cầu. Trình duyệt vẫn đóng.
target = next(
    entry
    for entry in entries
    if entry["request"]["url"].endswith("page=1")
)

captured_request = target["request"]
skip_headers = {"accept-encoding"}

headers = {
    header["name"]: header["value"]
    for header in captured_request["headers"]
    if not header["name"].startswith(":")
    and header["name"].lower() not in skip_headers
}

request = urllib.request.Request(
    captured_request["url"],
    headers=headers,
    method=captured_request["method"],
)

with urllib.request.urlopen(request, timeout=10) as response:
    if response.status != 200:
        raise urllib.error.HTTPError(
            captured_request["url"],
            response.status,
            "trạng thái không mong đợi",
            response.headers,
            None,
        )

    live_data = json.loads(response.read())

captured_data = json.loads(
    target["response"]["content"]["text"]
)

print("\n=== phát lại (không trình duyệt) ===")
print("trạng thái:", response.status)
print(
    "tác giả của câu trích dẫn đầu tiên:",
    live_data["quotes"][0]["author"]["name"],
)
print(
    "khớp với nội dung đã thu thập:",
    live_data == captured_data,
)

Chạy kết hợp đã in ra:

text Copy
=== thu thập ===
HAR đã được ghi: session.har - 333259 bytes

=== kiểm tra (không trình duyệt) ===
tổng số mục: 10
  application/json: 4
  text/css: 3
  text/html: 1
  application/javascript: 1
  font/woff2: 1

=== phát lại (không trình duyệt) ===
trạng thái: 200
tác giả của câu trích dẫn đầu tiên: Albert Einstein
khớp với nội dung đã thu thập: True

Chỉ giai đoạn đầu tiên nhập và sử dụng Playwright. Các giai đoạn sau hoạt động trên tập tin và điểm cuối HTTP trực tiếp đã chọn.

Điều gì được một HAR ghi lại

Tệp HAR đại diện cho các giao dịch HTTP được ghi lại bởi ngữ cảnh trình duyệt.

Tùy thuộc vào bộ ghi và cấu hình, một mục có thể chứa:

  • Phương thức yêu cầu và URL
  • Tham số chuỗi truy vấn
  • Tiêu đề yêu cầu
  • Cookie yêu cầu
  • Dữ liệu đã gửi
  • Trạng thái phản hồi
  • Tiêu đề phản hồi
  • Cookie phản hồi
  • Loại MIME
  • Nội dung phản hồi
  • Kích thước truyền tải
  • Thông tin thời gian
  • Chi tiết chuyển tiếp
  • Thông tin bộ nhớ đệm

Với record_har_content="embed", Playwright lưu trữ nội dung phản hồi có sẵn bên trong HAR. Nếu không có nội dung nhúng, danh sách yêu cầu vẫn có thể hữu ích, nhưng lưu trữ có thể không chứa thân phản hồi cần thiết cho việc phân tích hoặc so sánh ngoại tuyến.

Điều gì một HAR không đảm bảo

Tệp HAR là một bản ghi lâu bền của hoạt động HTTP đã ghi lại, nhưng nó không phải là bản ghi đầy đủ của mọi hành vi của trình duyệt.

Các khung WebSocket không được lưu trữ

HAR mô hình hóa các giao dịch yêu cầu và phản hồi. Nó không bảo tồn chuỗi các tin nhắn được chuyển qua một kết nối WebSocket đã thiết lập.

Một trang kết hợp các điểm cuối HTTP bình thường với một nguồn cấp WebSocket trực tiếp cần có cơ chế thu thập riêng biệt:

  • HAR cho lưu lượng yêu cầu và phản hồi HTTP
  • Bộ lắng nghe khung WebSocket cho các tin nhắn socket

Kết nối ban đầu có thể liên quan đến một bản nâng cấp HTTP, nhưng dòng khung liên tục nằm ngoài mô hình yêu cầu-phản hồi HAR bình thường.

Một HAR không phải là ảnh chụp DOM

Tệp không bảo tồn cây tài liệu cuối cùng theo cách mà một ảnh chụp DOM sẽ làm.
Một thân phản hồi có thể chứa HTML hoặc JSON gốc, nhưng các biến thể JavaScript sau này, trạng thái phần tử, bố cục đã được hiển thị và diện mạo nhìn thấy được của người dùng là những vấn đề riêng biệt.

HAR Không Phải Là Một Video

Kho lưu trữ không chứa dòng thời gian hình ảnh của những gì xuất hiện trên trang.

Sử dụng ghi session Scrapeless khi mục tiêu là xem xét hành vi trình duyệt nhìn thấy được. Sử dụng việc capture HAR khi mục tiêu là kiểm tra lưu lượng HTTP có cấu trúc.

Một Vài Nội Dung Có Thể Thiếu Hoặc Được Mã Hóa

HAR hỗ trợ các trường nội dung tùy chọn. Một bộ ghi có thể bỏ qua các thân phản hồi, và các tài nguyên nhị phân có thể được mã hóa.

Trước khi phân tích response.content.text, hãy kiểm tra rằng:

  • Trường text tồn tại.
  • Loại nội dung được mong đợi.
  • Trường encoding được xử lý nếu có.
  • Nội dung không bị bỏ qua bởi cấu hình ghi.

Khi Tái Phát Không Cần Trình Duyệt Hoạt Động

Một yêu cầu được ghi lại có thể được phát lại thành công khi máy chủ đang hoạt động vẫn chấp nhận yêu cầu tái cấu trúc.

Điểm cuối công cộng /api/quotes hoạt động vì nó không phụ thuộc vào một phiên xác thực đã hết hạn.

Việc phát lại trở nên phức tạp hơn khi yêu cầu gốc sử dụng:

  • Cookie phiên
  • Mã thông báo CSRF
  • Thông tin đăng nhập ngắn hạn
  • URL đã ký
  • Chữ ký yêu cầu theo phiên
  • Trạng thái chỉ được lưu trữ bên trong trình duyệt
  • Dữ liệu được tạo ra bởi một bước điều hướng trước đó
  • Một thân yêu cầu mà nội dung thay đổi theo phiên

HAR có thể giữ lại các giá trị thông tin đăng nhập gốc, nhưng không thể kéo dài thời gian hiệu lực của chúng. Khi các giá trị đó hết hạn, một phiên trình duyệt mới có thể cần thiết để tạo ra trạng thái mới.

Phát Lại Dữ Liệu HAR Một Cách An Toàn

Một tệp HAR có thể chứa dữ liệu phiên nhạy cảm.

Các tiêu đề yêu cầu và phản hồi có thể tiết lộ:

  • Cookie
  • Tiêu đề xác thực
  • Khóa API
  • Các định danh phiên
  • URL nội bộ
  • Dữ liệu cá nhân được trả về bởi một điểm cuối

Xem xét các tệp HAR như là các đối tượng nhạy cảm:

  • Không cam kết chúng vào một kho lưu trữ công khai.
  • Loại bỏ thông tin đăng nhập trước khi chia sẻ.
  • Giới hạn quyền truy cập vào các phiên sản xuất đã được lưu trữ.
  • Tránh ghi lại hoàn chỉnh tiêu đề không cần thiết.
  • Chỉ lưu trữ các bản capture cần thiết cho nhiệm vụ gỡ lỗi hoặc kiểm toán.
  • Xóa các bản lưu trữ theo yêu cầu giữ lại của dự án.

Kho lưu trữ trong hướng dẫn này đến từ một trang trình diễn công khai không xác thực. Những giả định tương tự không nên được áp dụng tự động cho các ứng dụng đã xác thực.

Vấn Đề Thường Gặp

Tệp HAR Không Xuất Hiện

Nguyên nhân phổ biến nhất là đã đóng trình duyệt mà không đóng rõ ràng ngữ cảnh.

Sử dụng:

python Copy
context.close()
browser.close()

Cũng xác nhận rằng quá trình có thể ghi vào thư mục chứa HAR_PATH.

HAR Không Chứa Thân Phản Hồi

Xác nhận rằng ngữ cảnh sử dụng:

python Copy
record_har_content="embed"

Sau đó kiểm tra xem entry["response"]["content"]["text"] có tồn tại không. Một số tài nguyên có thể bị bỏ qua hoặc được đại diện với một mã hóa.

urllib Từ Chối Một Tên Tiêu Đề

Loại bỏ bất kỳ tiêu đề nào có tên bắt đầu bằng :. Đây là tiêu đề giả HTTP/2, không phải là các trường tiêu đề thông thường.

URL và phương thức yêu cầu đã mang ý nghĩa liên quan của chúng.

Phản Hồi Tái Phát Bị Nén Một Cách Bất Ngờ

Đừng sao chép giá trị accept-encoding của trình duyệt một cách mù quáng trừ khi client phát lại hỗ trợ mọi mã hóa nội dung đã được quảng cáo.

Hãy để client HTTP đàm phán một mã hóa mà nó có thể giải mã.

Phản Hồi Mới Không Khớp Với HAR

Một sự không khớp không nhất thiết có nghĩa là mã tái cấu trúc là sai.

Máy chủ có thể trả lại nội dung đang thay đổi, dấu thời gian, các trường ngẫu nhiên, kết quả cụ thể theo vị trí địa lý, hoặc dữ liệu gắn liền với thông tin đăng nhập không còn hợp lệ.

So sánh các trường được mong đợi sẽ giữ ổn định thay vì giả định rằng mỗi điểm cuối luôn trả về số byte giống hệt nhau.

Kết Luận

record_har_path của Playwright biến một ngữ cảnh trình duyệt thành một kho lưu trữ HTTP bền vững.

Quy trình làm việc có ba giai đoạn rõ ràng:

  1. Kết nối Playwright với Scrapeless Scraping Browser và ghi lại session trang.
  2. Đóng trình duyệt và kiểm tra log.entries như một JSON thông thường.
  3. Tái cấu trúc một yêu cầu đủ điều kiện với urllib và so sánh phản hồi trực tiếp của nó với nội dung đã ghi lại.

Trình duyệt chỉ cần thiết để tạo ra kho lưu trữ. Khi context.close() xóa sạch HAR, tệp có thể được phân tích trên một máy không có cài đặt Playwright, quy trình trình duyệt, hoặc kết nối CDP.

Sự tách biệt đó khiến việc capture HAR trở nên hữu ích cho gỡ lỗi sau phiên, phát hiện API nội bộ, kiểm toán mạng, và tái cấu trúc yêu cầu. Nó cũng giữ cho các hạn chế luôn hiển thị: HAR không lưu trữ các khung WebSocket, trạng thái hình ảnh đã được hiển thị, hoặc tính hiệu lực tương lai của các thông tin đăng nhập đã được ghi lại.
Xem trang sản phẩm Scraping Browser để tìm hiểu về khả năng phiên lướt web phía sau quy trình capture, và kiểm tra các gói giá của Scrapeless khi chuyển từ một phiên trình diễn sang khối lượng capture lớn hơn.

Giải thích về Giao thức Chrome DevTools bao gồm bề mặt giao thức bên dưới kết nối trình duyệt.

Sẵn Sàng Để Lưu Trữ Một Phiên Trình Duyệt Thực?

Tham gia cộng đồng Scrapeless để so sánh các mẫu capture của Playwright và quy trình gỡ lỗi trình duyệt với các nhà phát triển khác: Discord · Telegram.

Đăng ký tại app.scrapeless.com để nhận miễn phí thời gian chạy Scraping Browser, sau đó điều chỉnh các bước capture, kiểm tra và tái tạo yêu cầu cho một trang công cộng có liên quan đến dự án của bạn.


Câu Hỏi Thường Gặp

H: Tệp HAR là gì?

Tệp HAR là một kho lưu trữ JSON của các giao dịch HTTP được ghi lại trong một phiên trình duyệt. Mảng log.entries của nó chứa một đối tượng cho mỗi yêu cầu đã ghi, với thông tin yêu cầu, phản hồi, thời gian và nội dung lồng nhau.

Một tệp HAR không phải là ảnh chụp màn hình, video trang hoặc snapshot DOM hoàn chỉnh.

H: Capture HAR khác gì so với việc chặn yêu cầu trực tiếp?

Capture HAR ghi lại lưu lượng HTTP trong ngữ cảnh trình duyệt một cách rộng rãi, trong khi việc chặn trực tiếp quan sát các yêu cầu phù hợp khi chúng xảy ra.

Việc chặn trực tiếp hữu ích khi điểm cuối đã được biết. Capture HAR hữu ích khi yêu cầu quan trọng chỉ có thể được xác định sau khi phiên đã kết thúc.

H: Có cần trình duyệt để đọc tệp HAR không?

Không. Một tệp HAR hoàn chỉnh là một tài liệu JSON thông thường có thể được đọc bằng mô-đun json của Python.

Trình duyệt cần thiết trong quá trình capture, nhưng không cần thiết trong kiểm tra ngoại tuyến.

H: Capture HAR có bao gồm lưu lượng WebSocket không?

Capture HAR không lưu trữ các tin nhắn được trao đổi bên trong một kết nối WebSocket đã thiết lập.

Sử dụng một trình nghe khung WebSocket khi trang phụ thuộc vào một nguồn socket trực tiếp. HAR vẫn có thể bao gồm lưu lượng HTTP thông thường được sử dụng bởi cùng một trang.

H: Ghi lại HAR của Playwright có giống với ghi lại phiên Scrapeless không?

Không. Ghi lại HAR của Playwright tạo ra một kho lưu trữ mạng có cấu trúc, trong khi ghi lại phiên Scrapeless tạo ra một bản phát lại hình ảnh của phiên trình duyệt được render.

Sử dụng HAR để phân tích yêu cầu và phản hồi. Sử dụng ghi lại phiên khi hành vi trang có thể nhìn thấy là đối tượng của cuộc điều tra.

H: Ví dụ urllib có giống với route_from_har() của Playwright không?

Không. route_from_har() phục vụ phản hồi đã ghi cho các yêu cầu được thực hiện bên trong ngữ cảnh trình duyệt Playwright đang hoạt động.

Ví dụ urllib đọc một yêu cầu từ HAR và gửi một yêu cầu mới đến máy chủ mà không cần khởi động trình duyệt.

H: Tại sao một HAR chứa các tiêu đề như :authority:method?

Những tên này là các trường tiêu đề giả của HTTP/2 được sử dụng để truyền dữ liệu điều khiển yêu cầu trong giao thức HTTP/2.

Chúng không phải là các trường tiêu đề thông thường, vì vậy một khách hàng theo kiểu HTTP/1.1 phải thể hiện ý nghĩa của chúng thông qua phương thức yêu cầu và URL thay vì sao chép các tên có tiền tố hai chấm.

H: Có thể phát lại mọi yêu cầu đã ghi thành công không?

Không. Một yêu cầu chỉ có thể được phát lại trong khi máy chủ trực tiếp chấp nhận phương thức, URL, nội dung, tiêu đề và thông tin xác thực đã được tái tạo.

Các yêu cầu phụ thuộc vào cookie hết hạn, mã CSRF, URL đã ký hoặc thông tin xác thực bearer ngắn hạn có thể yêu cầu một phiên trình duyệt mới.

H: Có cần một proxy riêng cho quy trình này không?

Không cần cấu hình proxy riêng khi kết nối Scraping Browser của Scrapeless đã chỉ định quốc gia proxy mong muốn.

Ví dụ đặt proxyCountry=US trong URL kết nối CDP, vì vậy phiên trình duyệt sử dụng kết nối đó.

H: Chia sẻ tệp HAR có an toàn không?

Một tệp HAR nên được xem như nhạy cảm cho đến khi nội dung của nó được xem xét và làm sạch.

Nó có thể chứa cookie, tiêu đề ủy quyền, khóa API, điểm cuối nội bộ, dữ liệu biểu mẫu đã gửi hoặc nội dung phản hồi riêng tư. Xóa các giá trị nhạy cảm trước khi chia sẻ hoặc cam kết tệp.

H: Ghi lại HAR có chỉ hoạt động với Scraping Browser của Scrapeless không?

Không. record_har_path là một tùy chọn ngữ cảnh trình duyệt của Playwright và có thể được sử dụng với các trình duyệt tương thích địa phương hoặc từ xa.

Scraping Browser của Scrapeless cung cấp môi trường Chromium từ xa được quản lý và cấu hình proxy được sử dụng trong giai đoạn capture.

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