Przejdź do treści

RSS Reader

  • przez

Chciałbym się „pochwalić” małym projekcikiem aplikacji do sprawdzania kanałów RSS i wysyłania ostatnich wpisów w mailu. Ja używam Feedly ale ostatnio doszkalam się z python i pomyślałem, że zrobię sobie taki mały projekcik 🙂 Będę go używał do ważniejszych kanałów RSS i będę miał bardziej zorganizowane artykuły do przeczytania. Ten projekt jest takim wstępem do czegoś większego. Mam pewien pomysł ale jak zrobię to napiszę 😉

Repozytorium znajduje się tutaj i jest też tam instrukcja jak używać. Jeśli coś dopisać to daj znać 😉

Do sprawdzania kanałów RSS używam biblioteki feedparser. Robię to w poniższy sposób. Tutaj taka mała uwaga modified nie zawsze działa. To nie jest wina biblioteki a bardziej serwerów (z tego co wyczytałem w necie). Dlatego dodatkowo sprawdzam datę artykułu 😉

class FeedsReader:
    """Class representing a feeds reader"""

    def __init__(self, feed_urls) -> None:
        self.urls = feed_urls

    def get_feeds(self, from_date) -> []:
        """Function checks feeds and return posts since `from_date`."""

        feeds = []
        for url in self.urls:
            try:
                logging.info("Checking: %s since %s", url, from_date)
                d = feedparser.parse(
                    url_file_stream_or_string=url, modified=from_date)
                feed = Feed(d.feed.title, d.feed.subtitle)
                length = len(d.entries)
                logging.info("Downloaded %d entries", length)
                for i, entry in enumerate(d.entries):
                    logging.info(
                        "Checking %d entry of [%s]", i + 1, d.feed.title)
                    if datetime.datetime.fromtimestamp(mktime(entry.published_parsed)) >= from_date:
                        feed.add_entry(
                            entry.title, entry.summary, entry.link)
                feeds.append(feed)
            except Exception as e:
                logging.error("Something went wrong: %s", e, exc_info=True)
                continue

        return feeds

Jak już pobiorę artykuły/posty to wysyłam je w poniższy sposób. To co na pewno poprawię to szablon maila. W innych projektach używałem np. Sendgrid Więc może zrobię coś podobnego. Ale cierpliwości 😉

class EmailSender:
    """Class sends email with feeds"""

    def __init__(self, sender, receiver, smtp_host, smtp_port, smtp_user, smtp_password) -> None:
        self.sender = sender
        self.receiver = receiver
        self.smtp_host = smtp_host
        self.smtp_port = smtp_port
        self.smtp_user = smtp_user
        self.smtp_password = smtp_password

    def send_feeds_email(self, feeds) -> None:
        """Function sends email containing feeds' entries."""

        body = self.create_email_body(feeds)

        mail = MIMEMultipart('alternative')
        mail['From'] = self.sender
        mail['To'] = self.receiver
        mail['Subject'] = "You latest feeds!"
        mail.attach(MIMEText("Switch to html", 'text'))
        mail.attach(MIMEText(body, 'html'))

        with smtplib.SMTP_SSL(self.smtp_host, self.smtp_port) as smtp_server:
            smtp_server.login(self.smtp_user, self.smtp_password)
            smtp_server.sendmail(self.sender, self.receiver, mail.as_string())
            smtp_server.quit()

    def create_email_body(self, feeds) -> str:
        """Function create body of the feeds email."""

        body = """
        <!doctype html><html>
          <head></head>
          <body style="font-family: sans-serif;"><p><h1>Hello</h1><p>I think that you should read below articles ;-)</p>
         """
        for feed in feeds:
            body = body + f'<h2>{feed.name}</h2><p><ul>'
            for entry in feed.entries:
                body = body + \
                    f'<li><a href="{entry.url}">{entry.title}</a><br />{entry.summary}</li>'
            body = body + '</ul></p>'

        return body + "</body></html>"

Przykładowy mail wygląda tak jak poniżej. Jak sam(a) widzisz style trzeba poprawić 😀