Cơ bảnHướng dẫnClaude

Tóm tắt trang web với Claude Haiku — Nhanh và rẻ

Điểm nổi bật

Nhấn để đến mục tương ứng

  1. 1Tận dụng Claude hiệu quả: requests: Fetch HTML từ URL BeautifulSoup: Parse và clean HTML Claude Haiku: Tóm tắt content nhanh, rẻ pip install — mẹo quan trọng là cung cấp đủ ngữ cảnh để AI trả về kết quả chính xác hơn 80% so với prompt chung chung.
  2. 2Thành thật mà nói: import requests from bs4 import BeautifulSoup import re def fetchwebpageurl: str -> str: """ Fetch HTML từ URL và. Phương pháp này hiệu quả trong hầu hết trường hợp, nhưng bạn cần điều chỉnh cho phù hợp ngữ cảnh riêng.
  3. 3Nội dung cốt lõi: summarystyle: - "brief": Tóm tắt 2-3 câu - "bullet": Các điểm chính dạng b. Nắm vững phần này sẽ giúp bạn áp dụng hiệu quả hơn 70% so với đọc lướt toàn bài.
  4. 4Công cụ AI sẽ thay đổi cách bạn làm việc: TOPICFILTERPROMPT = """Đọc tóm tắt tin tức sau và đánh giá mức độ liên quan đến chủ đề: "{topic}" Tóm tắt: {summary}. Điểm mấu chốt là biết cách đặt prompt đúng để nhận kết quả có thể sử dụng ngay.
  5. 5Một điều ít người đề cập: from datetime import datetime def generatedailydigestrssurls: list, topic: str = None -> str: """ Tạo daily digest. Hiểu rõ bối cảnh áp dụng sẽ quyết định 80% thành công khi triển khai.
Tóm tắt trang web với Claude Haiku — Nhanh và rẻ

Tóm tắt trang web tự động với Claude Haiku — fetch HTML, clean content, summarize trong vài giây với chi phí cực thấp.

Bạn cần đọc 50 bài báo mỗi ngày để theo dõi tin tức ngành? Hay cần extract thông tin từ hàng trăm trang web? Claude Haiku — model nhanh nhất và rẻ nhất của Anthropic — hoàn hảo cho tác vụ này. Chi phí chỉ khoảng $0.001 mỗi bài viết.

Tech Stack

  • requests: Fetch HTML từ URL
  • BeautifulSoup: Parse và clean HTML
  • Claude Haiku: Tóm tắt content (nhanh, rẻ)
pip install anthropic requests beautifulsoup4 lxml

Bước 1: Fetch và clean HTML

import requests
from bs4 import BeautifulSoup
import re

def fetch_webpage(url: str) -> str:
    """
    Fetch HTML từ URL và trả về clean text.
    """
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "vi-VN,vi;q=0.9,en;q=0.8",
    }

    try:
        response = requests.get(url, headers=headers, timeout=10)
        response.raise_for_status()
        response.encoding = response.apparent_encoding
        return response.text
    except requests.RequestException as e:
        raise ValueError(f"Không thể fetch URL: {e}")

def clean_html(html: str) -> str:
    """
    Extract text từ HTML, loại bỏ noise (ads, nav, footer).
    """
    soup = BeautifulSoup(html, "lxml")

    # Xóa các elements không cần thiết
    for tag in soup.find_all(["script", "style", "nav", "header", "footer",
                               "aside", "advertisement", "iframe"]):
        tag.decompose()

    # Cũng xóa theo class/id phổ biến của ads
    for tag in soup.find_all(class_=re.compile(r"ad|banner|sidebar|popup|cookie",
                                                re.IGNORECASE)):
        tag.decompose()

    # Thử tìm main content area
    main_content = (
        soup.find("article") or
        soup.find("main") or
        soup.find(class_=re.compile(r"content|article|post|entry", re.IGNORECASE)) or
        soup.find("body")
    )

    if main_content:
        text = main_content.get_text(separator="
", strip=True)
    else:
        text = soup.get_text(separator="
", strip=True)

    # Clean whitespace
    lines = [line.strip() for line in text.splitlines() if line.strip()]
    text = "
".join(lines)

    # Giới hạn độ dài (tránh vượt context window)
    max_chars = 50000  # Khoảng 12.5k tokens
    if len(text) > max_chars:
        text = text[:max_chars] + "

[Nội dung bị cắt bớt do quá dài...]"

    return text

# Test
html = fetch_webpage("https://vnexpress.net/")
content = clean_html(html)
print(f"Extracted {len(content)} characters")
print(content[:500])

Bước 2: Summarize với Claude Haiku

import anthropic

client = anthropic.Anthropic()

SUMMARIZE_SYSTEM_PROMPT = """Bạn là trợ lý tóm tắt nội dung web.
Tóm tắt ngắn gọn, súc tích, và chính xác bằng tiếng Việt.
Tập trung vào thông tin quan trọng nhất."""

def summarize_webpage(url: str, summary_style: str = "brief") -> dict:
    """
    Tóm tắt nội dung một trang web.

    summary_style:
    - "brief": Tóm tắt 2-3 câu
    - "bullet": Các điểm chính dạng bullet
    - "detailed": Tóm tắt chi tiết 200-300 từ
    - "tldr": Chỉ 1 câu
    """
    # Fetch content
    html = fetch_webpage(url)
    content = clean_html(html)

    prompts = {
        "brief": "Tóm tắt nội dung trang web này trong 2-3 câu ngắn gọn:",
        "bullet": "Liệt kê 5 điểm chính nhất từ trang web này:",
        "detailed": "Viết tóm tắt chi tiết (200-300 từ) về nội dung trang web này:",
        "tldr": "Tóm tắt toàn bộ nội dung trong ĐÚNG 1 câu:",
    }

    prompt = prompts.get(summary_style, prompts["brief"])

    response = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=500,
        system=SUMMARIZE_SYSTEM_PROMPT,
        messages=[{
            "role": "user",
            "content": f"{prompt}

Nội dung:
{content}"
        }],
        temperature=0.3,
    )

    return {
        "url": url,
        "style": summary_style,
        "summary": response.content[0].text,
        "content_length": len(content),
        "tokens_used": response.usage.input_tokens + response.usage.output_tokens,
    }

# Test
result = summarize_webpage("https://techcrunch.com/", "bullet")
print(f"URL: {result['url']}")
print(f"Tokens used: {result['tokens_used']}")
print(f"
Tóm tắt:
{result['summary']}")

Batch summarizer — Xử lý nhiều URLs

from concurrent.futures import ThreadPoolExecutor, as_completed
import time

def batch_summarize(urls: list, style: str = "brief", max_workers: int = 5) -> list:
    """Tóm tắt nhiều URLs song song."""
    results = []
    errors = []

    def process_url(url):
        try:
            time.sleep(0.5)  # Rate limiting nhẹ
            return summarize_webpage(url, style)
        except Exception as e:
            return {"url": url, "error": str(e), "summary": None}

    print(f"Đang tóm tắt {len(urls)} URLs với {max_workers} workers...")

    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        future_to_url = {executor.submit(process_url, url): url for url in urls}

        for future in as_completed(future_to_url):
            result = future.result()
            if result.get("error"):
                errors.append(result)
                print(f"  ERROR: {result['url'][:50]}... - {result['error'][:50]}")
            else:
                results.append(result)
                print(f"  OK: {result['url'][:50]}... ({result['tokens_used']} tokens)")

    print(f"
Hoàn thành: {len(results)}/{len(urls)} thành công")
    return results, errors

# News aggregator ví dụ
tech_news_urls = [
    "https://techcrunch.com/",
    "https://theverge.com/",
    "https://wired.com/",
    "https://arstechnica.com/",
]

results, errors = batch_summarize(tech_news_urls, style="bullet")

for r in results:
    print(f"
=== {r['url']} ===")
    print(r["summary"])

News Monitor với topic filtering

TOPIC_FILTER_PROMPT = """Đọc tóm tắt tin tức sau và đánh giá mức độ liên quan đến chủ đề: "{topic}"

Tóm tắt: {summary}

Trả về:
- relevance_score: 0-10 (10 = rất liên quan)
- is_relevant: true/false (relevant nếu score >= 6)
- reason: lý do ngắn gọn

Chỉ trả về JSON."""

import json

def filter_by_topic(summaries: list, topic: str) -> list:
    """Lọc các bài viết theo chủ đề."""
    relevant = []

    for item in summaries:
        if not item.get("summary"):
            continue

        prompt = TOPIC_FILTER_PROMPT.format(
            topic=topic,
            summary=item["summary"]
        )

        response = client.messages.create(
            model="claude-haiku-4-5",
            max_tokens=150,
            messages=[
                {"role": "user", "content": prompt},
                {"role": "assistant", "content": "{"}
            ],
            temperature=0.0,
        )

        try:
            data = json.loads("{" + response.content[0].text)
            if data.get("is_relevant", False):
                item["relevance_score"] = data.get("relevance_score", 0)
                item["relevance_reason"] = data.get("reason", "")
                relevant.append(item)
        except json.JSONDecodeError:
            pass

    # Sắp xếp theo relevance
    relevant.sort(key=lambda x: x.get("relevance_score", 0), reverse=True)
    return relevant

# Lọc bài về AI
ai_articles = filter_by_topic(results, "artificial intelligence và machine learning")
print(f"Tìm thấy {len(ai_articles)} bài liên quan đến AI")
for art in ai_articles:
    print(f"
[{art['relevance_score']}/10] {art['url']}")
    print(f"Reason: {art['relevance_reason']}")

Ứng dụng thực tế: Daily Digest

from datetime import datetime

def generate_daily_digest(rss_urls: list, topic: str = None) -> str:
    """
    Tạo daily digest từ danh sách URLs.
    """
    print(f"Generating daily digest for {len(rss_urls)} sources...")

    # Tóm tắt tất cả
    summaries, _ = batch_summarize(rss_urls, style="bullet")

    # Filter theo topic nếu có
    if topic:
        summaries = filter_by_topic(summaries, topic)

    # Tạo digest
    today = datetime.now().strftime("%d/%m/%Y")
    digest = f"# Daily Digest - {today}

"

    if topic:
        digest += f"**Chủ đề:** {topic}

"

    digest += f"**Tổng cộng:** {len(summaries)} nguồn

---

"

    for i, item in enumerate(summaries, 1):
        digest += f"## {i}. [{item['url']}]({item['url']})

"
        digest += f"{item['summary']}

"
        if item.get("relevance_score"):
            digest += f"*Relevance: {item['relevance_score']}/10*

"
        digest += "---

"

    # Tóm tắt tổng thể
    all_summaries = "

".join([s["summary"] for s in summaries])
    overall_response = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=300,
        messages=[{
            "role": "user",
            "content": f"Từ các tóm tắt tin tức sau, viết 3 xu hướng chính nhất hôm nay:

{all_summaries[:3000]}"
        }],
    )

    digest = "## Xu hướng hôm nay

" + overall_response.content[0].text + "

---

" + digest

    return digest

# Tạo digest
digest = generate_daily_digest(
    rss_urls=tech_news_urls,
    topic="AI và automation"
)

# Lưu thành file
with open(f"digest_{datetime.now().strftime('%Y%m%d')}.md", "w", encoding="utf-8") as f:
    f.write(digest)
print(f"Digest saved!")

Chi phí ước tính

Quy mô Tokens/bài Chi phí/bài (Haiku) Chi phí 1000 bài
Tin ngắn (~500 chữ) ~800 $0.0002 $0.20
Bài dài (~2000 chữ) ~3000 $0.0008 $0.80
Bài rất dài (~5000 chữ) ~7000 $0.0018 $1.80

Claude Haiku là lựa chọn tối ưu cho web summarization — đủ thông minh để tóm tắt tốt, đủ nhanh để batch nhiều URLs, và đủ rẻ để chạy production scale. Kết hợp với Batch Processing API để tối ưu hóa throughput thêm nữa.

Còn thắc mắc về bài này?Claude Assistant đã nắm nội dung bài — hỏi trực tiếp hoặc chọn nhanh:

Bài viết có hữu ích không?

Bản quyền thuộc về tác giả. Vui lòng dẫn nguồn khi chia sẻ.

← Bài trước
CLAUDE.md Masterclass — Tối ưu workspace cho Claude Code
Bài sau →
Agentic Coding — Phần 5: Ứng dụng sáng tạo, tương lai và TDD workflow

Bình luận (0)

Khách
Bạn cần để bình luận