Xây dựng Arbitra: Tiện ích Chrome so sánh giá thời gian thực cho Retail Arbitrage

05 tháng 4, 2026·9 phút đọc

Kinh doanh chênh lệch giá (Retail Arbitrage) về lý thuyết rất đơn giản nhưng thực tế lại là cơn ác mộng với hàng chục tab trình duyệt. Bài viết này chia sẻ hành trình xây dựng Arbitra – một tiện ích Chrome giúp tự động so sánh giá giữa Amazon, Mercari và Yahoo Auctions, bao gồm các thách thức về kỹ thuật cào dữ liệu (web scraping), kiến trúc Manifest V3 và thuật toán tính toán lợi nhuận.

Xây dựng Arbitra: Tiện ích Chrome so sánh giá thời gian thực cho Retail Arbitrage

Kinh doanh chênh lệch giá (Retail Arbitrage) về mặt lý thuyết rất đơn giản: mua một sản phẩm ở nền tảng này với giá rẻ và bán ở nền tảng khác với giá cao hơn để hưởng phần chênh lệch. Tuy nhiên, trên thực tế, công việc này biến thành "cái chết theo hàng tá tab trình duyệt".

Bạn đang xem một sản phẩm trên Amazon Nhật Bản. Liệu nó có rẻ hơn trên Mercari? Hoặc Yahoo Auctions thì sao? Bạn mở thêm ba tab, gõ tên sản phẩm vào thanh tìm kiếm của từng trang, cuộn qua kết quả, tính toán trong đầu các loại phí, và cố nhớ giá gốc để so sánh. Đến khi hoàn tất, bạn đã mất mười phút cho một sản phẩm và trình duyệt của bạn đã có 47 tab đang mở.

Giao diện tiện ích ArbitraGiao diện tiện ích Arbitra

Sau hàng trăm lần lặp lại quy trình này, tôi quyết định tự động hóa nó. Kết quả là Arbitra – một tiện ích Chrome nằm trong thanh bên (side panel) của trình duyệt, có khả năng so sánh giá giữa Amazon, Mercari và Yahoo Auctions theo thời gian thực. Khi bạn truy cập trang sản phẩm của bất kỳ nền tảng nào, Arbitra sẽ trích xuất dữ liệu, tìm kiếm trên hai nền tảng còn lại và hiển thị điểm lợi nhuận để bạn biết cơ hội kinh doanh này có đáng theo đuổi hay không.

Bài viết này sẽ đi sâu vào kiến trúc kỹ thuật, các thách thức trong việc cào dữ liệu (web scraping) và thuật toán chấm điểm giúp đưa ra quyết định mua hoặc bỏ qua.

Kiến trúc: Content Scripts, Background Worker và Side Panel

Các tiện ích Chrome được xây dựng trên Manifest V3 có một mô hình giao tiếp riêng biệt. Bạn không thể chỉ có một tập lệnh đơn lẻ (monolithic script) làm mọi thứ. Thay vào đó, bạn có ba ngữ cảnh thực thi cần trao đổi với nhau:

  • Content Scripts: Được chèn vào các trang web, có quyền truy cập vào DOM nhưng quyền truy cập Chrome API hạn chế.
  • Service Worker: Chạy trong nền, xử lý Chrome API và các yêu cầu cross-origin.
  • Bề mặt UI (UI Surfaces): Popup, thanh bên hoặc trang tùy chọn, mỗi cái là một ứng dụng React riêng biệt.

Dưới đây là cách dữ liệu luân chuyển trong Arbitra:

[Trang Amazon] --> Content Script trích xuất dữ liệu sản phẩm
                     |
                     v
              Background Service Worker
              - Nhận dữ liệu qua chrome.runtime.sendMessage
              - Xây dựng truy vấn tìm kiếm
              - Lấy dữ liệu Mercari + Yahoo Auctions song song
              - Tính toán điểm liên quan
              - Lưu trữ kết quả trong bộ nhớ
                     |
                     v
              Side Panel (React + Zustand)
              - Nhận kết quả qua chrome.runtime.onMessage
              - Hiển thị thẻ so sánh giá
              - Tính toán điểm lợi nhuận
              - Hiển thị phán quyết MUA / XÉT / BỎ QUA

Tôi chọn thanh bên (side panel) thay vì popup bởi vì quy trình arbitrage cần sự kiên trì. Popup sẽ đóng ngay khi bạn click ra ngoài. Thanh bên thì luôn mở trong khi bạn duyệt web, nghĩa là bạn có thể điều hướng giữa các trang sản phẩm và thấy so sánh cập nhật tự động.

Cào dữ liệu từ ba nền tảng khác nhau

Thách thức thực sự đầu tiên là trích xuất thông tin sản phẩm từ ba nền tảng có cấu trúc HTML hoàn toàn khác biệt.

Amazon: Nghĩa địa của các bộ chọn (Selector)

Amazon liên tục thay đổi DOM của trang sản phẩm. Một bộ chọn (selector) hoạt động hôm nay có thể bị hỏng vào tháng sau. Cách tiếp cận của tôi là xây dựng danh sách ưu tiên các bộ chọn và lần lượt thử cho đến khi cái nào hoạt động:

function extractPrice(): number {
  const selectors = [
    '#corePrice_feature_div .a-price .a-offscreen',
    '#corePriceDisplay_desktop_feature_div .a-price .a-offscreen',
    '.priceToPay .a-offscreen',
    // ... hơn 10 bộ chọn nữa
    '.a-price .a-offscreen', // phương án dự phòng cuối cùng
  ];

  for (const selector of selectors) {
    const el = document.querySelector(selector);
    if (el?.textContent) {
      const cleaned = el.textContent.replace(/[ký hiệu tiền tệ]/g, '');
      const price = parseInt(cleaned, 10);
      if (price > 0) return price;
    }
  }
  return 0;
}

Ngoài giá, Arbitra còn trích xuất ASIN (mã định danh sản phẩm của Amazon), tên thương hiệu, số kiểu (model number) và hình ảnh sản phẩm. Mỗi phần siêu dữ liệu trích xuất giúp nâng cao độ chính xác của tìm kiếm trên các nền tảng khác.

Mercari: SPA và API Endpoint

Mercari là một ứng dụng đơn trang (SPA) được xây dựng bằng Next.js, nghĩa là DOM được hiển thị ở phía máy khách và thay đổi thường xuyên.

Điều thú vị là tìm kiếm sản phẩm trên Mercari từ background service worker. Vì content script bị sandbox trong trang của nó và không thể thực hiện các yêu cầu cross-origin, tất cả các truy vấn tìm kiếm đều chạy từ background worker. Mercari cung cấp một endpoint API tìm kiếm chấp nhận các yêu cầu POST JSON. Khi lệnh gọi API trực tiếp thành công, kết quả trả về dưới dạng dữ liệu có cấu trúc.

Khi cách tiếp cận API thất bại (do giới hạn tốc độ, thay đổi định dạng, v.v.), tiện ích sẽ quay lại fetching trang HTML tìm kiếm và phân tích cú pháp. Điều này liên quan đến việc trích xuất thẻ script __NEXT_DATA__ hoặc sử dụng Regex để tìm kiếm mẫu ô mục.

Tôi cũng xây dựng một "Cách tiếp cận lai" (Hybrid Approach) cho Mercari. Khi bạn đã ở trên trang tìm kiếm của Mercari, một nút nổi sẽ hiện ra. Nhấn vào nó sẽ kích hoạt content script trích xuất kết quả tìm kiếm trực tiếp từ DOM đã hiển thị.

Yahoo Auctions: Thách thức đặc thù của đấu giá

Yahoo Auctions thêm độ phức tạp vì mặt hàng có cả giá thầu hiện tại và giá tùy chọn mua ngay. Tiện ích thử nhiều định dạng URL và phân tích cú pháp HTML để trích xuất ID đấu giá, giá và tên sản phẩm.

Xây dựng truy vấn tìm kiếm thông minh

Cách tiếp cận ngây thơ là lấy tên sản phẩm đầy đủ từ nền tảng này và dán vào hộp tìm kiếm của nền tảng khác. Cách này thất bại thảm hại vì tên sản phẩm Amazon thường chứa đầy từ khóa SEO, thông số kích thước và ngôn ngữ tiếp thị.

Trình xây dựng truy vấn của Arbitra sử dụng hệ thống ưu tiên:

  1. Thương hiệu + Số kiểu: Kết hợp chính xác nhất.
  2. Thương hiệu + Từ khóa đã làm sạch: Trích xuất các từ có nghĩa, loại bỏ tiếng ồn.
  3. Số kiểu đơn lẻ: Nếu không tìm thấy thương hiệu.
  4. Tên sản phẩm đã làm sạch: Phương án cuối cùng, lấy 3 từ có nghĩa đầu tiên.

Hàm trích xuất từ khóa sẽ loại bỏ các từ tiếng ồn (ví dụ: "miễn phí vận chuyển", "hàng chính hãng"), nội dung trong ngoặc và thông số quy cách (mm, kg...).

Thuật toán chấm điểm liên quan và lợi nhuận

Kết quả tìm kiếm đa nền tảng thường rất nhiễu. Mỗi kết quả tìm kiếm nhận được điểm liên quan dựa trên các yếu tố: khớp số kiểu (+100 điểm), khớp thương hiệu (+50 điểm), và các mẫu âm tính (-40 điểm) nếu chứa từ khóa phụ kiện như "case", "cover".

Sau khi có giá từ nhiều nền tảng, Arbitra tính toán điểm lợi nhuận trên thang điểm 0-100 với ba phán quyết: MUA (70+), XÉT (40-69), và BỎ QUA (dưới 40).

Điểm số kết hợp bốn thành phần:

  • Biên lợi nhuận (Profit margin): 30%+ = 40 điểm.
  • ROI: Tỷ suất lợi nhuận trên vốn đầu tư.
  • Chênh lệch giá: Khoảng cách giá giữa hai nền tảng.
  • Cạnh tranh: (Dành cho triển khai tương lai).

Thanh bên trình bày điều này dưới dạng thẻ mã màu: xanh lá cho MUA, vàng cho XÉT, đỏ cho BỎ QUA. Nó cũng tính toán các phí đặc thù của từng nền tảng (phí giới thiệu Amazon, phí 10% của Mercari, v.v.) để đưa ra con số lợi nhuận ròng chính xác.

Bài học kinh nghiệm từ việc cào dữ liệu quy mô lớn

Việc xây dựng Arbitra đã dạy cho tôi một số bài học khó khăn về web scraping trong ngữ cảnh tiện ích trình duyệt:

  • Giới hạn tốc độ (Rate limiting) là có thật: Mỗi tìm kiếm kích hoạt ít nhất hai yêu cầu HTTP. Nếu người dùng click "phân tích" quá nhanh, tiện ích có thể bị chặn tạm thời. Tôi đã thêm độ trễ 3 giây giữa các lần kiểm tra giá trong watchlist.
  • Phân tích cú pháp HTML rất mong manh: Tôi phải xây dựng 5 chiến lược dự phòng khác nhau để phân tích kết quả tìm kiếm của Mercari. Cách tiếp cận này không đẹp mắt nhưng rất kiên cường.
  • Khả năng khác nhau giữa Content Script và Background Worker: Content Script chạm được vào DOM nhưng không thể gọi cross-origin. Background Worker có thể fetch từ bất kỳ domain nào nhưng không chạm vào DOM.
  • Điều hướng SPA làm hỏng Content Script: Cần sử dụng MutationObserver để theo dõi thay đổi URL và khởi động lại script khi người dùng điều hướng mà không tải lại trang.

Công nghệ sử dụng

Dự án này sử dụng một bộ công nghệ hiện đại:

  • Build: Vite + CRXJS (Plugin Chrome extension cho Vite).
  • Ngôn ngữ: TypeScript.
  • UI: React 19 + Tailwind CSS 4.
  • Quản lý trạng thái: Zustand.
  • Biểu đồ: Chart.js.
  • Backend: Supabase (tier miễn phí) để lưu lịch sử giá và đồng bộ cài đặt.
  • Thanh toán: ExtensionPay cho gói đăng ký Pro.

Nếu bạn đang kinh doanh chênh lệch giá giữa các chợ thương mại điện tử Nhật Bản, hoặc chỉ tò mò về sự chênh lệch giá giữa Amazon, Mercari và Yahoo Auctions, hãy thử trải nghiệm Arbitra. Gói miễn phí đủ dùng để bạn đánh giá xem nó có phù hợp với quy trình làm việc của mình hay không.

Bài viết được tổng hợp và biên soạn bằng AI từ các nguồn tin tức công nghệ. Nội dung mang tính tham khảo. Xem bài gốc ↗