🎯 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ây khả năng truy cập không phải là một trang rẻ hơn: Đo lường những gì các tác nhân đọc

Michael Lee
Michael Lee

Expert Network Defense Engineer

07-Aug-2026

TL;DR:

  • Cây truy cập là thứ mà hầu hết các tác nhân trình duyệt cung cấp cho mô hình thay vì HTML thô, được lấy qua Giao thức Chrome DevTools với Accessibility.getFullAXTree.
  • không phải là một sự nén của trang. Trên một trang danh mục trực tiếp: HTML thô 9,824 token, innerText 582, cây truy cập đầy đủ 5,951 — cây này tốn 10.2× văn bản thường.
  • Lý do nằm ở các vai trò của nút: trong số 1,401 nút, 267 là StaticText và 391 là InlineTextBox, vì vậy hầu hết các chuỗi được lưu trữ hai lần.
  • Lọc theo vai trò tương tác cho 742 token trên 114 nút — 1.3× innerText — trong khi giữ mọi thứ mà tác nhân cần để nhấp chuột.
  • Đo lường qua Chromium cục bộ và qua Trình duyệt Scraping không có mảnh, mọi con số đều giống nhau, do đó đại diện trang của một tác nhân không bị sai lệch giữa các môi trường.
  • Kế hoạch miễn phí của Scrapeless phủ sóng chạy trình duyệt đám mây trong hướng dẫn này.

Mỗi tác nhân trình duyệt phải trả lời một câu hỏi trước khi có thể làm gì đó: bạn cung cấp cho mô hình điều gì? Một tài liệu HTML 51,004 ký tự không phù hợp với ngân sách hướng dẫn hợp lý, và một ảnh chụp màn hình tốn token hình ảnh và mất chuỗi chính xác. Câu trả lời thông thường thứ ba là cây truy cập.

Câu trả lời đó đúng về hình thức và sai về giá cả. Cây này chứa các vai trò và tên — link, button, heading — điều mà chính xác là những gì mà tác nhân cần để quyết định nơi nhấp chuột. Nó cũng, không được lọc, tốn kém hơn một bậc so với văn bản thường của trang.

Hướng dẫn này kéo cây qua CDP, đo lường nó so với các lựa chọn khác trên cùng một trang trực tiếp, và cho thấy bộ lọc mà khiến nó đáng giá để gửi đi.

Cây Truy Cập Là Gì

Trình duyệt xây dựng một cây thứ hai song song với DOM, dành cho các trình đọc màn hình. Mỗi nút mang một role — một trong những loại điều khiển được định nghĩa bởi quy định WAI-ARIA — và một name, chuỗi mà một trình đọc màn hình công bố, được suy ra bởi thuật toán trong Tính toán Tên và Mô tả Có thể Truy cập. Các bao bọc trình bày sẽ gộp lại, aria-* thuộc tính sẽ được giải quyết, và các phần tử tương tác được gán nhãn.

Cấu trúc đó là lý do mà các tác nhân thích nó. link: Books to Scrape có thể hành động trực tiếp theo cách mà <div class="col-sm-8 h1"><a href="..."> thì không. Cây này được tiết lộ bởi miền Truy cập của Giao thức Chrome DevTools, và nó là cùng một dữ liệu mà Chrome hiển thị trong ngăn truy cập của chính nó. Nếu CDP chính nó là mới, giới thiệu giao thức đề cập đến phương tiện mà bài viết này dựa vào.

Cài Đặt

bash Copy
pip install playwright tiktoken
playwright install chromium

tiktoken chỉ ở đây để đếm token; việc trích xuất cần có Playwright một mình. Chạy xác minh sử dụng Playwright 1.59.0 và tiktoken 0.12.0.

Kéo Cây

Playwright tiết lộ một phiên CDP thô, đó là cách bạn đạt được các miền mà nó không gói lại:

python Copy
    cdp = page.context.new_cdp_session(page)
    nodes = cdp.send("Accessibility.getFullAXTree")["nodes"]

Mỗi nút là một dict mà rolename của nó lại là các đối tượng với khóa value. Hầu hết các nút không có tên — các vùng chứa, các nút bị bỏ qua và các hộp bố trí — vì vậy phép chiếu hữu ích là vai trò cộng với tên cho những cái được đặt tên:

python Copy
def ax_lines(nodes, roles=None):
    lines = []
    for node in nodes:
        role = (node.get("role") or {}).get("value", "")
        name = ((node.get("name") or {}).get("value") or "").strip()
        if not name:
            continue
        if roles is not None and role not in roles:
            continue
        lines.append(f"{role}: {name}")
    return lines

Trên một danh mục sách trực tiếp cho ra các dòng như:

text Copy
RootWebArea: All products | Books to Scrape - Sandbox
heading: All products
link: Books to Scrape
StaticText: We love being scraped!
link: Home
StaticText: /
InlineTextBox: /

Hai trong số bảy dòng đó là cùng một dấu gạch chéo. Sự trùng lặp đó là toàn bộ câu chuyện về chi phí.

Đo Lường Nó So Với Các Lựa Chọn Khác

Đếm token cho ba đại diện của cùng một trang giống hệt nhau:

python Copy
def measure(page, label):
    html = page.content()
    text = page.evaluate("document.body.innerText")
    cdp = page.context.new_cdp_session(page)
    nodes = cdp.send("Accessibility.getFullAXTree")["nodes"]

    full = "\n".join(ax_lines(nodes))
    acts = "\n".join(ax_lines(nodes, INTERACTIVE))
    roles = [(n.get("role") or {}).get("value", "") for n in nodes]
text Copy
  raw html            tokens=  9824  chars=51004
  innerText           tokens=   582  chars=2029
  AX full             tokens=  5951  named_nodes=864
  AX interactive only tokens=   742  nodes=114
  AX total nodes      1401
  StaticText nodes    267
  InlineTextBox nodes 391
  price in html/text/ax: True/True/True

Cây truy cập đầy đủ tốn 5,951 token so với innerText's 582. Nó là 10.2× văn bản thường của cùng một trang, và khoảng 60% HTML thô mà nó lẽ ra phải thay thế.

Số lượng vai trò giải thích điều này. Trong số 1,401 nút, 267 là StaticText và 391 là InlineTextBox — 658 nút, gần một nửa cây, dành cho văn bản mà trang đã chứa một lần. InlineTextBox nút là các đoạn bố trí: một câu duy nhất bị chia thành hai dòng đã được hiển thị sẽ trở thành hai trong số đó. Gửi toàn bộ cây có nghĩa là phải trả tiền cho mỗi chuỗi ít nhất hai lần.

Đáng nói một cách rõ ràng: không có gì bị mất. Giá £51.77 có mặt trong HTML, trong innerText, và trong cây truy cập. Trên trang này, cây này tốn kém hơn, không ít đầy đủ hơn.

Lọc Để Những Gì Một Tác Nhân Có Thể Hành Động

Một tác nhân đọc một trang cần văn bản. Một tác nhân vận hành một trang cần những thứ mà nó có thể nhấp chuột và nhập vào. Đó là một tập hợp vai trò nhỏ:

python Copy
INTERACTIVE = {"link", "button", "textbox", "combobox", "checkbox", "radio", "menuitem", "tab"}

Việc gửi tập hợp đó đến cùng một chức năng sẽ gộp cây thành 114 nút và 742 token — 1.3× innerText, và rẻ hơn 8× so với phiên bản không được lọc. Mỗi liên kết và điều khiển giữ lại tên có thể truy cập của nó, điều mà một hướng dẫn nhấp chuột đề cập đến.
Điều đó gợi ý một sự phân chia thay vì một lựa chọn. Sử dụng innerText khi mô hình cần đọc và trích xuất, sử dụng cây lọc vai trò khi nó cần quyết định những gì để hoạt động, và gửi cả hai khi nhiệm vụ cần cả hai — cùng nhau chúng là 1.324 token, vẫn là một phần tám của HTML thô. Hướng dẫn vòng lặp tác nhân đề cập đến những gì xảy ra sau khi quyết định đó được đưa ra.

Chạy nó trên Trình duyệt Scraping

Không có gì ở trên cần một trình duyệt cục bộ. Trình duyệt Scraping Scrapeless nói cùng một giao thức, vì vậy phiên CDP và cuộc gọi truy cập không thay đổi — chỉ kết nối là khác:

python Copy
    endpoint = (
        "wss://browser.scrapeless.com/api/v2/browser"
        f"?token={os.environ['SCRAPELESS_API_KEY']}&sessionTTL=180&proxyCountry=ANY"
    )
    with sync_playwright() as p:
        browser = p.chromium.connect_over_cdp(endpoint, timeout=90000)
        page = browser.new_page()
        page.goto(URL, wait_until="domcontentloaded")
        measure(page, "Scrapeless Scraping Browser")
        browser.close()

Chạy trên đám mây trả về các số liệu giống hệt nhau trên mọi chỉ số: 9.824 / 582 / 5.951 / 742 token, 1.401 nút, số StaticTextInlineTextBox giống nhau. Điều đó có một hệ quả thực tiễn. Một đại diện trang web di chuyển giữa máy tính xách tay của bạn và sản xuất sẽ làm hành vi của tác nhân không thể tái tạo; cái này không phải như vậy. Giữ chìa khóa trong môi trường như SCRAPELESS_API_KEY, và xem giới thiệu Trình duyệt Scraping để biết các thông số phiên còn lại.

Bắt đầu mất một phút — tạo một tài khoản Scrapeless miễn phí và kế hoạch miễn phí bao gồm lần chạy này.

Chạy nó

bash Copy
export SCRAPELESS_API_KEY="your-api-key"
python3 ax_demo.py

Đầu ra hoàn chỉnh từ lần chạy xác minh:

text Copy
playwright 1.59.0 | tiktoken 0.12.0
[local chromium]
  raw html            tokens=  9824  chars=51004
  innerText           tokens=   582  chars=2029
  AX full             tokens=  5951  named_nodes=864
  AX interactive only tokens=   742  nodes=114
  AX total nodes      1401
  StaticText nodes    267
  InlineTextBox nodes 391
  price in html/text/ax: True/True/True

[Scrapeless Scraping Browser]
  raw html            tokens=  9824  chars=51004
  innerText           tokens=   582  chars=2029
  AX full             tokens=  5951  named_nodes=864
  AX interactive only tokens=   742  nodes=114
  AX total nodes      1401
  StaticText nodes    267
  InlineTextBox nodes 391
  price in html/text/ax: True/True/True

ratios vs innerText: html=16.9x  ax_full=10.2x  ax_interactive=1.3x

Khắc phục sự cố

Accessibility.getFullAXTree trả về rất ít nút. Cây được xây dựng lười biếng. Điều hướng và chờ nội dung trước khi yêu cầu nó, và gọi Accessibility.enable trước nếu khách hàng của bạn không làm điều đó một cách ngầm định.

Mỗi nút có tên rỗng. Bạn đang đọc node["name"] trực tiếp. Cả rolename đều là đối tượng — chuỗi nằm ở node["name"]["value"].

Số lượng nút khác nhau giữa hai lần chạy của cùng một trang. Các nút InlineTextBox theo đường gói dòng, vì vậy độ rộng viewport khác nhau thay đổi số lượng của chúng. Đặt một viewport rõ ràng khi số lượng tự nó quan trọng.

Cây bỏ qua một số thứ hiển thị trên màn hình. Nội dung được đánh dấu aria-hidden, và văn bản được tạo ra hoàn toàn bởi CSS ::before/::after, cố ý vắng mặt. Đọc những cái đó từ DOM thay vào đó; cây truy cập không phải là một sự thay thế cho nó.

Vai trò trông không quen thuộc. StaticText, InlineTextBox, và RootWebArea là các vai trò Chrome nội bộ hơn là vai trò ARIA, đó là lý do tại sao việc lọc trên danh sách cho phép chỉ ARIA làm giảm hầu hết cây. Những ánh xạ API truy cập cơ bản định nghĩa các vai trò mà một trình duyệt được yêu cầu tiết lộ; bất cứ điều gì ngoài bộ đó là đặc thù của động cơ.

Kết luận

Cây truy cập là một câu trả lời tốt cho những gì một tác nhân nên được cung cấp, và là một mặc định xấu trong hình thức thô của nó. Trên trang được đo ở đây, nó tốn 5.951 token — gấp mười lần văn bản thuần túy mà nó thường được cho là nén — vì gần một nửa số nút của nó tồn tại để mô tả văn bản mà trang đã nói trước đó một lần.

Lọc theo các vai trò mà một tác nhân có thể hành động, cây giống nhau là 742 token và vẫn liệt kê mọi điều khiển. Đó là phiên bản để đưa vào một gợi ý, kết hợp với innerText khi nhiệm vụ cũng yêu cầu đọc. Đo cả hai trên mục tiêu của bạn trước khi chọn: các số ở đây đến từ một trang danh mục, và tỷ lệ phụ thuộc hoàn toàn vào việc bao nhiêu phần của trang là văn xuôi và bao nhiêu phần là điều khiển.

Sẵn sàng thử chưa? Bắt đầu với kế hoạch miễn phí Scrapeless và xem bảng giá hiện tại cho khối lượng lớn hơn.

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

Q: Tôi có nên gửi cây truy cập thay vì HTML không?

Gửi một phiên bản đã lọc của nó. Chưa lọc nó đo 5.951 token so với 9.824 cho HTML thô — một sự tiết kiệm, nhưng ít hơn nhiều so với mong đợi. Giới hạn vào các vai trò tương tác nó giảm xuống còn 742, đây là nơi thực sự giảm.

Q: Cây truy cập có rẻ hơn văn bản thuần túy không?

Không, và đây là sự hiểu lầm phổ biến. Trên trang được đo ở đây, nó tốn 10,2× innerText. Giá trị của cây là các nhãn vai trò mà nó thêm vào, không phải là một tải trọng nhỏ hơn.

Q: Tại sao lại có nhiều nút InlineTextBox như vậy?
Chúng là các đoạn bố cục - mỗi đoạn tương ứng với một dòng văn bản được hiển thị. Một câu văn trải dài trên hai dòng tạo ra hai đoạn, nằm trên nút StaticText giữ cùng một chuỗi. Đó là lý do tại sao 658 trong số 1,401 nút trên trang thử nghiệm là sự trùng lặp văn bản.

H: Cây có chứa mọi thứ trên trang không?

Không hoàn toàn. Nội dung aria-hidden và văn bản được tạo ra bởi các phần tử pseudo-CSS được cố ý loại trừ. Trên trang được đo ở đây không có gì cần thiết bị thiếu - giá cả xuất hiện trong cả ba đại diện - nhưng hãy xác nhận điều đó trên mục tiêu của riêng bạn thay vì giả định.

H: Tôi có cần một Chrome cục bộ để đọc cây khả năng tiếp cận không?

Không. Chạy đám mây trong hướng dẫn này đã sản xuất ra các số byte giống hệt như Chromium cục bộ, vì cả hai đều giao tiếp bằng cùng một giao thức. Chỉ có dòng kết nối là thay đổi.

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