查看: 8193|回复: 6

[大赛作品提交] 基于树莓派+Kindle的RSS阅读器

[复制链接]
  • TA的每日心情
    慵懒
    2018-3-29 13:14
  • 签到天数: 20 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2017-12-26 22:20:09 | 显示全部楼层 |阅读模式
    分享到:
    十分感谢e络盟提供的比赛赞助基金。

    一、项目名称:
    基于树莓派+Kindle的RSS阅读器

    1.原理介绍
    本系统通过python编程读取rss源中的内容,首先利用正则表达式提取rss源发布时间,并将rss源中的时间与当前时间进行对比,当在一天以内时则认为是最新数据,将其解析完成后转换为html文件,在利用kindle提供的邮箱推送文档的功能,使用python将生成的html的文件以邮件的方式发送至kindle对应的邮箱,完成rss内容的推送。

    2.系统版本
    RASPBIAN STRETCH LITE
    最新版本下载地址
    https://downloads.raspberrypi.org/raspbian_lite_latest

    3. 应用源代码:
    本系统使用python3.5.3进行编程,首先我们需要安装第三方库feedparser,这里直接使用pip进行安装:
    1. pip3 install feedparser
    复制代码
    包安装完成后,就开始了正式的编程之旅了,首先我们要能解析出rss内容并转换为html文件,这里创建一个类RssParser,代码如下
    1. # -*- coding:utf-8 -*-

    2. import feedparser
    3. import date_cmp

    4. class RssParser:
    5.     def __init__(self, rss_url):
    6.         self.rss = feedparser.parse(rss_url)

    7.     def get_feed_title(self):
    8.         return self.rss.feed.title

    9.     def get_item_cnt(self):
    10.         return len(self.rss.entries)

    11.     def get_item_date(self, index):
    12.         return self.rss.entries[index].updated

    13.     def get_item_title(self, index):
    14.         return self.rss.entries[index].title

    15.     def get_itme_content(self, index):
    16.         return self.rss.entries[index].summary

    17.     def get_item_url(self, index):
    18.         return self.rss.entries[index].link

    19.     def generate_html(self):
    20.         html_template = """
    21.         <!DOCTYPE html>
    22.         <html lang="en">
    23.         <head>
    24.             <meta charset="UTF-8">
    25.         </head>
    26.         <body>
    27.             {content}
    28.         </body>
    29.         </html>
    30.         """
    31.         file_name = self.get_feed_title() + '.html'
    32.         html_content = ''
    33.         dateCmp = date_cmp.DateCmp()
    34.         for i in range(self.get_item_cnt()):
    35.             if dateCmp.IsLastest(self.get_item_date(i)):
    36.                 item_title = self.get_item_title(i)
    37.                 item_content = self.get_itme_content(i)
    38.                 item_url = self.get_item_url(i)
    39.                 html_content = html_content + '<h2>' + '<a href="' + item_url + '">' + item_title + '</a></h2>\r\n'
    40.                 html_content = html_content + '<div class="summary">\r\n' +  item_content + '\r\n</div>\r\n'

    41.         if 0 != len(html_content):
    42.             html = html_template.format(content=html_content)
    43.             html = html.encode("utf-8")
    44.             f = open(file_name, 'wb')
    45.             f.write(html)
    46.             f.close()
    47.             return file_name
    48.         else:
    49.             return '\0'

    复制代码
    如上面代码所示中,feedparser是我们安装的第三方类,date_cmp是自己编写的用于从字符串中解析出时间并与当前时间进行对比的包,当字符串显示的时间与当前时间在一天以内时,则接口函数IsLastest返回True,否则返回False,其代码如下:
    1. # -*- coding:utf-8 -*-
    2. import re
    3. import datetime

    4. class DateCmp:
    5.     def __init__(self):
    6.         self.month_map = {
    7.             'Jan':'01',
    8.             'Feb':'02',
    9.             'Mar':'03',
    10.             'Apr':'04',
    11.             'May':'05',
    12.             'Jun':'06',
    13.             'Jul':'07',
    14.             'Aug':'08',
    15.             'Sep':'09',
    16.             'Oct':'10',
    17.             'Nov':'11',
    18.             'Dec':'12'
    19.         }
    20.         self.date_patton0 = \
    21.             r'(20\d{2})[-/]?((?:[0-9]?|[1-9])[0-9])[-/]?((?:[0-9]?|[1-9])[0-9])?'
    22.         self.date_patton1 = \
    23.             r'([A-Za-z]{3,4}),[ |\t]?((?:[0-9]?|[1-9])[0-9])[ |\t]?([A-Za-z]{3,4})[ |\t]?(20\d{2})'
    24.         self.time_patton = \
    25.             r'((?:[0-9]?|[1-9]])[0-9]):((?:[0-9]?|[1-9]])[0-9]):((?:[0-9]?|[1-9]])[0-9])'

    26.     def Str2Date(self, str):
    27.         year = 0
    28.         month = 0
    29.         day = 0
    30.         hour = 0
    31.         minute = 0
    32.         second = 0

    33.         m = re.findall(self.date_patton0, str)  #xxxx-xx-xx xx:xx:xx
    34.         if 0 == len(m):
    35.             m = re.findall(self.date_patton1, str) #aaa, xx aaa xxxx xx:xx:xx
    36.             if 0 == len(m):
    37.                 return None
    38.             else:
    39.                 year = int(m[0][3])
    40.                 month = int(self.month_map[m[0][2]])
    41.                 day = int(m[0][1])
    42.         else:
    43.             year = int(m[0][0])
    44.             month = int(m[0][1])
    45.             day = int(m[0][2])

    46.         m = re.findall(self.time_patton, str)
    47.         if 0 != len(m):
    48.             hour = int(m[0][0])
    49.             minute = int(m[0][1])
    50.             second = int(m[0][2])
    51.         else:
    52.             return None

    53.         try:
    54.             b = datetime.datetime(year, month, day, hour, minute, second)
    55.         except ValueError:
    56.             b = None
    57.         return b

    58.     def IsLastest(self, str):
    59.         date_get = self.Str2Date(str)
    60.         if None == date_get:
    61.             return True
    62.         else:
    63.             date_now = datetime.datetime.now()
    64.             date_diff = date_now - date_get
    65.             if date_diff.days < 1:
    66.                 return True
    67.             else:
    68.                 return False
    复制代码
    当html文件可以正常生成了,接下来就是使用邮箱发送文件了,python代码如下所示:
    1. # -*- coding:utf-8 -*-
    2. import smtplib
    3. from email.mime.multipart import MIMEMultipart
    4. from email.mime.text import MIMEText
    5. from email.mime.application import MIMEApplication

    6. class EmailSend:
    7.     def __init__(self):
    8.         self.msg = MIMEMultipart()

    9.     def Login(self, server, user, pwd):
    10.         self.smtp = smtplib.SMTP(server, timeout = 30)
    11.         self.smtp.login(user, pwd)
    12.         self.User = user
    13.         self.Pwd = pwd

    14.     def AddText(self, text):
    15.         part = MIMEText(text)
    16.         self.msg.attach(part)

    17.     def AddAppendix(self, file_name):
    18.         part = MIMEApplication(open(file_name,'rb').read())
    19.         part.add_header('Content-Disposition', 'attachment', filename=file_name)
    20.         self.msg.attach(part)

    21.     def SendEmail(self, to):
    22.         self.msg['Subject'] = 'Convert'
    23.         self.msg['From'] = self.User
    24.         self.msg['To'] = to
    25.         self.smtp.sendmail(self.User, to, self.msg.as_string())
    26.         pass

    27.     def Logout(self):
    28.         self.smtp.close()
    复制代码
    在上述过程中软件界面如果什么都不显示,会十分单调,这里添加几行python代码,就可以获得树莓派的温度,如下
    1. # -*- coding:utf-8 -*-
    2. import os

    3. class RaspberryInfo:
    4.     # Get CPU temperature as a character string
    5.     def GetCpuTemperature(self):
    6.         res = os.popen('vcgencmd measure_temp').readline()
    7.         self.CpuTemperature = res.replace("temp=","").replace("'C\n","")
    复制代码
    OK,代码都已编写完成了,接下来就是编写一个主程序对上述功能进行调用了,在调用之前,我们先要配置发送邮箱的服务器、用户名和密码、kindle接收邮箱的地址,rss源读取的时间,rss源地址,这些内容分别保存在user_email.txt文件、kindle_email.txt、timer.txt、urls.txt四个文件中,如下所示:
    user_email.txt文件
    1. smtp.126.com
    2. xxxxxx@126.com
    3. password
    复制代码
    kindle_email.txt文件
    1. xxxxxxx@kindle.cn
    复制代码
    timer.txt文件
    1. 13:10
    复制代码
    urls.txt文件
    1. http://feed.cnblogs.com/blog/sitehome/rss
    复制代码
    最后附上主函数实现整个系统的功能
    1. # -*- coding:utf-8 -*-

    2. from mail_send import EmailSend
    3. from rss_reader import RssParser
    4. from get_raspberry_info import RaspberryInfo
    5. import time
    6. import datetime
    7. import sys
    8. import os

    9. print('正在启动,请稍后...')
    10. #读取发送邮箱的用户名和密码
    11. f = open('user_email.txt', 'rt')
    12. [server, user, pwd] = f.readlines();
    13. server = server.strip('\n')
    14. user = user.strip('\n')
    15. pwd = pwd.strip('\n')
    16. f.close();

    17. #读取发送的kindle邮箱
    18. f = open('kindle_email.txt', 'rt')
    19. kindle_email = f.readline()
    20. kindle_email = kindle_email.strip('\n')
    21. f.close()

    22. #读取发送时间
    23. f = open('timer.txt', 'rt')
    24. send_time = f.readline()
    25. send_time = send_time.strip('\n')
    26. [hour, minute] = send_time.split(':')
    27. send_hour = int(hour)
    28. send_minute = int(minute)
    29. f.close()

    30. #登录邮箱
    31. email_send = EmailSend()
    32. email_send.Login(server,user,pwd);

    33. #获取rss内容并转换成网页
    34. f = open('urls.txt', 'rt')
    35. urls = f.readlines()

    36. #获取当前时间,当到达发送时间时,则读取rss内容,转换为html并发送至kindle邮箱
    37. while True:
    38.     now_time = datetime.datetime.now()
    39.     #达到发送时间
    40.     if now_time.hour == send_hour and now_time.minute == send_minute:
    41.         for url in urls:
    42.             url = url.strip('\n')
    43.             rss = RssParser(url)
    44.             file_name = rss.generate_html()
    45.             if file_name != '\0':
    46.                 email_send.AddAppendix(file_name)
    47.                 email_send.SendEmail(kindle_email)
    48.                 print('send email success                                ')
    49.                 time.sleep(90)
    50.                
    51.     else:
    52.         #显示树莓派信息
    53.         rsp_info = RaspberryInfo()
    54.         rsp_info.GetCpuTemperature()
    55.         info = 'CPU 温度:' + rsp_info.CpuTemperature
    56.         time_info = '    当前时间:%d:%d:%d \r ' % (now_time.hour, now_time.minute, now_time.second)

    57.         sys.stdout.writelines('                                               \r')
    58.         sys.stdout.writelines(info + time_info)
    59.         time.sleep(1)

    复制代码
    4. 硬件连线图
    本系统只需要一块树莓派即可,真的要连的话就用网线把树莓派和路由器连起来好了!

    5. 演示视频
    由于从采集完成到发送邮件到kindle接收,是一段比较长的时间,且中间过程没有任何可以演示的地方,因此这里就发几张截图好了,一样可以看出效果哦。
    图一:等待过程中,显示树莓派CPU温度和当前的时间

    图一

    图一

    图二:为了防止作假,我们先看看kindle里面可是只有几本电子书哦

    图二

    图二

    图三:rss获取时间到了,邮件发送完成后会有一条提示信息:send email success

    图三

    图三

    图四:kindle已经收到推送了,好开心!

    图四

    图四

    图五:迫不及待的打开看看里面的内容

    图五

    图五

    图六:唯一不太方便的就是,rss源里的内容只是一些概要,要想看详细内容,需要理由kindle的浏览器

    图六

    图六

    回复

    使用道具 举报

    该用户从未签到

    发表于 2017-12-27 09:23:31 | 显示全部楼层
    我的kindle也是这款滴♬︎*(๑ºั╰︎╯︎ºั๑)♡︎
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2018-3-29 13:14
  • 签到天数: 20 天

    连续签到: 1 天

    [LV.4]偶尔看看III

     楼主| 发表于 2018-1-2 08:49:23 | 显示全部楼层
    ky123 发表于 2017-12-27 09:23
    我的kindle也是这款滴♬︎*(๑ºั╰︎╯︎ºั๑)♡︎

    那么巧啊,你有什么好看的书推荐一下呗
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2018-1-2 08:56:58 | 显示全部楼层
    yu0405jie 发表于 2018-1-2 08:49
    那么巧啊,你有什么好看的书推荐一下呗

    《飘》看不看呀,估计你不喜欢呢。可以看看《教父》,大学有一段时间特别迷民国人物传记,你也可以试试。书籍推荐类有一个微信公众号warfalcon,然后学习方法类有一个公众号白诗诗。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2018-3-29 13:14
  • 签到天数: 20 天

    连续签到: 1 天

    [LV.4]偶尔看看III

     楼主| 发表于 2018-1-3 09:37:53 | 显示全部楼层
    ky123 发表于 2018-1-2 08:56
    《飘》看不看呀,估计你不喜欢呢。可以看看《教父》,大学有一段时间特别迷民国人物传记,你也可以试试。 ...

    恩恩,好的,谢谢啦
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2018-1-30 14:52
  • 签到天数: 25 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2018-1-26 13:31:21 | 显示全部楼层
    请问笔记本事怎么用作树莓派显示器的?
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2021-7-30 11:40
  • 签到天数: 1792 天

    连续签到: 1 天

    [LV.Master]伴坛终老

    发表于 2018-1-30 06:55:02 | 显示全部楼层
    看看了,,,
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-4-19 17:02 , Processed in 0.191980 second(s), 31 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.