RSS σε 66 κοινωνικά δίκτυα: Facebook, Instagram, X, LinkedIn, Telegram και άλλα Blog Συνεργατικό Πρόγραμμα Επικοινωνία
Σύνδεση Ξεκινήστε δωρεάν
Updated: 2026-10-17
Create an RSS Feed for a Website Without One (Python)

Short answer: If a website has no RSS feed, you can create one with a short Python script. Download the news page politely, read the headlines and links with BeautifulSoup, remember which links you have already seen in a small SQLite database, write the newest items as RSS 2.0 XML and refresh the file on a schedule. Do this only for sites you own or have permission to use, share headlines and links rather than copied articles, and give the finished feed address to an auto-poster.

Plenty of useful sources publish no feed: a local council with a news page, a supplier with a list of announcements, a sports club with a results page, or your own older website built before feeds were common. People then copy links by hand, or they miss updates. A scraper that turns the page into a feed fixes the problem once and keeps working. It is also the part of automation where a careless script causes real trouble, for the website you read and for you. This guide builds a small, polite scraper that creates a clean feed, explains how to give items stable identifiers and dates, and shows how to run it reliably.

Check first: do you really need a scraper?

Before writing any code, look for an existing feed. Many sites have one that is not advertised:

  • view the page source and search for application/rss+xml ή application/atom+xml;
  • try common paths such as /feed/, /rss, /rss.xml και /atom.xml;
  • check whether the site runs on a platform that provides feeds by default; finding a WordPress feed link is a good example;
  • look for a sitemap or an API that lists the newest pages.

If the site owner can add a feed, ask. It is better for everyone than scraping. A scraper is the right tool only when there is no feed, no API and no willingness to add one.

Rules before you start

Scraping is acceptable only when it is respectful and permitted. Follow these rules:

  • Get permission when you can. For your own site or a client site this is easy. For other sites, read the terms of use. If they forbid automated access, do not scrape.
  • Respect robots.txt. The script below checks it before every run.
  • Identify yourself. Use a clear User-Agent with a contact address, so that the site owner can reach you.
  • Be gentle. One request every few minutes is plenty. Never fetch pages in a tight loop.
  • Share headlines and links, not whole articles. Copying full text can infringe copyright. A title, a short summary and a link back send readers to the source.
  • Never bypass logins, paywalls or bot protection. If the page needs one, the content is not meant for automated reuse.

Install the tools

You need Python 3 and two libraries: requests to download the page and beautifulsoup4 to read the HTML. Install them in a virtual environment with pip install requests beautifulsoup4. Everything else in the script comes from the standard library.

Find the pattern on the page

Open the news page in a browser, right-click a headline and choose Inspect. Look for the element that wraps one news item, for example an article tag with a class, a list item or a table row. Inside it you need the link with the title, and optionally a summary and a date. Write down the CSS selectors that match them, such as article.news-item for the wrapper, h2 a for the title link and p for the summary. Choose selectors that describe the structure rather than the layout, because class names such as col-md-6 change with every redesign.

The script

Save this as make_feed.py. Change the address, the selectors and the file paths to match your page.

import os
import sqlite3
import tempfile
import urllib.robotparser
from datetime import datetime, timezone
from email.utils import format_datetime
from urllib.parse import urljoin
from xml.sax.saxutils import escape

import requests
from bs4 import BeautifulSoup

START = "https://www.example.org/news/"
DB = "/opt/feeds/seen.db"
OUT = "/var/www/feeds/example-news.xml"
AGENT = "ExampleFeedBot/1.0 (+https://www.example.com/contact)"
LIMIT = 20


def allowed(url):
    robots = urllib.robotparser.RobotFileParser()
    robots.set_url(urljoin(url, "/robots.txt"))
    robots.read()
    return robots.can_fetch(AGENT, url)


def scrape():
    response = requests.get(START, headers={"User-Agent": AGENT}, timeout=20)
    response.raise_for_status()
    soup = BeautifulSoup(response.text, "html.parser")
    found = []
    for card in soup.select("article.news-item"):
        link = card.select_one("h2 a")
        if not link or not link.get("href"):
            continue
        summary = card.select_one("p")
        found.append({
            "title": link.get_text(strip=True),
            "url": urljoin(START, link["href"]),
            "summary": summary.get_text(strip=True) if summary else "",
        })
    return found


def main():
    if not allowed(START):
        raise SystemExit("robots.txt does not allow this page")
    items = scrape()
    if not items:
        raise SystemExit("Nothing found: the page layout may have changed")

    db = sqlite3.connect(DB)
    db.execute("CREATE TABLE IF NOT EXISTS items (url TEXT PRIMARY KEY, title TEXT, summary TEXT, first_seen TEXT)")
    now = datetime.now(timezone.utc).isoformat()
    for item in items:
        db.execute("INSERT OR IGNORE INTO items VALUES (?, ?, ?, ?)", (item["url"], item["title"], item["summary"], now))
    db.commit()
    rows = db.execute("SELECT url, title, summary, first_seen FROM items ORDER BY first_seen DESC, rowid DESC LIMIT ?", (LIMIT,)).fetchall()
    db.close()

    parts = []
    for url, title, summary, seen in rows:
        stamp = format_datetime(datetime.fromisoformat(seen), usegmt=True)
        parts.append(
            "<item><title>" + escape(title) + "</title>"
            "<link>" + escape(url) + "</link>"
            '<guid isPermaLink="true">' + escape(url) + "</guid>"
            "<pubDate>" + stamp + "</pubDate>"
            "<description>" + escape(summary) + "</description></item>"
        )

    xml = (
        '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel>'
        "<title>Example Organisation News</title>"
        "<link>" + START + "</link>"
        "<description>Unofficial feed of the news page</description>"
        + "".join(parts) + "</channel></rss>"
    )
    handle, temp_path = tempfile.mkstemp(dir=os.path.dirname(OUT), suffix=".tmp")
    with os.fdopen(handle, "w", encoding="utf-8") as out:
        out.write(xml)
    os.chmod(temp_path, 0o644)
    os.replace(temp_path, OUT)


if __name__ == "__main__":
    main()

Why it is built this way

  • The address is the identifier. A page address is unique and does not change when the headline is edited. It becomes the GUID, so a corrected title does not create a new item; see why your RSS feed auto-posts the same article twice.
  • The database remembers when you first saw an item. Most news pages do not give a machine-readable date. Using the current time for every item on every run would make the whole feed look new each time. Storing the first-seen time keeps each date stable.
  • Links are made absolute. The urljoin call turns relative links into full addresses, which avoids the problems described in relative URLs in RSS feeds.
  • The script fails loudly on an empty page. If the layout changes and the selectors match nothing, the script stops and the old feed stays online instead of becoming empty.
  • The file is replaced atomically, so a reader never sees a half-written feed.

Dates and the first run

If the page shows real dates, parse them and use them instead of the first-seen time. Read the date text with datetime.strptime or a library such as dateutil, assume a time zone if the page gives none, and convert to UTC. Real dates are more accurate, but a parsing error should never stop the run: fall back to the first-seen time and log a warning. On the very first run, every item on the page is new to your database and gets the same time. Check how your auto-poster treats a feed it sees for the first time, and consider letting the first run finish before you connect the feed, so old headlines are not shared as news. The rules for timestamps are explained in RSS date formats and pubDate errors.

Pages that load content with JavaScript

Some pages show an empty shell in the HTML and fill the list later with JavaScript. Your script then finds nothing, even though the browser shows plenty of headlines. Before reaching for a full browser, open the network tab of your browser tools and look for a request that returns the list as JSON. If the page calls such an address, the site already provides a structured source, and reading it is usually simpler and lighter than parsing HTML. Check the terms for that address in the same way as for the page itself. Only if no such source exists is a headless browser worth considering, and it is heavier to run, slower and easier to break, so keep it as the last choice. Also remember that summaries on listing pages are often shortened, which is fine for a feed: a title and one sentence are what an auto-poster needs.

Run it on a schedule

Use cron or a systemd timer. A line like the following runs the script every thirty minutes and keeps a log:

*/30 * * * * /opt/feeds/venv/bin/python /opt/feeds/make_feed.py >> /var/log/make_feed.log 2>&1

Use full paths for Python and the script, because cron has a minimal environment. Thirty minutes is enough for most news pages, and it keeps the load on the source site very low. Serve the output folder with your web server and check the content type; see the Content-Type guide. Monitor the age of the file, because a scraper fails silently when the source page changes; the checklist in RSS feed not updating helps when updates stop.

Test the feed before connecting it

  1. Run the script by hand and open the XML file. Check that titles and links are correct and that the newest item is first.
  2. Click three links to confirm that they open the right pages.
  3. Validate the file with the W3C Feed Validation Service.
  4. Run the script a second time and confirm that nothing is duplicated and the dates did not change.
  5. Wait for a real new item on the source page and confirm that it appears in the feed.

Common mistakes to avoid

  • Scraping too often. Frequent requests annoy site owners and can get your address blocked.
  • Fragile selectors. Layout classes break after a redesign; choose structural selectors and watch the logs.
  • Using the current time as the date. It makes old items look new on every run.
  • Copying full articles. Share the headline and link and send readers to the source.
  • Ignoring blocks. If the site blocks you or answers with errors, stop and ask for permission or a proper feed.

How PostRSS works with a generated feed

PostRSS has been publishing RSS and Atom feeds to social networks since 2014. Paste the address of your generated feed, connect your accounts and choose how each post is built from the title, the description or the page title. PostRSS checks the feed as often as every minute and shares each new item, with its link, to the channels you choose among 66 supported networks, messengers, team chats and blogs, including LinkedIn, X, Bluesky, Mastodon and Telegram. Keyword filters, UTM parameters and posting windows let you tune each channel. See the PostRSS features page and the plan limits on the pricing page. More developer guides are under the Technical Guide tag.

Σχετική ανάγνωση

The bottom line

A scraper that creates a feed is a small and useful tool when a source has none, as long as you use it with care. Look for a real feed first, get permission, respect robots.txt, identify your script, request pages rarely and share headlines with links. Use the page address as the identifier, store the first-seen time so dates stay stable, fail loudly when the page changes and write the file atomically. Run it on a schedule, validate the result and connect it to an auto-poster so that new items are shared without manual copying.

FAQ

Is it legal to create an RSS feed from a website that has none?

It depends on the site, its terms and your country, so this is not legal advice. The safest route is permission from the owner. Read the terms of use, respect robots.txt and share only headlines and links.

How often should the scraper run?

Every thirty minutes or every hour is enough for most news pages. More frequent requests rarely help and put needless load on the source site.

What happens when the website changes its layout?

The selectors may stop matching. The script in this guide stops with a message and keeps the old feed online. Watch the log or the file age so you notice and update the selectors.

Why not use the current time as the publication date?

Because every run would give every item a new date, and an auto-poster could treat old headlines as fresh news. Store the time when each item was first seen, or parse the real date from the page.

Can I connect a scraped feed to PostRSS?

Yes, once the feed is served at a public address. Add that address as a source in PostRSS, connect your social accounts and each new item is posted automatically. Make sure you are allowed to share the content you are republishing.

{“@context”: “https://schema.org”, “@type”: “FAQPage”, “mainEntity”: [{“@type”: “Question”, “name”: “Is it legal to create an RSS feed from a website that has none?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “It depends on the site, its terms and your country, so this is not legal advice. The safest route is permission from the owner. Read the terms of use, respect robots.txt and share only headlines and links.”}}, {“@type”: “Question”, “name”: “How often should the scraper run?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Every thirty minutes or every hour is enough for most news pages. More frequent requests rarely help and put needless load on the source site.”}}, {“@type”: “Question”, “name”: “What happens when the website changes its layout?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “The selectors may stop matching. The script in this guide stops with a message and keeps the old feed online. Watch the log or the file age so you notice and update the selectors.”}}, {“@type”: “Question”, “name”: “Why not use the current time as the publication date?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Because every run would give every item a new date, and an auto-poster could treat old headlines as fresh news. Store the time when each item was first seen, or parse the real date from the page.”}}, {“@type”: “Question”, “name”: “Can I connect a scraped feed to PostRSS?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Yes, once the feed is served at a public address. Add that address as a source in PostRSS, connect your social accounts and each new item is posted automatically. Make sure you are allowed to share the content you are republishing.”}}]}

New guides, once a month

What changed in the networks, what broke, and how to fix it before it costs you reach.

We send a confirmation e-mail first. Unsubscribe any time.

Περισσότερα εργαλεία από την ομάδα μας

Από την Internet Solutions, την ομάδα πίσω από το PostRSS. Κάθε προϊόν σάς εξοικονομεί χρόνο με τον δικό του τρόπο.

Live chat με AI για ιστότοπους Talkmio Ο ιστότοπός σας απαντά στους επισκέπτες 24/7 με βάση το δικό σας περιεχόμενο, στη γλώσσα τους. Δωρεάν πρόγραμμα · χωρίς κάρτα Βοηθός AI Ask Mio Συνομιλία, κώδικας, σχεδιασμός, γραφή και έρευνα. Το Mio επιλέγει το καλύτερο μοντέλο για κάθε εργασία. Δωρεάν πρόγραμμα Αυτόματος πιλότος AI για blog και social AI Blog Autopilot Η AI γράφει άρθρα SEO 2.000–3.000 λέξεων και κοινοποιεί το καθένα σε 60 κοινωνικά δίκτυα. Τα 3 πρώτα άρθρα δωρεάν Έλεγχος υγείας ιστότοπου Έλεγχος AI ιστοτόπου SEO, ταχύτητα, SSL, ασφάλεια και ρυθμίσεις email σε μία αναφορά, με σειρά προτεραιότητας. Ο πρώτος έλεγχος δωρεάν Σε βάθος ανίχνευση SEO Έλεγχος SEO AI ιστοτόπου Πλήρης ανίχνευση SEO σε 7 τομείς, μαζί με την ορατότητα στην αναζήτηση AI, με διορθώσεις ταξινομημένες κατά αντίκτυπο. Ο πρώτος έλεγχος δωρεάν RSS και ροές προϊόντων Δημιουργός RSS Feed Δημιουργήστε RSS από οποιαδήποτε σελίδα, καθώς και ροές προϊόντων για Google και Meta που ενημερώνονται μόνες τους. Δωρεάν πρόγραμμα Ανάπτυξη ιστότοπων και SEO Internet Solutions Ιστότοποι, ηλεκτρονικά καταστήματα και εξατομικευμένα συστήματα, που σχεδιάζει, κατασκευάζει και υποστηρίζει η ομάδα μας. Από το 2011