Vietnam Shopping Products Scraper
Pricing
from $0.00001 / actor start
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
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
5 days ago
Last modified
Categories
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ó
| key | Cách lấy | Độ tin cậy | Ghi chú |
|---|---|---|---|
tiki | API JSON tiki.vn/api/v2/products | ⭐ Cao | Giá/giá gốc/ảnh/rating/đã bán sạch, không cần proxy |
lazada | API JSON lazada.vn/catalog/?ajax=true | ⭐ Cao | mods.listItems; nên bật proxy nếu bị chặn |
chotot | API JSON gateway.chotot.com/v1/public/ad-listing | ⭐ Cao | Sàn rao vặt lớn (hàng mới + cũ); tin giá 0 tự bị lọc |
bing | Bing Shopping HTML | ⚠ Thử nghiệm | Qua 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 (
isValidProducttrongnormalize.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/salePricekhớpprice_vnd/sale_price_vndtrong app daisan-search (src/lib/advertisedProductsClient.ts) — ghép vào UI không cần đổi tên field.
Chạy local
npm installnpm 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-cliapify loginapify push
Input
| Field | Kiểu | Mặc định | Ý nghĩa |
|---|---|---|---|
queries | string[] | ["váy"] | Từ khóa (bắt buộc) |
sources | string[] | ["tiki","lazada"] | Nguồn cào |
maxItems | int | 0 | Tổng sản phẩm cả run (0 = tắt). Đặt 100 để lấy đúng 100 |
maxItemsPerQuery | int | 40 | Giới hạn / (từ khóa × nguồn); >40 tự phân trang. Bỏ qua nếu đặt maxItems |
sortBy | enum | relevance | relevance/newest/best_selling/price_asc/price_desc |
minPrice | int | 0 | Giá bán tối thiểu (VND), 0 = bỏ qua |
maxPrice | int | 0 | Giá bán tối đa (VND), 0 = bỏ qua |
productLanguage | enum | vi | Ngôn ngữ sản phẩm: any/vi/en |
country | string | vn | mã quốc gia (cc) |
language | string | vi | mã ngôn ngữ |
proxyConfiguration | object | {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 địnhvi):vigiữ tên có dấu tiếng Việt (loại hàng xuyên biên giới tên Anh/Trung);engiữ tên tiếng Anh;anykhô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/maxPricelọ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.jsbóc card bằng heuristic (img → leo lên<a>→ tìm giá). - Thực tế: Bing
/shopqua 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=28là 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 sangapify/actor-node-playwright-chrome, mở tranggoogle.com/search?q=...&udm=28, cuộn lazy-load, rồi dùng lại logic heuristic củaparseHtml.js(chuyển sangpage.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).
Tích hợp với app daisan-search
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.