Tuỳ biến Sitemap và RSS
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
- 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 đó.
- 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.
- Đọ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.
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():
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ỉ chourlvàlastmod(không có tiêu đề). Trộn hai loại trong cùngsourcesthì 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
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ĩa | Ví dụ |
|---|---|---|
tag | Tên thẻ HTML | {"tag": "h1"} |
class | Mộ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ác | Phả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ự:
"title_selector": {"tag": ["h1", "h2"], "class": ["article-title", "detail-title"]}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.
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:
<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:05hay2 giờ trướctheo 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 đó
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ệu | Nguyên nhân thường gặp | Cách chỉnh |
|---|---|---|
Bảng rỗng, df.attrs["failures"] có ROBOTS_DISALLOWED | Trang không mở đường dẫn này cho chương trình tự động | Dừng lại; không tìm cách vượt qua |
| Một cột để trống | Bộ chọn không khớp phần tử nào | Kiể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ước | Thê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 quan | Khung chọn quá rộng | Chọ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ó title | Ngà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_CONFIG | Cấu hình sai cấu trúc | Mỗ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ỏ:
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:
- Đọ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ệprobots.txtcủ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õ trongdf.attrs["failures"]. - Đ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. - 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 đó.