Categories: Без рубрики

python-feed-parsing/

Хочу поделиться с вами небольшим скриптом. Как правило, такого рода поделкам на Python я не посвящаю целые посты, а просто дописываю их в список примеров к заметке Как я выбирал скриптовый язык и остановился на Python (кстати, да, там есть обновления). Но этот конкретный скрипт показался мне достаточно интересным, чтобы рассказать о нем отдельно. Как вы уже поняли, он парсит RSS- и Atom-ленты, а затем отправляет информацию о новых записях на указанный e-mail адрес.

Потребность в таком скрипте возникла после того, как я решил отписаться от большинства неинтересных мне фидов, а оставшиеся пару десятков читать через e-mail. Разумеется, для отправки новых записей из RSS на электронную почту уже существует множество готовых сервисов (например, Blogtrottr ). Но новые записи они часто высылают с задержкой и/или с прикрепленной рекламой и/или за деньги, да и вообще завязываться на очередной SaaS из-за такой ерунды не хотелось. Вы ведь еще помните историю с Google Reader, верно? Так вот, в итоге получилось действительно удобнее, чем использовать отдельное приложение для чтения RSS (я пользовался Liferea, а до этого — Feedly). Как минимум, теперь у меня меньше нужных мне приложений, а значит в iPhone’е меньше иконок, а в Unity появился лишний свободный хоткей. Да и просто удобно, когда любые интересующие тебя события приходят в одно-единственное место.

Итак, писать, само собой разумеется, будем не все с нуля, а возьмем готовый модуль feedparser ( модуль на PyPI , документация ):

sudo pip3 install feedparser

А вот и сам скрипт ( репозиторий на GitHub ):

#!/usr/bin/env python3

# feed2email.py
# (c) Aleksander Alekseev 2016
# http://remontka.com/

import feedparser

from smtplib import SMTP
# from smtplib import SMTP_SSL as SMTP
from email . mime . text import MIMEText
from contextlib import contextmanager
import signal
import getpass
import hashlib
import time
import sys
import re

server = ‘smtp.yandex.ru’
port = 587 # 25
login = «YOUR_LOGIN»
from_addr = «NEWS <YOUR_LOGIN@yandex.ru>»
receiver = «YOUR_EMAIL»
processed_urls_fname = «processed-urls.txt»
feed_list_fname = «feed-list.txt»
# change to True before first run or you will receive A LOT of emails
# then change back to False
fake_send = False
sleep_time = 60 * 5 # seconds
net_timeout = 10 # seconds
smtp_retry_time = 30 # seconds
smtp_retries_num = 5

# >>> import hashlib
# >>> hashlib.sha1(b»qwerty»).hexdigest()
# ‘b1b3773a05c0ed0176787a4f1574ff0075f7521e’
pwhash = ‘b1b3773a05c0ed0176787a4f1574ff0075f7521e’

# FUNCS

class TimeoutException ( Exception ) : pass

@ contextmanager
def timeout_sec ( seconds ) :
def signal_handler ( signum , frame ) :
raise TimeoutException ( Exception ( «Timed out!» ) )
signal . signal ( signal . SIGALRM , signal_handler )
signal . alarm ( seconds )
try :
yield
finally :
signal . alarm ( 0 )

def file_to_list ( fname ) :
rslt = [ ]
with open ( fname , «r» ) as f:
rslt = [ x for x in f. read ( ) . split ( » n » ) if x. strip ( ) != «» ]
return rslt

# MAIN

password = getpass . getpass ( «SMTP Password: » )

if hashlib. sha1 ( bytearray ( password , ‘utf-8’ ) ) . hexdigest ( ) != pwhash:
print ( «Invalid password» , file = sys . stderr )
sys . exit ( 1 )

while True :
feed_list = file_to_list ( feed_list_fname )
# filter comments
feed_list = [ x for x in feed_list if not re . match ( «(?i) s *#» , x ) ]
keep_urls = 100 * len ( feed_list )
processed_urls = [ ]

try :
processed_urls = file_to_list ( processed_urls_fname )
except FileNotFoundError:
pass

print ( «Processing {} feeds…» . format ( len ( feed_list ) ) )

for feed in feed_list:
print ( feed )
f = None
try :
with timeout_sec ( net_timeout ) :
f = feedparser. parse ( feed )
except TimeoutException:
print ( «ERROR: Timeout!» )
continue

feed_title = f [ ‘feed’ ] . get ( ‘title’ , ‘(NO TITLE)’ )
feed_link = f [ ‘feed’ ] . get ( ‘link’ , ‘(NO LINK)’ )

for entry in f [ ‘entries’ ] :
if entry [ ‘link’ ] in processed_urls:
continue

subject = «{title} | {feed_title} ({feed_link})» . format (
title = entry. get ( ‘title’ , ‘(NO TITLE’ ) ,
feed_title = feed_title ,
feed_link = feed_link
)
print ( subject )
summary = entry. get ( ‘summary’ , ‘(NO SUMMARY)’ )
body = «{summary} n n {link} n n Source feed: {feed}» . format (
summary = summary [ : 256 ] ,
link = entry [ ‘link’ ] ,
feed = feed
)
print ( body )
print ( «——-» )

msg = MIMEText ( body , ‘plain’ )
msg [ ‘Subject’ ] = subject
msg [ ‘From’ ] = from_addr
msg [ ‘To’ ] = receiver

if not fake_send:
for attempt in range ( 1 , smtp_retries_num+ 1 ) :
try :
with timeout_sec ( net_timeout ) , SMTP ( server , port ) as conn:
conn. starttls ( )
conn. login ( login , password )
conn. sendmail ( from_addr , [ receiver ] , msg. as_string ( ) )
break
except Exception as exc:
print ( ( «Failed to send email {}/{} — {}, » +
«retrying in {} seconds» ) . format (
attempt , smtp_retries_num , exc ,
smtp_retry_time
)
)
time . sleep ( smtp_retry_time )

processed_urls = [ entry [ ‘link’ ] ] + processed_urls

with open ( processed_urls_fname , «w» ) as urls_file:
urls_file. write ( » n » . join ( processed_urls [ :keep_urls ] ) )

print ( «Sleeping {} seconds…» . format ( sleep_time ) )
time . sleep ( sleep_time )

Список фидов можно получить из OPML-файла при помощи примерно такого однострочника:

cat feeds.opml | python3 -c ‘import re,sys; [ print(m.group(1)) for ‘
‘ln in sys.stdin for m in [ re.search(«(?i)xmlUrl=»(.*?)»»»»ln) ] ‘
‘if m is not None ]’

Теперь правим немного настройкизапускаем на каком-нибудь сервере в screen и радуемся. Все равно у любого уважающего себя программиста в наше время уже есть сервер в DigitalOcean под VPN Syncthing

admin

Share
Published by
admin

Recent Posts

Консоль удаленного рабочего стола(rdp console)

Клиент удаленного рабочего стола (rdp) предоставляет нам возможность войти на сервер терминалов через консоль. Что…

2 месяца ago

Настройка сети в VMware Workstation

В VMware Workstation есть несколько способов настройки сети гостевой машины: 1) Bridged networking 2) Network…

2 месяца ago

Логи брандмауэра Windows

Встроенный брандмауэр Windows может не только остановить нежелательный трафик на вашем пороге, но и может…

2 месяца ago

Правильный способ отключения IPv6

Вопреки распространенному мнению, отключить IPv6 в Windows Vista и Server 2008 это не просто снять…

2 месяца ago

Ключи реестра Windows, отвечающие за параметры экранной заставки

Параметры экранной заставки для текущего пользователя можно править из системного реестра, для чего: Запустите редактор…

2 месяца ago

Как управлять журналами событий из командной строки

В этой статье расскажу про возможность просмотра журналов событий из командной строки. Эти возможности можно…

2 месяца ago