Bối cảnh: Cơn ác mộng bảo trì selector
Bạn vừa viết xong crawler bóc tách 10.000 sản phẩm e-commerce bằng BeautifulSoup hoặc Selenium. Sáng hôm sau, toàn bộ pipeline dừng hoạt động. Lý do rất quen thuộc: đội frontend của sàn vừa build lại giao diện, đổi class từ class="product-price" thành chuỗi hash ngẫu nhiên như class="_2rK9a".
Việc rà soát và cập nhật lại XPath hay CSS selector thủ công ngốn từ 30% đến 50% thời gian bảo trì crawler định kỳ. Đây chính là điểm yếu cố hữu của phương pháp bóc tách dữ liệu truyền thống.
ScrapeGraphAI giải quyết triệt để vấn đề này. Thay vì dựa vào DOM tree cố định, thư viện tận dụng đồ thị xử lý (Graph pipeline) và các mô hình ngôn ngữ lớn (LLM). LLM hiểu ngữ cảnh trang web tương tự mắt người. Bạn chỉ cần nạp URL cùng câu prompt mô tả dữ liệu cần lấy. ScrapeGraphAI sẽ tự phân tích trang và trả về JSON chuẩn xác.
Cài đặt môi trường
ScrapeGraphAI yêu cầu Python từ bản 3.10 trở lên. Khuyến nghị chạy trong virtual environment để tránh xung đột thư viện:
# Khởi tạo và kích hoạt virtualenv
python3 -m venv venv
source venv/bin/activate
# Cài đặt ScrapeGraphAI và Playwright để render JS động
pip install scrapegraphai playwright
# Tải binary trình duyệt
playwright install
Thư viện tích hợp sẵn nhiều LLM backend: OpenAI, Google Gemini, Groq, Azure OpenAI hoặc các model local chạy qua Ollama.
Cấu hình Pipeline Graph thực tế
Trung tâm của ScrapeGraphAI là các pipeline graph dựng sẵn. Hai class phổ biến nhất gồm SmartScraperGraph (bóc tách đơn trang) và SearchGraph (kết hợp search engine).
1. Bóc tách dữ liệu với SmartScraperGraph và GPT-4o-mini
Ví dụ sau trích xuất danh sách bài viết từ trang tin công nghệ với chi phí chỉ khoảng $0.002 cho mỗi lượt request:
import json
import os
from scrapegraphai.graphs import SmartScraperGraph
graph_config = {
"llm": {
"api_key": os.getenv("OPENAI_API_KEY"),
"model": "openai/gpt-4o-mini",
"temperature": 0,
},
"headless": True,
"verbose": False,
}
prompt = """
Trích xuất danh sách các bài viết trên trang gồm:
- title: Tiêu đề bài viết (string)
- author: Tên tác giả (string, null nếu không có)
- points: Số điểm upvote (integer)
- comments_count: Số lượt bình luận (integer)
"""
smart_scraper = SmartScraperGraph(
prompt=prompt,
source="https://news.ycombinator.com",
config=graph_config
)
result = smart_scraper.run()
print(json.dumps(result, indent=2, ensure_ascii=False))
2. Chạy Local LLM với Ollama (Bảo mật tuyệt đối, 0đ chi phí API)
Nếu bạn cần crawl dữ liệu nội bộ hoặc quy mô hàng trăm nghìn trang mỗi ngày, hãy trỏ sang cụm Ollama local:
from scrapegraphai.graphs import SmartScraperGraph
local_config = {
"llm": {
"model": "ollama/qwen2.5:7b",
"base_url": "http://localhost:11434",
"temperature": 0,
},
"embeddings": {
"model": "ollama/nomic-embed-text",
"base_url": "http://localhost:11434",
},
"headless": True
}
scraper = SmartScraperGraph(
prompt="Lấy tên sản phẩm, giá gốc và giá khuyến mãi",
source="https://example-shop.com/flash-sale",
config=local_config
)
data = scraper.run()
3. Tối ưu Token và Giảm chi phí
HTML thô của trang thương mại điện tử thường nặng từ 2MB đến 5MB (chứa hàng nghìn tag SVG, CSS inline và script rác). Đẩy toàn bộ HTML này vào LLM sẽ rất tốn token và tăng latency.
ScrapeGraphAI tự động parse và nén HTML trước khi gửi vào LLM. Ngoài ra, bạn nên giới hạn max_tokens và tinh chỉnh chunk_size trong config nếu trang có cấu trúc DOM quá lớn.
Triển khai Production & Monitoring
Khi đóng gói scraper vào Celery worker hay Kubernetes CronJob, bạn cần xử lý chặt chẽ ngoại lệ và theo dõi định mức token.
1. Thiết kế cơ chế Retry và Fallback
Tránh để lỗi mạng hay rate-limit 429 làm sập cả batch job. Hãy bọc logic thực thi trong hàm retry:
import logging
import time
from scrapegraphai.graphs import SmartScraperGraph
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
def fetch_with_retry(url: str, prompt: str, config: dict, max_retries: int = 3, backoff_factor: int = 2):
for attempt in range(1, max_retries + 1):
try:
logger.info(f"Đang crawl: {url} (Lần {attempt}/{max_retries})")
scraper = SmartScraperGraph(prompt=prompt, source=url, config=config)
output = scraper.run()
if output:
return output
except Exception as err:
logger.warning(f"Lỗi lần {attempt}: {err}")
if attempt == max_retries:
logger.error(f"Thất bại toàn bộ sau {max_retries} lần thử: {url}")
raise
time.sleep(backoff_factor ** attempt)
return None
2. Theo dõi Token Usage
Hàm get_execution_info() cung cấp chi tiết số token input/output và độ trễ của từng node. Bạn nên đẩy metric này về Prometheus hoặc Grafana để kiểm soát ngân sách API theo thời gian thực:
execution_info = smart_scraper.get_execution_info()
logger.info(f"Total tokens used: {execution_info.get('total_tokens', 0)}")
logger.info(f"Execution time: {execution_info.get('execution_time', 0):.2f}s")
3. Ba lưu ý cốt lõi khi vận hành
- Vượt Anti-bot: Khi crawl các trang bật Cloudflare, hãy cấu hình Proxy Pool xoay vòng qua Playwright config thay vì gửi HTTP request trần.
- Prompt có cấu trúc: Luôn đặt tên key JSON bằng tiếng Anh trong prompt (ví dụ
price,sku,stock_status) để model trả về output nhất quán, tránh lỗi format ở backend. - Kiến trúc Hybrid: Với 90% trang tĩnh có cấu trúc ít đổi, hãy dùng parser nhẹ (Scrapy, Selectolax) để đạt tốc độ 100 req/s. Chỉ kích hoạt ScrapeGraphAI làm tầng fallback khi parser truyền thống trả về dữ liệu rỗng.

