Chia sẻ code html đọc rss full text cho website

admin

Administrator
Thành viên BQT
👉 Tuy nhiên, nếu feed chặn CORS thì trình duyệt sẽ báo lỗi Failed to fetch. Đây không phải do code sai, mà do server RSS không cho phép gọi trực tiếp từ browser.

Để đọc full bài viết, bạn có 2 cách:

  1. Dùng proxy CORS (như https://api.allorigins.win hoặc tự dựng server nhỏ) → an toàn và ổn định hơn.
  2. Tự host PHP/Python proxy trên server của bạn → đảm bảo không bị chặn và luôn đọc được RSS + full content.

Đây là đoạn code html bạn cần.

HTML:
<!doctype html>
<html lang="vi">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>Simple Full RSS Reader</title>
  <style>
    :root{--accent:#185886}
    body{font-family:system-ui,-apple-system,Segoe UI,Roboto,'Helvetica Neue',Arial;margin:0;background:#f7f9fb;color:#111}
    header{background:linear-gradient(90deg,var(--accent),#0f5a83);color:#fff;padding:16px}
    .wrap{max-width:980px;margin:18px auto;padding:12px}
    .controls{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px}
    input[type=text]{flex:1;padding:8px;border:1px solid #ddd;border-radius:6px}
    button{background:var(--accent);color:#fff;border:none;padding:8px 12px;border-radius:6px;cursor:pointer}
    .hint{font-size:13px;color:#555;margin-bottom:8px}
    .item{background:#fff;border:1px solid #e6eef6;border-radius:8px;padding:12px;margin-bottom:12px;box-shadow:0 1px 2px rgba(0,0,0,.03)}
    .meta{font-size:13px;color:#666;margin-bottom:6px}
    .title{font-weight:700;color:#073b57;margin:0 0 6px}
    .content{margin-top:8px}
    .search{margin-left:auto}
    .small{font-size:13px;color:#666}
    .footer{font-size:13px;color:#666;margin-top:18px;text-align:center}
    .error{color:#a33}
  </style>
</head>
<body>
  <header>
    <div class="wrap">
      <h1 style="margin:0;font-size:20px">Simple Full RSS Reader</h1>
      <div style="font-size:13px;opacity:.9">Nhập URL RSS/Atom để đọc bài toàn văn. ⚠️ Lưu ý: nhiều trang chặn CORS nên cần proxy hoặc chạy file này trên server.</div>
    </div>
  </header>

  <main class="wrap">
    <div class="controls">
      <input id="feedUrl" type="text" placeholder="Ví dụ: https://vnexpress.net/rss/tin-moi-nhat.rss" value="">
      <select id="proxySelect" title="CORS proxy">
        <option value="https://api.allorigins.win/raw?url=">AllOrigins (free)</option>
        <option value="https://api.allorigins.cf/raw?url=">AllOrigins CF</option>
        <option value="https://cors.bridged.cc/">Bridge</option>
      </select>
      <button id="loadBtn">Tải</button>
      <input id="search" class="search" type="text" placeholder="Tìm trong tiêu đề/nội dung...">
    </div>

    <div class="hint">Nếu chọn "Không proxy" sẽ lỗi vì trình duyệt chặn CORS. Để đọc full bài, hãy luôn dùng proxy hoặc chạy qua server riêng.</div>

    <div id="status" class="small"></div>
    <div id="list"></div>
    <div class="footer">https://fxvnn.com • Trang này chèn HTML từ feed—cẩn trọng khi đọc nội dung từ nguồn lạ.</div>
  </main>

  <script>
    const $ = id => document.getElementById(id);
    const loadBtn = $('loadBtn');
    const list = $('list');
    const status = $('status');
    const search = $('search');

    function setStatus(txt, isError){ status.textContent = txt; status.className = isError? 'error small':'small'; }

    function getText(node, tagNames){
      for(const t of tagNames){
        const el = node.getElementsByTagName(t)[0];
        if(el && el.textContent.trim()) return el.textContent.trim();
      }
      return '';
    }

    function getHtml(node, tagCandidates){
      for(const name of tagCandidates){
        const byName = node.getElementsByTagName(name);
        if(byName && byName.length){
          const n = byName[0];
          if(n.childNodes.length>0){
            return n.textContent || n.innerHTML || '';
          }
        }
      }
      return '';
    }

    function renderItems(items){
      list.innerHTML = '';
      if(items.length===0){ list.innerHTML = '<div class="small">Không có mục nào.</div>'; return }
      items.forEach(it=>{
        const div = document.createElement('div'); div.className='item';
        const title = document.createElement('div'); title.className='title'; title.innerHTML = it.title || '(No title)';
        const meta = document.createElement('div'); meta.className='meta'; meta.innerHTML = (it.pubDate? ('<strong>'+it.pubDate+'</strong> • '):'') + (it.author? ('by '+it.author):'') + (it.link? (' • <a target="_blank" href="'+it.link+'">nguồn</a>'):'');
        const content = document.createElement('div'); content.className='content';
        content.innerHTML = it.fullContent || it.summary || '';
        div.appendChild(title); div.appendChild(meta); div.appendChild(content);
        list.appendChild(div);
      });
    }

    function parseFeed(text){
      const parser = new DOMParser();
      const xml = parser.parseFromString(text, 'application/xml');
      const parseError = xml.getElementsByTagName('parsererror')[0];
      if(parseError) throw new Error('XML parse error');

      const rssItems = Array.from(xml.getElementsByTagName('item'));
      const atomItems = Array.from(xml.getElementsByTagName('entry'));
      const nodes = rssItems.length? rssItems : atomItems;

      const out = nodes.map(node => {
        const title = getText(node, ['title']);
        let link = '';
        if(node.getElementsByTagName('link').length){
          const l = node.getElementsByTagName('link')[0];
          link = l.getAttribute('href') || l.textContent || '';
        }
        const pubDate = getText(node, ['pubDate','dc:date','updated','published']);
        const author = getText(node, ['author','dc:creator','creator']);
        let full = getHtml(node, ['content:encoded','encoded','content','description','summary']);
        if(!full){
          full = getText(node, ['description','summary']);
        }
        return {title, link, pubDate, author, fullContent: full, summary: full};
      });
      return out;
    }

    async function fetchFeed(rawUrl, proxyPrefix){
      try{
        setStatus('Đang tải...');
        const url = proxyPrefix? (proxyPrefix + encodeURIComponent(rawUrl)) : rawUrl;
        const res = await fetch(url);
        if(!res.ok) throw new Error('HTTP ' + res.status);
        const text = await res.text();
        const items = parseFeed(text);
        setStatus('Đã tải ' + items.length + ' mục.');
        return items;
      }catch(err){
        setStatus('Lỗi: ' + err.message, true);
        throw err;
      }
    }

    async function load(){
      const raw = $('feedUrl').value.trim();
      if(!raw) return setStatus('Vui lòng nhập URL feed.', true);
      const proxy = $('proxySelect').value || '';
      try{
        const items = await fetchFeed(raw, proxy);
        renderItems(items);
      }catch(e){}
    }

    loadBtn.addEventListener('click', e=>{ load(); });
    $('feedUrl').addEventListener('keydown', e=>{ if(e.key==='Enter') load(); });

    search.addEventListener('input', ()=>{
      const q = search.value.trim().toLowerCase();
      const nodes = Array.from(list.children);
      nodes.forEach(n=>{
        const text = (n.innerText||'').toLowerCase();
        n.style.display = text.includes(q)? '' : 'none';
      });
    });
  </script>
</body>
</html>

Mọi người có thể chỉnh code html hoặc css theo ý muốn của các bạn
 

Mở ví lưu trữ và giao dịch coin – nhận thưởng BTC ngay hôm nay

Tạo tài khoản ONUS miễn phí, xác minh KYC, hoàn tất nhiệm vụ đơn giản để nhận thưởng. Áp dụng cho người dùng mới. Số lượng có hạn.

  • Đăng ký & KYC nhanh trong vài phút
  • Nhận thưởng 270K sau khi hoàn tất yêu cầu
  • Giao diện dễ dùng, hỗ trợ tiếng Việt
Ưu đãi cho người mới Bảo mật & an toàn
Mở ví ONUS ngay *Điều khoản áp dụng • Có thể kết thúc sớm

Giao dịch Crypto với XM

Nạp rút nhanh chóng, điều kiện giao dịch minh bạch, chi phí cạnh tranh Được tin dùng bởi hàng triệu trader toàn cầu.

  • Khớp lệnh nhanh, ổn định
  • Chi phí & Spread rõ ràng
  • Hỗ trợ tiếng Việt 24/7
Bắt Đầu Ngay
Sidebar Prices (XAU, BTC, ETH)
Thị trường
Cặp
Giá hiện tại
Xu hướng
Đang tải...
Next: --:--
XAU/USD – Tín hiệu hôm nay
--
Đang phân tích…
Dữ liệu: fxvnn.com • Tham khảo
Back
Top