Vietnam Shopping Products Scraper avatar

Vietnam Shopping Products Scraper

Pricing

from $0.00001 / actor start

Go to Apify Store
Vietnam Shopping Products Scraper

Vietnam Shopping Products Scraper

Scrape products by keyword from Tiki, Lazada, Chợ Tốt and Google Shopping. Returns URL, title, price, sale price, discount, image, brand, seller, rating and sold count. Supports language/price filters, sorting and URL dedup across sources.

Pricing

from $0.00001 / actor start

Rating

5.0

(1)

Developer

EMT Crawler

EMT Crawler

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

5 days ago

Last modified

Share

Actor: products-shopping

Apify actor cào sản phẩm shopping theo từ khóa từ nhiều nguồn. Dùng để dựng giao diện kiểu Google Shopping: mỗi sản phẩm có url, title, price, salePrice, image, merchant, rating...

Built với Crawlee + CheerioCrawler (HTTP, không render JS).

📘 Hướng dẫn & giải thích chi tiết (đầu vào/đầu ra, kiến trúc, publish, mở rộng, xử lý sự cố): docs/HUONG_DAN.md

Nguồn cào hiện có

keyCách lấyĐộ tin cậyGhi chú
tikiAPI JSON tiki.vn/api/v2/products⭐ CaoGiá/giá gốc/ảnh/rating/đã bán sạch, không cần proxy
lazadaAPI JSON lazada.vn/catalog/?ajax=true⭐ Caomods.listItems; nên bật proxy nếu bị chặn
chototAPI JSON gateway.chotot.com/v1/public/ad-listing⭐ CaoSàn rao vặt lớn (hàng mới + cũ); tin giá 0 tự bị lọc
bingBing Shopping HTML⚠ Thử nghiệmQua HTTP thường bị redirect/JS-shell → 0 kết quả; cần Playwright

Lọc giá rác: sản phẩm giá VND < 1.000 ₫ (listing bait, vd "₫121") bị loại tự động (isValidProduct trong normalize.js).

Vì sao Google/Bing/Shopee không có? Các trang này render bằng JavaScript hoặc chống bot mạnh nên không cào được bằng CheerioCrawler (HTTP thuần). Đã thử & xác nhận: Shopee chặn (error 90309999), Bing redirect, Sendo/Sàn khác trả challenge. Muốn cào Google Shopping cần chuyển sang PlaywrightCrawler — xem mục "Các hướng đi".

Output (mỗi item trong dataset)

{
"query": "váy",
"source": "tiki",
"position": 1,
"title": "Chân Váy Thời Trang Kiểu Đuôi Cá...",
"url": "https://tiki.vn/...-p278476178.html",
"price": 250000, // giá gốc (list price)
"salePrice": 139000, // giá khuyến mãi (null nếu không giảm)
"discountRate": 44, // % giảm (nguồn cấp hoặc suy ra từ price/salePrice)
"currency": "VND",
"image": "https://salt.tikicdn.com/.../x.png",
"images": ["https://salt.tikicdn.com/.../x.png"],
"brand": "MAYHOMES", // thương hiệu
"category": "Chân váy dài",// ngành hàng (Tiki có, Lazada để null)
"merchant": "MAYHOMES Official Store",
"rating": 5,
"reviews": 2,
"sold": 88, // số đã bán
"scrapedAt": "2026-06-30T..."
}

Quy ước price / salePrice khớp price_vnd / sale_price_vnd trong app daisan-search (src/lib/advertisedProductsClient.ts) — ghép vào UI không cần đổi tên field.

Chạy local

npm install
npm test # unit test parse giá + parser HTML (offline, không cần mạng)
apify run # đọc input từ storage/key_value_stores/default/INPUT.json
# hoặc:
node src/main.js

Kết quả ở storage/datasets/default/*.json.

Deploy

npm -g install apify-cli
apify login
apify push

Input

FieldKiểuMặc địnhÝ nghĩa
queriesstring[]["váy"]Từ khóa (bắt buộc)
sourcesstring[]["tiki","lazada"]Nguồn cào
maxItemsint0Tổng sản phẩm cả run (0 = tắt). Đặt 100 để lấy đúng 100
maxItemsPerQueryint40Giới hạn / (từ khóa × nguồn); >40 tự phân trang. Bỏ qua nếu đặt maxItems
sortByenumrelevancerelevance/newest/best_selling/price_asc/price_desc
minPriceint0Giá bán tối thiểu (VND), 0 = bỏ qua
maxPriceint0Giá bán tối đa (VND), 0 = bỏ qua
productLanguageenumviNgôn ngữ sản phẩm: any/vi/en
countrystringvnmã quốc gia (cc)
languagestringvimã ngôn ngữ
proxyConfigurationobject{useApifyProxy:false}proxy Apify

Xem input.json ở thư mục gốc làm ví dụ.

Tính năng

  • Lọc theo ngôn ngữ (productLanguage: any/vi/en, mặc định vi): vi giữ tên có dấu tiếng Việt (loại hàng xuyên biên giới tên Anh/Trung); en giữ tên tiếng Anh; any không lọc. Chữ CJK/Thái luôn bị loại ở vi/en.
  • Phân bổ đều theo nguồn: khi đặt maxItems, kết quả được chia đều giữa các nguồn bằng round-robin (xen kẽ tiki/lazada/chợ tốt); nguồn nào thiếu hàng thì tự bù từ nguồn khác cho đủ tổng.
  • Sắp xếp & lọc giá: sortBy (liên quan/mới nhất/bán chạy/giá tăng/giá giảm) — áp ở nguồn (Tiki/Lazada) + sort client-side cuối cùng đảm bảo đúng thứ tự. minPrice/maxPrice lọc theo khoảng giá.
  • Đa nguồn + đa từ khóa: chạy đồng thời (từ khóa × nguồn), gộp về một dataset.
  • Phân trang: maxItemsPerQuery > 40 tự kéo nhiều trang (Tiki/Lazada 40 item/trang, tối đa 200 = 5 trang).
  • Làm giàu dữ liệu: price, salePrice, discountRate, brand, category, merchant, rating, reviews, sold.
  • Khử trùng URL trên toàn run (chống trùng giữa các trang & nguồn).
  • Lọc giá rác (listing bait giá VND < 1.000 ₫).
  • Tự thử lại khi sàn chặn tạm thời (maxRequestRetries: 3).

Kiến trúc (dễ mở rộng)

src/
├── main.js # đọc input, fan-out (từ khóa × nguồn), chạy CheerioCrawler
├── sources.js # định nghĩa nguồn: cách build URL/request ← thêm nguồn mới ở đây
├── routes.js # router theo label: handler TIKI / LAZADA (JSON), BING (HTML)
├── mappers.js # map item thô từng sàn (Tiki, Lazada) -> item chuẩn (test offline)
├── parseHtml.js # parser HTML heuristic dùng chung (không bám class name)
└── normalize.js # parse giá VN/USD, rating, reviews; quy ước price/salePrice; lọc giá rác

Thêm 1 nguồn JSON mới (vd Shopee): (1) thêm entry vào SOURCES trong sources.js (build URL + label); (2) viết mapXxxItem trong mappers.js; (3) thêm router.addHandler('<LABEL>', ...) trong routes.js gọi mapper + isValidProduct. Nguồn HTML thì dùng lại parseHtmlProducts (như handler BING).


Các hướng đi để cào sản phẩm shopping

Hướng 1 — API JSON của sàn TMĐT (actor này: tiki, lazada, chotot)

  • Gọi thẳng endpoint search JSON của sàn.
  • Ưu: dữ liệu sạch, đúng VND, có sẵn giá gốc/giá KM/rating/người bán; không cần render JS; Tiki/Chợ Tốt không cần proxy, Lazada thỉnh thoảng cần.
  • Nhược: mỗi sàn một endpoint + một mapper riêng. Đã thử & KHÔNG dùng được qua HTTP: Shopee (error 90309999), Sendo (rỗng), Thế Giới Di Động/Điện Máy Xanh (trang challenge) → cần Playwright + cookie/bypass.

Hướng 2 — Parse HTML SERP shopping (actor này, nguồn bing — thử nghiệm)

  • CheerioCrawler tải HTML rồi parseHtml.js bóc card bằng heuristic (img → leo lên <a> → tìm giá).
  • Thực tế: Bing /shop qua HTTP thuần bị redirect sang JS-shell → 0 kết quả. Parser vẫn hữu ích khi cấp HTML đã render (vd từ Playwright) hoặc cho các trang shop server-render khác.

Hướng 3 — Google Shopping qua PlaywrightCrawler (cần chuyển template)

  • Giao diện udm=28 là JS-heavy → phải render bằng trình duyệt.
  • Cách làm: đổi dependency sang @crawlee/playwright + playwright, đổi base image Docker sang apify/actor-node-playwright-chrome, mở trang google.com/search?q=...&udm=28, cuộn lazy-load, rồi dùng lại logic heuristic của parseHtml.js (chuyển sang page.evaluate).
  • Ưu: đúng dữ liệu Google như ảnh demo. Nhược: chậm/tốn tài nguyên hơn, bắt buộc proxy RESIDENTIAL.

Hướng 4 — SERP API trả phí (SerpApi / Oxylabs / Bright Data)

  • Trả JSON Google Shopping sạch, không lo chống bot. Nhược: trả phí theo request + cần API key.
  • Chưa hiện thực trong actor này (có thể thêm sau nếu cần).

Khuyến nghị: dùng Hướng 1 (Tiki/Lazada/Chợ Tốt) làm nguồn chính miễn phí cho dữ liệu VN; cần Shopee/Google thì cân nhắc Hướng 3 (Playwright) hoặc Hướng 4 (SERP API).

Output đã chuẩn hóa sẵn. Trỏ edge function apify-run / apify-runner (trong repo daisan-search, supabase/functions/) tới actor này thay vì actor marketplace — các field (title, url, price, salePrice, image, currency) đã trùng tên nên hàm normalize() gần như không cần sửa.