#!/usr/bin/python # -*- coding: sjis -*- # 複数のサイトからRSSを取得して一つのRSSにして再配信するための # Twistedのサンプルアプリケーションです。
# 必要なモジュールをインポートする from twisted.internet import reactor from twisted.application.internet import TimerService from twisted.web.client import getPage from twisted.web import server, resource
import feedparser from sqlobject import *
# RSSのフィード元を保存するためのRDBMSのテーブル class Feed(SQLObject): title = StringCol(notNone=True) link = StringCol(notNone=True, unique=True) entries = RelatedJoin("Entry")
# RSSの各エントリを保存するためのRDBMSのテーブル class Entry(SQLObject): title = StringCol(notNone=True) href = StringCol(notNone=True, unique = True) description = StringCol() feeds = RelatedJoin("Feed")
# RSSのフィード元のテーブルを更新するための関数 def updateChannel(title, url): feeds = Feed.select(Feed.q.link == url) if not feeds.count(): feed = Feed(title=title, link=url) else: feed = feeds[0] return feed
# RSSの各エントリを保存するための関数 def updateEntry(entry, channel): entries = Entry.select(Entry.q.href == entry.link) if not entries.count(): e = Entry(title = entry.title.encode("utf8"), href = entry.link.encode("utf8"), description = entry.setdefault("summary", "").encode("utf8")) channel.addEntry(e)
# Twisted.web.clientのgetPageでページを取得したときに # 処理されるコールバック関数 # この関数の中でRDBMSのFeedテーブルとEntryテーブルを更新します def gotPage(content): rss = feedparser.parse(content) channel = updateChannel(rss.feed.title.encode("utf8"), rss.feed.link.encode("utf8")) for entry in rss.entries: updateEntry(entry, channel) # 各サイトから一度にRSSを取得します。 # リクエストは非同期に処理されます def update(urls): for url in urls: if url: getPage(url).addCallback(gotPage)
# RSSを再配信するためのサーバのサイトクラス class RssFeeder(resource.Resource): isLeaf = True # HTTPのGETのリクエストはこの関数が処理します。 # ここでは、RSSファイルを作成して、そのファイルを返しています。 def render_GET(self, request): entries = Entry.select(orderBy="-id") content = [] content.append('') content.append('') content.append('OreOre Plannet') host = request.getHost() content.append('http://%s:%d/' %(host.host, host.port)) for entry in entries: content.append('') content.append('' + entry.title + '') content.append('' + entry.href + '') content.append('') content.append('') content.append('') request.setHeader("Content-Type", "text/xml") return "\r\n".join(content)
def main(): # アプリケーションの初期化を行います。
# URLのリストをplannet-url.txtから読み込んで # リストに保存しています。 filename = "plannet-url.txt" urls = open(filename).read().split("\n")
# RDBMSを初期化します。 # sqliteのデータベースをメモリ上に作成して、 # 必要なテーブルを作成します。 sqlhub.processConnection = connectionForURI('sqlite:/:memory:') Entry.createTable() Feed.createTable() # HTTPサーバを初期化します。 # HTTPのリクエストを処理するためのオブジェクトを作成して、 # ポート番号1234でリクエストを待ちます。 site = server.Site(RssFeeder()) reactor.listenTCP(1234, site)
# タイマーを作成して、30分ごとにupdate関数をコールします。 # タイマーはreactorが動いてから1秒後に開始されます。 timer = TimerService(60*30, update, urls) reactor.callLater(1, timer.startService) # メインイベントループ reactor.run() if __name__ == "__main__": main()
|