Thu thập dữ liệu
Yozh Crawler thu thập dữ liệu trên một trang web bắt đầu từ một URL hạt giống duy nhất và truyền trực tiếp mọi trang được phát hiện qua SSE. Nó đảm nhận toàn bộ quá trình khám phá — mở rộng phạm vi, loại trừ trùng lặp, xác định phạm vi, trích xuất liên kết, thử lại và tuân thủ các quy tắc lịch sự — trong khi việc truy xuất từng trang được ủy quyền cho Yozh Scraper qua HTTP. Chỉ có duy nhất một bộ công cụ Playwright cần vận hành, và mọi tính năng của trình trích xuất (proxy, chế độ ẩn danh, phiên làm việc, quy tắc trích xuất) cũng được áp dụng cho các trang web đã thu thập.
- Điều kiện phạm vi —
same-domain/subdomains/all/regex, với các mẫu bao gồm và loại trừ cùng các giới hạnmax_depth/max_pagesgiới hạn cứng. - Loại bỏ trùng lặp dựa trên dấu vân tay — Các URL được chuẩn hóa rồi mã hóa băm (SHA1), do đó các truy vấn được sắp xếp lại và các biến thể có dấu gạch chéo ở cuối sẽ được gộp lại thành một lượt truy cập.
- Cơ chế luân phiên theo từng miền — một máy chủ chậm hoặc có dung lượng lớn sẽ không thể làm cạn kiệt nguồn công nhân của các máy chủ khác.
- Bộ giới hạn tốc độ thích ứng — một thùng token toàn cục cho từng miền (có độ dao động) được chia sẻ giữa các tác vụ; một
429giảm một nửa RPS trong khoảng thời gian làm mát. - Tình trạng phiên làm việc — Hệ thống chấm điểm theo phong cách Crawlee:
401/403/429khi phiên làm việc kết thúc, các lỗi sẽ làm tăng điểm số của phiên, còn thành công sẽ làm giảm điểm số; luân chuyển phiên khi điểm số ≥ 3 hoặc sau 50 lần sử dụng. - Phát trực tuyến SSE — mỗi tác vụ đều phát ra
stats,page,page_error, và các sự kiệndone/cancelled. Hãy xử lý các kết quả ngay khi chúng xuất hiện.
:8000 và trình thu thập dữ liệu trên :8001.Bắt đầu nhanh
Trình thu thập dữ liệu được nối dây vào gốc docker-compose.yml và chạy song song với trình trích xuất:
docker compose up --build # scraper → http://localhost:8000 # crawler → http://localhost:8001
Hoặc chạy nó trên máy cục bộ mà không cần Docker — chỉ SCRAPER_URL vào một trình thu thập dữ liệu đang chạy:
cd yozh-crawler pip install -r requirements.txt cp .env.example .env # edit SCRAPER_URL if needed python -m uvicorn src.main:app --reload --port 8001
Cách sử dụng cơ bản
Gửi yêu cầu thu thập dữ liệu kèm theo seed_url và một scope. Lời gọi này sẽ trả về một job_id ngay lập tức; sau đó, quá trình thu thập dữ liệu sẽ chạy ở chế độ nền trên các tác vụ công việc.
curl -X POST http://localhost:8001/api/v1/crawl
-H "Content-Type: application/json"
-d '{
"seed_url": "https://example.com",
"scope": {"mode": "same-domain", "max_depth": 2, "max_pages": 50,
"per_domain_rps": 1.0, "per_domain_concurrency": 1},
"scrape_options": {"proxy_type": "none"},
"enable_scraping": false
}'
Kết quả trả về chỉ là mã công việc:
{ "job_id": "crawl_abc123" }
Từ đây, bạn có thể phát trực tiếp các sự kiện hoặc truy vấn công việc để lấy bản ghi đầy đủ.
Khám phá so với khai thác — nút enable_scraping chuyển đổi
Cùng một công cụ thu thập dữ liệu hoạt động theo cả hai hướng. Một biến boolean dùng để lựa chọn giữa chế độ khám phá tiết kiệm tài nguyên và chế độ thu thập dữ liệu toàn diện — và mỗi chế độ sử dụng cấu hình proxy riêng, do đó không xảy ra hiện tượng ảnh hưởng lẫn nhau.
Bản đồ khám phá
Một lần quét nhẹ. Công cụ thu thập dữ liệu vẫn hiển thị từng trang (để phát hiện các liên kết được tạo bằng JavaScript), nhưng trình thu thập dữ liệu chỉ giữ lại phần khung cơ bản — rất lý tưởng cho sơ đồ trang web, kiểm tra liên kết và phát hiện sự thay đổi.
- Giữ
url·parent_url·depth·status·took_ms - Chèn mã HTML thô, ảnh chụp màn hình và dữ liệu đã trích xuất
- Sử dụng loại rẻ hơn
crawl_proxy - Tải trọng nhỏ nhất, tốc độ di chuyển chậm nhất
Thu thập toàn bộ
Mỗi trang đã truy cập đều được lưu lại kèm theo ScrapeResponse — mã HTML thô, ảnh chụp màn hình (tùy chọn) và bất kỳ trường dữ liệu nào từ quy tắc trích xuất của bạn. Thu thập và cấu trúc dữ liệu chỉ trong một lần xử lý.
- Giữ nguyên toàn bộ
ScrapeResponsetrên mỗi trang -
raw_html·screenshot· đã trích xuấtdata - Công dụng
scrape_options.proxy_* - Chuyển
extractcác quy tắc để thu được JSON sạch
crawl_proxy chỉ được sử dụng khi enable_scraping=false; scrape_options.proxy_* được sử dụng khi true. Nếu crawl_proxy là null, thì scrape_options proxy sẽ được sử dụng bất kể chế độ nào.Phạm vi thu thập dữ liệu
Phạm vi xác định giới hạn của quá trình thu thập dữ liệu: nơi mà quá trình này được phép truy cập, và mức độ tác động tối đa được phép đối với từng máy chủ. Đây là scope đối tượng trong yêu cầu.
| Trường | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
mode | same-domain · subdomains · all · regex | same-domain | Những liên kết nào nằm trong phạm vi. regex phù hợp với include_patterns. |
include_patterns | string[] | [] | Các mẫu biểu thức chính quy (Regex) mà một URL phải phù hợp để được đưa vào hàng đợi (được sử dụng bởi regex chế độ / như một danh sách cho phép). |
exclude_patterns | string[] | [] | Các mẫu biểu thức chính quy (Regex) loại bỏ một URL ngay cả khi URL đó nằm trong phạm vi áp dụng. |
max_depth | int | 3 | Độ sâu liên kết tối đa tính từ nút gốc (nút gốc có độ sâu là 0). |
max_pages | int | 500 | Giới hạn tối đa về số trang được truy cập trước khi quá trình thu thập dữ liệu kết thúc. |
per_domain_rps | float | 1.0 | Tốc độ nạp lại “thùng token” cho mỗi miền (yêu cầu/giây). |
per_domain_concurrency | int | 1 | Số lượng yêu cầu tối đa trong một lần truy cập đối với một tên miền duy nhất. |
subdomains” đơn giản. Phương pháp này sử dụng hai nhãn cuối cùng làm miền có thể đăng ký, do đó nó sẽ khớp quá mức với các máy chủ trong Danh sách hậu tố công khai (Public Suffix List) như github.io hoặc co.uk. Nên ưu tiên same-domain hoặc regex cho những trường hợp đó.Kết quả phát trực tuyến (SSE)
Mỗi tác vụ đều cung cấp một luồng sự kiện do máy chủ gửi (Server-Sent Events). Hãy đọc luồng này để thực hiện các thao tác trên các trang ngay khi chúng được phát hiện, thay vì phải chờ quá trình thu thập dữ liệu hoàn tất.
curl -N http://localhost:8001/api/v1/crawl/crawl_abc123/events
Dòng dữ liệu phát ra năm loại sự kiện:
| Sự kiện | Khi nào |
|---|---|
stats | Bản tóm tắt tiến độ định kỳ (đã truy cập / đang chờ xử lý / thất bại / bỏ qua do trùng lặp / nằm ngoài phạm vi / thử lại). |
page | Mỗi URL đã truy cập có một mục. Chứa đầy đủ ScrapeResponse trong chế độ thu thập, chỉ lưu trữ siêu dữ liệu tối thiểu trong chế độ khám phá. |
page_error | Một URL đã thất bại sau khi đã thử lại tất cả các lần. |
done | Terminal — quá trình quét đã hoàn tất bình thường. |
cancelled | Terminal — quá trình thu thập dữ liệu đã bị hủy. |
Một page sự kiện trong chế độ khám phá trông như sau:
{
"event": "page",
"url": "https://example.com/docs/intro",
"parent_url": "https://example.com/docs",
"depth": 2,
"status_code": 200,
"took_ms": 812,
"scrape_response": null
}
Tình trạng và kết quả
Bạn thích phương thức thăm dò hơn? Bản ghi công việc có thể được truy vấn bất cứ lúc nào — kể cả trong quá trình thu thập dữ liệu, với các trang đã được phát hiện cho đến thời điểm đó. /results là một tên gọi khác của điểm cuối công việc, được giữ lại để đảm bảo tính đối xứng với trình thu thập dữ liệu.
curl http://localhost:8001/api/v1/crawl/crawl_abc123 curl http://localhost:8001/api/v1/crawl/crawl_abc123/results
{
"job_id": "crawl_abc123",
"status": "running",
"stats": {
"visited": 47, "queued": 12, "failed": 0,
"dedup_skipped": 9, "out_of_scope": 31, "retries_total": 2
},
"pages": [
{ "url": "https://example.com/", "parent_url": null,
"depth": 0, "status_code": 200, "took_ms": 640 }
]
}
status di chuyển qua queued → running → done (hoặc failed / cancelled).Hủy quá trình thu thập dữ liệu
Dừng một tác vụ đang chạy bằng lệnh DELETE. Hủy nhẹ là tùy chọn mặc định và là lựa chọn an toàn.
# soft — stop scheduling, let in-flight requests drain curl -X DELETE "http://localhost:8001/api/v1/crawl/crawl_abc123?hard=false" # hard — abort in-flight asyncio tasks immediately curl -X DELETE "http://localhost:8001/api/v1/crawl/crawl_abc123?hard=true"
?hard=true sẽ hủy yêu cầu đang được xử lý của trình thu thập dữ liệu, nhưng trình thu thập dữ liệu không có cách nào biết được điều đó — quá trình hiển thị trang của nó vẫn hoàn tất bình thường. Nên ưu tiên hủy mềm trừ khi bạn bắt buộc phải dừng ngay lập tức.MCP
fastapi-mcp được triển khai tại /mcp dưới dạng một điểm cuối HTTP có thể phát trực tuyến. Chỉ cần di chuột hoặc đặt con trỏ vào đó, các công cụ sẽ tự động xuất hiện:
healthcreate_crawlget_crawlget_crawl_resultscancel_crawl
"open-crawler": {
"type": "http",
"url": "http://localhost:8001/mcp"
}
stream_crawl_events được loại trừ một cách có chủ đích khỏi MCP — các phản hồi truyền phát không phù hợp với công cụ yêu cầu/phản hồi.Tài liệu tham khảo về cấu hình
Yêu cầu — CrawlRequest
| Trường | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
seed_url | chuỗi (URL) | bắt buộc | Địa chỉ URL duy nhất mà quá trình thu thập dữ liệu bắt đầu từ đó. |
scope | CrawlScope | defaults | Phạm vi và tính lịch sự — xem Phạm vi Crawl. |
scrape_options | ScrapeOptions | defaults | Được chuyển tiếp nguyên văn đến công cụ thu thập dữ liệu theo từng trang (url được chèn vào). |
crawl_proxy | ScrapeOptions · null | null | Proxy giá rẻ được sử dụng ở chế độ khám phá. Chỉ proxy_type / proxy_pool_id / proxy_geo được đọc. |
enable_scraping | bool | false | Hãy giữ nguyên ScrapeResponse trên mỗi trang (true) hoặc chỉ siêu dữ liệu khám phá (false). |
Mỗi trang — ScrapeOptions (đã chọn)
| Trường | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
proxy_type | none · mobile · res_static · res_rotating · dc_static · … | none | Nhóm máy chủ proxy mà các yêu cầu truy xuất trang đi qua. |
device | desktop · mobile | desktop | Khung xem / Hồ sơ trình duyệt. |
render | bool | true | Hiển thị bằng trình duyệt (cần thiết cho các liên kết được tạo bằng JavaScript). |
stealth | bool | true | Áp dụng các biện pháp tăng cường bảo mật chống phát hiện. |
wait_until | domcontentloaded · networkidle | domcontentloaded | Khi trang được coi là đã sẵn sàng. |
screenshot | bool | false | Chụp ảnh màn hình (chế độ thu thập). |
extract | ExtractRule · null | null | Quy tắc trường CSS/XPath → có cấu trúc data theo từng trang. |
session_id | chuỗi · null | null | Tái sử dụng phiên thu thập dữ liệu đã được xác thực — xem phần “Thu thập dữ liệu đã được xác thực”. |
Biến môi trường
| Biến | Mặc định | Ghi chú |
|---|---|---|
SCRAPER_URL | http://web-scraper:8000 | Trình thu thập dữ liệu đầu vào (sử dụng tên dịch vụ Docker trong mạng Compose). |
WORKERS | 2 | Số lượng tác vụ thu thập dữ liệu song song. |
QUEUE_MAXSIZE | 200 | Độ sâu hàng đợi các công việc đang chờ xử lý. |
JOB_TIMEOUT_MS | 3_600_000 | Giới hạn thời gian thực cho một tác vụ thu thập dữ liệu. |
SCRAPER_JOB_TIMEOUT_MS | 120_000 | Thời gian chờ tối đa cho mỗi yêu cầu của trình thu thập dữ liệu theo trang. |
MAX_RETRIES | 3 | Số lần thử lại cho mỗi yêu cầu khi xảy ra lỗi tạm thời. |
RETRY_HTTP_CODES | [408,429,500,502,503,504] | Các mã trạng thái kích hoạt việc thử lại. |
RETRY_BACKOFF_MAX | 30.0 | Giới hạn trên của thời gian lùi theo hàm mũ (giây). |
SESSION_MAX_ERROR_SCORE | 3.0 | Ngưỡng kết thúc phiên. |
SESSION_MAX_USAGE | 50 | Xoay vòng phiên làm việc sau N lần sử dụng. |
SESSION_BLOCKED_CODES | [401,403,429] | Các đoạn mã giúp kết thúc phiên làm việc ngay lập tức. |
Tham khảo API
| Phương thức | Đường dẫn | Mục đích |
|---|---|---|
| POST | /api/v1/crawl | Tạo một công việc. Trả về {"job_id":"…"}. |
| GET | /api/v1/crawl/{id} | Bản ghi công việc — trạng thái, số liệu thống kê, số trang đã hoàn thành. |
| GET | /api/v1/crawl/{id}/results | Tên gọi khác của bản ghi công việc. |
| GET | /api/v1/crawl/{id}/events | Chuyên ngành SSE (stats/page/page_error/done/cancelled). |
| DELETE | /api/v1/crawl/{id}?hard=bool | Hủy công việc (hủy tạm thời hoặc hủy vĩnh viễn). |
| GET | /api/v1/health | Sức khỏe + khả năng tiếp cận của trình trích xuất. |
Các chi tiết quan trọng
robots.txt không được tham khảo. Trình thu thập dữ liệu sẽ truy cập mọi URL nằm trong phạm vi, bất kể /robots.txt. Bạn có trách nhiệm tuân thủ các quy tắc robots và điều khoản của trang web đối với các mục tiêu mà bạn không sở hữu — hãy sử dụng exclude_patterns và giới hạn tốc độ để duy trì sự lịch sự.POST /sessions + POST /sessions/{id}/login), sau đó truyền scrape_options.session_id. Trình thu thập dữ liệu truyền đi và nhận lại cookie cùng trạng thái lưu trữ cho mỗi yêu cầu, do đó mọi trang được thu thập đều nhận được trạng thái đã xác thực.