用Java抓取RSS生成Mobi文件发送到Kindle
生活随笔
收集整理的這篇文章主要介紹了
用Java抓取RSS生成Mobi文件发送到Kindle
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
最近寫了個小工具,通過抓取RSS生成適合Kindle展示的Mobi格式的文件,并發送到Kindle 個人圖書館,也算是繼續“自動化”之旅。
代碼前前后后寫了個把月,趁著放假期間,決定把它搞定。使用方法什么的就不多說了,項目開源到Github上去了,上面有使用說明。
這篇文章簡單得聊聊項目本身以及總結的一些問題。
項目簡介
首先來看看項目的組織結構圖:
大致分為三大部分:
- core:核心部分,定義了RSS相關的基本數據抽象(base)以及所有流程的接口抽象(contract)
- component:組件(可選),兩個組件,一個是對mobi文件進行strip處理,以很好得控制最終文件的大小,另一個是郵件發送
- impl:對core以及component的實現。
core
base包不必多說,一個RSS源大概可以分解為三個對象:一個Feed包含了N個Entry,每個Entry都包含了文本內容(desc)以及若干個Image。 說說核心流程的抽象:(按照流程順序說明,不按照圖中接口順序)
AbstractConfigManager
是一個抽象類,維護了項目最核心的配置文件(resources/rtms.properties),并對其中的配置完整性進行檢查。IFeedLinkProvider
要抓取RSS,必須要有RSS Source(RSS URL)。該接口作為Feed link 的 provider 定義了一個方法來獲取所有需要抓取的鏈接: /*** get parsing rss links** @return the String array of all links*/String[] getFeedLinks();IRSSParser
獲取到feed的鏈接之后,就需要去一個個parse它們,該接口定義了parse方法: /*** parse feed with given urls** @param urls the URL Array* @return the BaseFeed Array*/BaseFeed[] parse(URL[] urls);返回生成的Feed對象集合,由于有些RSS源不提供全文輸出(只是提供一個摘要,比如看這里),所以這時候就需要一個全文輸出處理,來從給定的URL獲取原文
IFullTxtOutput
該接口定義了輸出全文的協議: /*** output full text from a entrylink** @param entryLink the string of the entry link url* @return the full text*/String fullTextFrom(String entryLink);在parse的過程中,難免會遇到<img />標簽,我們在parse時候先對其src屬性進行處理,但圖片并不在此進行下載,所以需要將其先存起來,在需要下載的時候,在取出來下載,這時,我們需要一個“圖片運輸器“
IImgTransporter
該接口定義了圖片的保存與獲取協議: /*** push a img obj to the image store** @param img the instance of BaseImage*/public void push(BaseImage img);/*** get all image objs with the feed** @param feed the instance of BaseFeed* @return the map of all the images per feed*/public Map<String, BaseImage> getAllImageObjsWithFeed(BaseFeed feed);由于我們認為一個RSS Feed是一個基準單位(一個mobi文件以一個個feed組合而成)所以圖片的獲取以feed為單位整取(當然也可以粒度再細一點以feed里每個entry為基準)。
如果不需要額外的功能,我們已經能夠生成mobi文件了:
IMobiGenerator
該接口定義了生成mobi需要實現的方法: /*** generate mobi file with a list of feeds** @param feeds the List of BaseFeed instances* @return return the generated mobi file path*/String generate(List<BaseFeed> feeds);通過傳入一個BaseFeed對象的集合,最終輸出mobi文件的全路徑即可。 以上這些接口,定義了將RSS生成Mobi文件的最基本的流程,如果需要一些附加功能,可以有選擇的實現component package中的一些接口。
component
該package大概提供了三個擴展:IEntryTransporter
上面在說到IfullTxt的時候,我們通過實現該接口,完成了全文輸出。出于效率與性能考慮,我們有必要將最近處理過的feed的一些entry“緩存”起來。這是因為,該項目有可能被構建為daily task,而有些RSS 源并不是每日更新,即便更新過,如果不多,還是會抓取到一些舊的。這時我們會先去查看這些entry是否曾經已被處理過,如果已經處理過,那么就沒必要再去處理了(特別是全文輸出還是很耗時的),協議: /*** save a entry** @param entry the instance of BaseEntry*/void save(BaseEntry entry);/*** check is entry exists** @param entry the instance of BaseEntry* @return if exists return true otherwise return false*/boolean entryExists(BaseEntry entry);/*** get processed entry (the func for cache entry)** @param entry the instance of BaseEntry* @return return the processed entry*/BaseEntry getProcessedEntry(BaseEntry entry);/*** get a feed's all entry (processed)** @param feed the instance of BaseFeed* @return the map of the feed's entries (key is entry's link)*/Map<String, BaseEntry> getAllEntryPerFeed(BaseFeed feed);IFileStripHandler
由于生成適合kindle的mobi文件,大致的手段是通過amazon提供的kindlegen命令行工具實現,但通過他生成的文件非常大(大到幾十兆)。這樣非常不便于網絡傳輸(特別是郵件發送),在不影響閱讀的情況下,是有辦法大幅減小其大小的,所以,我們定義類該接口,供需要的擴展實現: /*** do strip* @param originalFilePath the original file path* @param newFilePath the new path*/void doStrip(String originalFilePath, String newFilePath);最后,如果有必要,可以將生成的文件發生到kindle接受的圖書館(一個認可的郵件地址),這時我們需要抽象出,郵件發送的接口:
IMailSender
它定義了發送帶附件的郵件接口: /*** send mobi file from path* @param filePath the mobi file path*/void sendFrom(String filePath);impl
該package默認實現了core以及component里所有的接口(既然全都實現了,還抽出接口來干嘛?)。這里,我只是提供了默認實現,抽出接口的原因是為了保證流程的穩定性,從而不必過份關注實現(下面你會看到實現的方式可能并不是唯一的),即使實現變了,也只是某個對象的內部發生改變,不至于擴大影響。抽象與實現
哪里可能存在變化呢?因為我本機裝了redis,所以我對圖片對象以及entry對象的存儲借助于redis,如果你不熟悉redis你可以更改其他的存儲方式。FeedLink我默認存放在一個properties配置文件里,你可以存放在其他數據源內。RSSParser采用的是ROM+jsoup的解析方式,FullTxt 以及 Strip mobi借助于python來實現。。。由于有很多開源庫可供選擇,所以,如果你對某個庫更熟悉,你可以更改它的實現,而不必傷筋動骨。庫與技術點總結
(1)mobi文件生成其實是可以基于html文件的,因而可以定義出固定的templete,填充內容后直接生成即可,這里使用的是freemarker (2)解析Feed以及對html進行過濾處理使用的是ROM+jsoup (3)json處理采用gson (4)全文輸出借助于python的兩個強大的開源庫(feedparser / readability-lxml)。原理大概是解析dom,對某些元素的父元素計算特征值,可參考這篇文章?以及 這篇文章 (5)mobi文件生成,借助于amazon提供的 for mac平臺的kindlegen (6)郵件發送采用的是javamail (7)strip減小mobi文件大小也借助于python的實現,通過刪除文件內部大量無用的空白等 (8)圖片多線程下載,采用的是線程池,這邊還有待重新處理TODO
(1)重新實現多線程圖片下載 (2)用node.js 起一個http server或者構建一個linux定時任務,做daily task具體的使用方法以及后續更新請關注:https://github.com/yanghua/RssToMobiService
總結
以上是生活随笔為你收集整理的用Java抓取RSS生成Mobi文件发送到Kindle的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VOD?
- 下一篇: 需求分析解决方案文案,展示图文结合的文案