Vnstock Logo

Tuỳ biến Sitemap và RSS

Mở rộng

Mục lục

Ngoài các trang tin trong danh mục, bạn có thể tự thêm chuyên mục hay trang tin khác mà bạn quan tâm, nếu trang đó công bố nguồn cấp tin (RSS) hoặc sơ đồ trang và điều kiện sử dụng của trang cho phép.

Khi nào bạn cần tuỳ biến nguồn tin

  1. Theo dõi chuyên mục chuyên biệt: Thay vì đọc toàn bộ tin tức kinh doanh chung, bạn chỉ muốn nhận tin về "Bất động sản", "Thị trường hàng hoá" hoặc "Khởi nghiệp" từ kênh RSS riêng của chuyên mục đó.
  2. Thêm trang tin yêu thích ngoài danh mục: Trang tin có công bố nguồn cấp tin RSS hoặc sơ đồ trang XML Sitemap, bạn có thể đưa vào danh sách theo dõi phục vụ nghiên cứu cá nhân nếu điều kiện sử dụng của trang cho phép.
  3. Đọc nội dung bài viết cho nghiên cứu cá nhân: Thư viện không kèm sẵn cách đọc nội dung bài cho trang nào. Khi cần phân tích sâu (xử lý ngôn ngữ tự nhiên, đánh giá cảm xúc thị trường) ở trang mà điều kiện sử dụng cho phép, bạn tự dựng cấu hình từ một bài mẫu theo mục 3.
Áp dụng cho cấp Silver trở lên

Tính năng khai báo nguồn tự chọn qua tham số sources hoặc cấu hình riêng config dành riêng cho người dùng từ cấp Silver trở lên (Silver, Golden, Diamond). Người dùng thuộc cấp thấp hơn khi truyền các tham số này sẽ nhận thông báo lỗi NEWS_TIER_REQUIRED.


1. Dùng danh sách nguồn tự chọn (sources)

Bạn chỉ cần truyền danh sách các đường dẫn RSS feed hoặc XML Sitemap vào tham số sources của fetch_feeder() hoặc fetch_articles():

Python
import vnstock_news

# Theo dõi trực tiếp 2 chuyên mục chuyên sâu
custom_sources = [
    "https://tuoitre.vn/rss/kinh-doanh.rss",
    "https://vietstock.vn/761/kinh-te/vi-mo.rss"
]

df = vnstock_news.fetch_feeder(
    sources=custom_sources,
    within="12h",
    top_n=30
)

print(f"Tổng số bài viết nhận được: {len(df)}")

Cơ chế nhận diện định dạng chuẩn mở

Các trang web có thể phát hành nguồn cấp tin dưới các định dạng khác nhau (kênh RSS hoặc XML Sitemap). Bạn không cần bận tâm về việc cấu hình định dạng:

  • Thư viện đọc phần đầu của tệp để biết đó là RSS/Atom hay XML Sitemap, kể cả khi tên tệp gây nhầm.
  • Mỗi loại nguồn cho các cột riêng: RSS cho title, link, description, pubDate; sơ đồ trang chỉ cho url và lastmod (không có tiêu đề). Trộn hai loại trong cùng sources thì bảng có đủ các cột, dòng của loại nào thì cột của loại kia để trống.

2. Tự khai báo cấu hình bộ chọn (config)

Danh mục có sẵn trong thư viện chỉ kèm bộ chọn cho thông tin mô tả bài (tiêu đề, tóm tắt, thời gian, tác giả, chuyên mục, thẻ). Thế hệ 5 không kèm sẵn cách đọc nội dung bài cho bất kỳ trang tin nào: không mục nào trong danh mục có content_selector, nên fetch_articles(site_name=...) luôn để trống cột content. Đây là lựa chọn có chủ đích, vì nội dung bài viết thuộc về toà soạn.

Khi cần đọc thông tin từ một trang ngoài danh mục, hoặc cần nội dung bài cho nghiên cứu cá nhân ở trang mà điều kiện sử dụng cho phép, bạn truyền một từ điển cấu hình vào tham số config của fetch_articles().

Cấu trúc từ điển config

Python
import vnstock_news

site_profile = {
    # Nguồn lấy danh sách bài (khai một hoặc cả hai)
    "rss": {"urls": ["https://trangtin.example/rss/tin-moi.rss"]},
    "sitemap_url": "https://trangtin.example/sitemap.xml",

    # Bộ chọn cho từng trường của trang bài
    "config": {
        "title_selector": {"tag": "h1", "class": "article-title"},
        "short_desc_selector": {"tag": "p", "class": "article-sapo"},
        "publish_time_selector": {"tag": "span", "class": "article-date"},
        "author_selector": {"tag": "span", "class": "article-author"},
        "category_selector": {"tag": "a", "class": "article-category"},
        "tags_selector": {"tag": "div", "class": "article-tags"},
        "content_selector": {"tag": "div", "class": "article-body"},
    },
}

df = vnstock_news.fetch_articles(config=site_profile, top_n=5)

Khi đã có sẵn đường dẫn bài, bạn bỏ phần rss và sitemap_url, chỉ giữ khối "config", rồi truyền đường dẫn qua urls: fetch_articles(urls=[...], config={"config": {...}}).

Bộ chọn được viết thế nào

Mỗi bộ chọn là một từ điển mô tả phần tử HTML cần tìm. Thư viện lấy phần tử đầu tiên trên trang khớp đủ mọi điều kiện, rồi đọc chữ hiển thị bên trong nó.

Khoá trong bộ chọnÝ nghĩaVí dụ
tagTên thẻ HTML{"tag": "h1"}
classMột lớp CSS mà phần tử có (phần tử có nhiều lớp vẫn khớp){"tag": "div", "class": "article-body"}
Thuộc tính HTML khácPhải bằng đúng giá trị ghi{"tag": "span", "itemprop": "datePublished"}

Muốn dự phòng khi các chuyên mục dùng giao diện khác nhau, ghi danh sách giá trị cho một khoá. Thư viện thử lần lượt theo thứ tự:

Python
"title_selector": {"tag": ["h1", "h2"], "class": ["article-title", "detail-title"]}
Những cách viết không dùng được

Bộ chọn không phải cú pháp CSS hay XPath: chuỗi như "div.article-body > p" không được hiểu. Một trường chỉ nhận một từ điển, không nhận danh sách nhiều từ điển (sai cấu trúc sẽ báo INVALID_SITE_CONFIG). Thư viện đọc chữ hiển thị của phần tử, không đọc giá trị thuộc tính, nên thẻ <meta> hay thuộc tính datetime của thẻ <time> không cho ra kết quả; hãy chọn phần tử mà ngày giờ hiện ra thành chữ trên trang.


3. Tự dựng cấu hình đọc nội dung từ một bài mẫu

Cách nhanh nhất để có cấu hình đúng là bắt đầu từ một bài viết duy nhất trên trang tin bạn muốn theo dõi. Ví dụ dưới đây dùng tên miền minh hoạ trangtin.example; bạn thay bằng trang của mình.

Trước khi bắt đầu

Nội dung bài viết thuộc về toà soạn. Chỉ làm việc này với trang mà robots.txt và điều kiện sử dụng cho phép, chỉ dùng cho nghiên cứu cá nhân, và không đăng lại nội dung ở nơi khác. Thử với một bài, sau đó đọc số lượng nhỏ, đừng tải hàng loạt.

Bước 1: Mở một bài mẫu và xem mã HTML

Mở bài trong trình duyệt, ví dụ https://trangtin.example/kinh-te/bai-mau.html. Nhấp chuột phải vào tiêu đề, chọn Kiểm tra (Inspect) để xem phần tử HTML chứa nó. Lặp lại cho thời gian đăng, tên tác giả và phần thân bài.

Bước 2: Ghi lại phần tử chứa từng trường

Với mỗi trường, ghi tên thẻ và một lớp CSS đặc trưng. Ví dụ trang mẫu có cấu trúc:

HTML
<h1 class="article-title">Tiêu đề bài viết</h1>
<span class="article-date">Thứ Sáu, 10/10/2026, 08:05</span>
<span class="article-author">Tên tác giả</span>
<div class="article-body">
  <p>Đoạn mở đầu...</p>
  <p>Đoạn tiếp theo...</p>
</div>

Một vài mẹo khi chọn:

  • Thân bài: chọn khung bao trọn các đoạn văn của bài, không chọn từng thẻ <p>. Tránh khung quá rộng (cả trang) vì sẽ kéo theo menu, quảng cáo và bài liên quan.
  • Thời gian đăng: chọn phần tử có ngày giờ hiện thành chữ. Thư viện tự hiểu các dạng như Thứ Sáu, 10/10/2026, 08:05 hay 2 giờ trước theo giờ Việt Nam.
  • Lớp CSS: ưu tiên lớp có tên gợi nghĩa (article-body, detail-content) hơn lớp sinh tự động (css-1x2y3z), vì lớp sinh tự động hay đổi sau mỗi lần trang cập nhật giao diện.

Bước 3: Viết cấu hình và thử với đúng bài mẫu đó

Python
import vnstock_news

sample_url = "https://trangtin.example/kinh-te/bai-mau.html"

config = {
    "config": {
        "title_selector": {"tag": "h1", "class": "article-title"},
        "publish_time_selector": {"tag": "span", "class": "article-date"},
        "author_selector": {"tag": "span", "class": "article-author"},
        "content_selector": {"tag": "div", "class": "article-body"},
    }
}

df = vnstock_news.fetch_articles(urls=[sample_url], config=config)

row = df.iloc[0] if not df.empty else None
if row is None:
    print("Không đọc được trang:", df.attrs["failures"])
else:
    print("Tiêu đề :", row["title"])
    print("Thời gian:", row["publish_time"])
    print("Tác giả :", row["author"])
    print("Nội dung :", (row["content"] or "")[:500])

Bước 4: Đối chiếu và chỉnh lại

Dấu hiệuNguyên nhân thường gặpCách chỉnh
Bảng rỗng, df.attrs["failures"] có ROBOTS_DISALLOWEDTrang không mở đường dẫn này cho chương trình tự độngDừng lại; không tìm cách vượt qua
Một cột để trốngBộ chọn không khớp phần tử nàoKiểm lại tên thẻ và lớp CSS trong mã HTML của bài
title ra chữ khác tiêu đềTrên trang có phần tử cùng thẻ, cùng lớp đứng trướcThêm thuộc tính hoặc đổi sang lớp đặc trưng hơn
content lẫn menu, quảng cáo, bài liên quanKhung chọn quá rộngChọn khung hẹp hơn, sát phần thân bài
content chỉ có một đoạnĐang chọn một thẻ <p>Chọn khung bao các đoạn
publish_time trống dù có titleNgày giờ nằm trong thuộc tính, không hiện thành chữChọn phần tử có ngày giờ hiện trên trang
Lỗi INVALID_SITE_CONFIGCấu hình sai cấu trúcMỗi trường là một từ điển, đặt trong khoá "config"

Khi bài mẫu cho kết quả đúng, thử thêm hai, ba bài ở chuyên mục khác của cùng trang. Nếu giao diện khác nhau, thêm giá trị dự phòng bằng danh sách như ở mục 2.

Bước 5: Dùng cấu hình trong chương trình của bạn

Thêm nguồn cấp tin hoặc sơ đồ trang của trang đó vào cấu hình, giữ số bài nhỏ:

Python
config["rss"] = {"urls": ["https://trangtin.example/rss/kinh-te.rss"]}

df = vnstock_news.fetch_articles(config=config, top_n=5, within="1d")
print(df[["title", "publish_time", "url"]])

Cấu hình là của bạn, nằm trong mã của bạn. Khi trang đổi giao diện, cột nào trống thì quay lại bước 1 với một bài mới.


4. Quy chuẩn truy cập và tôn trọng website nguồn

Các cơ quan báo chí và website tin tức công bố nguồn cấp tin RSS và sơ đồ trang XML cho các trình đọc tin (Feed Readers) và người đọc. Truy cập được không có nghĩa là được dùng không giới hạn, nên thư viện giữ nhịp truy cập theo các nguyên tắc sau:

  1. Đọc và tôn trọng chỉ dẫn robots.txt: Trước khi tiếp cận một đường dẫn mới, thư viện tự động kiểm tra các chỉ dẫn công bố trong tệp robots.txt của website. Nếu một đường dẫn nào được đơn vị xuất bản chỉ định không tiếp nhận việc lập chỉ mục tự động, thư viện sẽ tôn trọng quy định này, không gửi yêu cầu và thông báo rõ trong df.attrs["failures"].
  2. Điều phối nhịp độ truy cập hợp lý: Thư viện duy trì khoảng cách yêu cầu vừa phải và tuân thủ thời gian giãn cách nếu website có yêu cầu (Crawl-delay ), tránh gây ảnh hưởng tới tài nguyên máy chủ của website nguồn.
  3. Phản hồi đúng chuẩn khi máy chủ bận (Mã 429): Nếu máy chủ nguồn phản hồi mã HTTP 429 (yêu cầu tạm giảm tần suất), thư viện sẽ ghi nhận trạng thái và tạm dừng gửi yêu cầu tới trang đó.