Tất cả bài viết

Dữ liệu thay thế: Khi một lệnh chặn trông giống một điểm dữ liệu

Các pipeline dữ liệu thay thế chịu tổn thất do lỗi thu thập ngầm nhiều hơn là do các mô hình kém. Dưới đây là cách một trang bị chặn biến thành một tín hiệu giả và cách ngăn chặn điều này.

Trang sản phẩm của nhà bán lẻ phản hồi với status 200 nhưng không có nội dung. Pipeline không ghi lại một lượt chặn. Nó ghi lại một kệ hàng trống.

Đó là lỗi mà không ai tính trước trong alternative data. Không phải do thiếu dataset, cũng không phải do vendor chậm. Một tầng thu thập liên tục cung cấp các hàng dữ liệu cho bạn nhưng lại âm thầm đo lường một thứ khác với công ty bạn đang theo dõi.

Thách thức

Vào tháng 1 năm 2026, Exabel đã khảo sát 100 nhà quản lý danh mục đầu tư cơ bản và nhà phân tích tại Mỹ, Anh, Singapore và Hồng Kông, quản lý tổng cộng khoảng 610 tỷ USD. 71% cho biết việc kết hợp dữ liệu từ các nguồn khác nhau là phần gây thất vọng nhất khi làm việc với alternative data, và 94% nói rằng họ đã chạy AI hoặc machine learning ở một khâu nào đó trong quy trình nghiên cứu.

Nhìn vào hai con số đó, bạn sẽ thấy bản chất của vấn đề. Mảng mô hình hóa được trang bị nhân sự đầy đủ. Phần hạ tầng dữ liệu bên dưới thì không.

Một bảng dữ liệu thu thập từ web (giá cả, tình trạng kho, trang tuyển dụng, số lượng đánh giá, danh mục hàng hóa) trước tiên phải là một time series. Mọi time series đều mang một giả định không ai ghi vào spec: dữ liệu quan sát của hôm nay được thu thập theo cùng cách với hôm qua. Phá vỡ giả định đó một cách rõ ràng, bạn nhận được một cảnh báo. Phá vỡ nó một cách âm thầm, bạn nhận được một tín hiệu sai.

Ba lỗi âm thầm đó xuất hiện trong hầu hết mọi bảng dữ liệu thu thập từ web.

Mã 200 nhưng không có nội dung. Các hệ thống chặn bot từ lâu đã không còn trả về mã 403 rõ ràng nữa. Một trang challenge, một cửa sổ xác nhận, hoặc một trang kết quả trống trả về một trạng thái thành công và một body khiến parser của bạn đọc ra kết quả bằng không. Việc có ít danh sách sản phẩm trông sẽ giống hệt như nhu cầu sụt giảm.

Vị trí request bị thay đổi. Giá cả, tiền tệ, mặt hàng, banner quảng cáo, đôi khi là cả việc trang có hiển thị hay không: các nhà bán lẻ quyết định mọi thứ dựa trên nơi request có vẻ xuất phát. Nếu đợt thu thập thứ Hai đi qua Đức và thứ Năm đi qua Ba Lan, thì chuỗi dữ liệu của bạn sẽ xuất hiện một sự thay đổi do hệ thống của bạn chứ không phải do nhà bán lẻ.

Hệ thống xoay vòng lấy ngay phản hồi đầu tiên. Việc luân chuyển qua các điểm exit mà không cho bộ thu thập biết thế nào là thành công sẽ làm hệ thống dừng lại ở điểm exit đầu tiên có phản hồi. Từ chối cũng là một phản hồi. Vậy là dữ liệu được ghi vào, job báo thành công màu xanh, và không ai kiểm tra lại.

Không có vấn đề nào trong số này bắn ra một exception. Ingestion đếm số hàng, dashboard vẫn màu xanh, và nhà phân tích nhận được một biểu đồ. Sau đó, model dành cả quý để học hành vi của hạ tầng thu thập thay vì hành vi của doanh nghiệp.

Hướng tiếp cận

Hãy coi tính toàn vẹn của dữ liệu là một thuộc tính của request, không phải của parser ở bước sau. Cần phải đảm bảo ba điều sau.

1. Mô tả giao diện của một trang thực. Collector không thể tự xác định điều này. Cung cấp một chuỗi string chỉ tồn tại trong nội dung thực tế và một vài chuỗi chỉ xuất hiện khi bị từ chối, lúc đó trang challenge sẽ không còn bị tính là một quan sát. Chúng tôi từng đề cập điều này khi các quy tắc validate được ra mắt: chính bản thân request quyết định tiêu chí thành công.

import requests

r = requests.post(
    "https://api.foura.ai/api/proxy",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "maxTries": 8,
        "exitCountries": ["DE"],
        "request": {
            "method": "GET",
            "url": "https://retailer.example/p/12345",
            "validate": {
                "status": {"accept": [200]},
                "data": {
                    "accept": ["data-testid=\"price\""],
                    "fail": ["Access Denied", "Just a moment"]
                }
            }
        }
    }
).json()

observation = r["data"]        # content your rules accepted, or nothing
exit_id = r["proxy"]           # opaque ID of the exit that delivered it
served_from = r["exitCountry"] # verify it against what you asked for

Việc luân chuyển hiện đã có định nghĩa hoàn thành. Nó tiếp tục thử các exit cho đến khi một exit trả về thứ gì đó vượt qua các quy tắc của bạn, thay vì trả về đối tượng có hình dạng trang đầu tiên mà nó gặp.

2. Giữ cố định điểm thuận lợi. exitCountries là một allowlist nghiêm ngặt của các mã quốc gia hiển thị theo mục tiêu và các exit có địa lý không xác định bị bỏ qua thay vì bị thay thế. Hai lưu ý thực tế, cả hai đều đáng biết trước khi bạn xây dựng dựa trên nó. Siêu dữ liệu quốc gia được làm mới theo chu kỳ (thường trong khoảng mười phút), do đó đây không phải là tra cứu trực tiếp tại thời điểm request, đó chính là lý do tại sao response mang exitCountry để bạn kiểm tra. Và khi pool không có đối sánh nào cho phạm vi mà bạn yêu cầu, lệnh gọi sẽ quay lại với HTTP 200 và một lớp bảo vệ lỗi thay vì một exception. Đọc body, không đọc trạng thái. Giữ nguyên phạm vi và thử lại sau thay vì mở rộng nó, vì phạm vi được mở rộng là một sự phá vỡ trong chuỗi.

3. Giữ danh tính của exit. Trường proxy là một ID mờ, không phải là địa chỉ. Truyền nó trở lại trong lệnh gọi Single hoặc Browser tiếp theo và trang chi tiết đến từ cùng một điểm thuận lợi như trang tìm kiếm đã tìm thấy nó (cách sử dụng lại một exit). Lưu trữ ID đó và header X-FourA-Request-Id cùng với mỗi hàng. Khi một nhà phân tích đặt câu hỏi về một đợt tăng vọt sáu tuần sau, câu hỏi "điều này có thật không?" trở thành một lượt tra cứu thay vì một cuộc tranh luận.

Đối với một nguồn mà bạn đang tích hợp và chưa hiểu rõ, Auto là cách nhanh nhất để tìm ra một đường dẫn hoạt động: nó đi theo bậc thang từ rẻ đến đắt, cho bạn biết bậc nào đã chiến thắng và trả lại session đã hoạt động. Sử dụng nó để tìm tuyến đường, sau đó đặt khối lượng production lên các engine trực tiếp. Phát lại session đó thông qua Single nơi không cần render, Browser nơi nó thực sự cần. Tìm đường và thu thập ở trạng thái ổn định là các công việc khác nhau.

Kết quả

Điều gì thay đổi khi ba thuộc tính đó được giữ nguyên, trên một nhóm gồm vài nghìn trang sản phẩm mỗi ngày trên khắp hàng chục nhà bán lẻ (kịch bản minh họa dựa trên các chuẩn mực của ngành):

  • Khoảng trống là khoảng trống, không phải phỏng đoán. Các từ chối không bao giờ đi vào bảng tính dưới dạng số không, vì vậy tập kết quả trống có nghĩa là nhà bán lẻ không hiển thị gì cả và tín hiệu vắng mặt của bạn rất đáng để giao dịch.
  • Các hàng có thể so sánh. Mọi quan sát trong một chuỗi đều đến từ quốc gia mà chuỗi được xác định, do đó biến động giá là biến động giá.
  • Lịch sử có thể tái tạo. Exit ID cộng với request ID cho mỗi hàng có nghĩa là bất kỳ điểm dữ liệu nào bị tranh chấp đều có thể được theo dõi lại lệnh gọi chính xác đã tạo ra nó.
  • Rẻ hơn cho mỗi hàng có thể sử dụng. Các request đáng lẽ ra sẽ tạo ra một quan sát bị loại bỏ sẽ được thử lại tại thời điểm thu thập thay vì phải trả tiền, được phân tích cú pháp, lưu trữ và sau đó được làm sạch khỏi một quá trình backtest.

Nhưng điều cuối cùng là điều mà các nhóm nghiên cứu đánh giá thấp. Một hàng xấu không miễn phí chỉ vì nó rẻ để tìm nạp. Nó tiêu tốn một chu kỳ nghiên cứu và đôi khi nó làm mất niềm tin của người phải ký duyệt tín hiệu.

Bài học chính

Người mua alt data đánh giá các nhà cung cấp dựa trên mức độ bao phủ, độ trễ và chiều sâu lịch sử. Hầu như không ai đặt câu hỏi quyết định xem một panel có thể giao dịch được hay không: tập dữ liệu này hoạt động như thế nào vào ngày mà nguồn từ chối phản hồi?

Một nhà cung cấp loại bỏ hàng đó là trung thực. Một nhà cung cấp trả về một trang thông báo lỗi (courtesy page) như một kết quả quan sát thực chất đã bán cho bạn phép đo về cơ sở hạ tầng của chính họ, và bạn sẽ phải trả giá cho điều đó trong một quá trình backtest có vẻ hoạt động tốt cho đến khi nó thất bại. Câu hỏi đó cần có trong mọi danh sách kiểm tra thẩm định dữ liệu, và nó phải nằm trong pipeline của riêng bạn trước tiên, bởi vì nếu bạn tự thu thập dữ liệu, bạn chính là nhà cung cấp.