2011/01/19

TwitterとGoogle App Engineの自分用Webアプリケーション「TwitMail」(ソース)

先月つくったTwitMail(TwitterとGoogle App Engineの自分用Webアプリケーション)、未だTaskQueueの実装が済んでいないですが、現状のもののソースを公開しておきます。

app.yaml
application: アプリ名
version: 1

runtime: python
api_version: 1

handlers:
- url: /main
  script: get_timeline.py

- url: /send
  script: send_tweet.py

- url: /db/delete
  script: db_delete.py

- url: .*
  script: default.py

cron.yaml
cron:

- description: Get Timeline job
  url: /main
  schedule: every 10 minutes

- description: Send Tweet job
  url: /send
  schedule: every 15 minutes

- description: DB Delete job
  url: /db/delete
  schedule: every 60 minutes

get_timeline.py
# -*- coding: utf-8 -*-
import sys, os, re, urllib, urllib2
import simplejson
import tweepy
from datetime import *
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db


#OAuth
CONSUMER_KEY        = 'CONSUMER_KEY'        #自分で取得した値を入れる
CONSUMER_SECRET     = 'CONSUMER_SECRET'     #自分で取得した値を入れる
ACCESS_TOKEN        = 'ACCESS_TOKEN'        #自分で取得した値を入れる
ACCESS_TOKEN_SECRET = 'ACCESS_TOKEN_SECRET' #自分で取得した値を入れる


#データモデルの定義
class TimelineData(db.Model):
    icon_url   = db.StringProperty()                   #アイコン画像URL
    scr_name   = db.StringProperty()                   #スクリーン名
    usr_name   = db.StringProperty()                   #ユーザ名
    tweet      = db.StringProperty(multiline=True)     #ツイート
    status_id  = db.StringProperty()                   #ステータスID
    reply_id   = db.StringProperty()                   #リプライID
    created_at = db.StringProperty()                   #ツイートされた日時
    ds_created = db.DateTimeProperty()                 #DataStoreに登録された日時
    sent       = db.IntegerProperty()                  #送信済みフラグ
    schema_ver = db.IntegerProperty()                  #スキーマ・バージョン



# メイン処理
class GetTimeline(webapp.RequestHandler):
  def get(self):
    #HomeTimelineの取得    
    auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
    api = tweepy.API(auth)
    home_timeline = api.home_timeline(count=50)
    
    #TimeLineの並び順を逆順に変更
    home_timeline.reverse()
    
    for tw in home_timeline:
      try:
        #同じステータスIDが登録されているかCheck
        registed_check_query = TimelineData().all().order('-ds_created').filter('status_id =', str(tw.id).encode("UTF-8")).get()
        
        print registed_check_query
        
        #登録がなければ、登録
        if None == registed_check_query:
          #データストアに登録
          td = TimelineData()
          td.icon_url   = tw.user.profile_image_url                         #アイコン画像URL
          td.scr_name   = tw.user.screen_name                               #スクリーン名
          td.usr_name   = tw.user.name                                      #ユーザ名
          td.tweet      = tw.text                                           #ツイート
          td.status_id  = str(tw.id).encode("UTF-8")                        #ステータスID
          td.reply_id   = str(tw.in_reply_to_status_id).encode("UTF-8")     #リプライID
          td.created_at = str(tw.created_at).encode("UTF-8")                #ツイートされた日時
          td.ds_created = datetime.utcnow() + timedelta(hours=9)            #DataStoreに登録された日時
          td.sent       = 0                                                 #送信済みフラグ、0は未送信
          td.schema_ver = 2                                                 #スキーマ・バージョン
          td.put()
          
          print "▼Check Status"
          
          print td.icon_url.encode("UTF-8")
          print td.scr_name.encode("UTF-8")
          print td.usr_name.encode("UTF-8")
          print td.tweet.encode("UTF-8")
          print td.status_id.encode("UTF-8")
          print td.reply_id.encode("UTF-8")
          print td.created_at.encode("UTF-8")
          print str(td.ds_created).encode("UTF-8")
          print str(td.sent).encode("UTF-8")
          print str(td.schema_ver).encode("UTF-8")
          
          print "△Save DataStore\n"
          
        else:
          print "△Skip DataStore\n"
          
      except:
        print "△NG DataHandling\n"



application = webapp.WSGIApplication(
                                [
                                  ('/main', GetTimeline),
                                ],
                                debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
    main()

send_tweet.py
# -*- coding: utf-8 -*-
import sys, os, re, urllib, urllib2
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
import base64
from google.appengine.api import mail
from dateutil import parser
from dateutil import relativedelta


#データモデルの定義
class TimelineData(db.Model):
    icon_url   = db.StringProperty()                   #アイコン画像URL
    scr_name   = db.StringProperty()                   #スクリーン名
    usr_name   = db.StringProperty()                   #ユーザ名
    tweet      = db.StringProperty(multiline=True)     #ツイート
    status_id  = db.StringProperty()                   #ステータスID
    reply_id   = db.StringProperty()                   #リプライID
    created_at = db.StringProperty()                   #ツイートされた日時
    ds_created = db.DateTimeProperty()                 #DataStoreに登録された日時
    sent       = db.IntegerProperty()                  #送信済みフラグ
    schema_ver = db.IntegerProperty()                  #スキーマ・バージョン


#メイン処理
class SendTweet(webapp.RequestHandler):
  def get(self):
    
    not_send = TimelineData().all().order('ds_created').filter('sent =', 0).fetch(limit=200)
    #print not_send
    
    count = 0   #ツイート数
    start = ""  #最初のツイート
    body = ""   #ツイートの要約
    #"http://twitter.com/#!/"
    
    if not_send:
      for ns in not_send:
        #時刻を変換
        d = parser.parse(ns.created_at)
        jst = d + relativedelta.relativedelta(hours=+9)
        #print jst
        
        try:
          
          body += '
' + "\n" body += '
' + "\n" body += '
' + ns.scr_name.encode("UTF-8") + ' (' + ns.usr_name.encode("UTF-8") + ')' + '
' + "\n" body += '
' + str(jst).encode("UTF-8") + '
' + "\n" body += '' body += '
' + ns.tweet.encode("UTF-8") + '
' + "\n" body += 'http://mobile.twitter.com/' + ns.scr_name.encode("UTF-8") + '/status/' + ns.status_id.encode("UTF-8") + '' + "\n" if 'None' != ns.reply_id: body += '' body += '
' + "\n" body += '
' + "\n" body += "\n" count += 1 if count == 1 : #start = ns.created_at.encode("UTF-8") start = str(jst).encode("UTF-8") ns.sent = 1 #送信済みフラグの変更 ns.put() print str(ns.sent).encode("UTF-8") except: print count print ns.sent #print body subject = start + " から " + str(count).encode("UTF-8") + "件"; print subject fromAddr = "from: メールアドレス"; toAddr = "to: メールアドレス"; html_h = "\n\n" html_f = "" + "\n" html_body = "" html_body += html_h html_body += body html_body += html_f #print html_body mail.send_mail(fromAddr, toAddr, subject, body=" ", html=html_body) else: print "No Data" application = webapp.WSGIApplication( [ ('/send', SendTweet), ], debug=True) def main(): run_wsgi_app(application) if __name__ == "__main__": main()

db_delete.py
# -*- coding: utf-8 -*-
import sys, os, re, urllib, urllib2
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db


#データモデルの定義
class TimelineData(db.Model):
    icon_url   = db.StringProperty()                   #アイコン画像URL
    scr_name   = db.StringProperty()                   #スクリーン名
    usr_name   = db.StringProperty()                   #ユーザ名
    tweet      = db.StringProperty(multiline=True)     #ツイート
    status_id  = db.StringProperty()                   #ステータスID
    reply_id   = db.StringProperty()                   #リプライID
    created_at = db.StringProperty()                   #ツイートされた日時
    ds_created = db.DateTimeProperty()                 #DataStoreに登録された日時
    sent       = db.IntegerProperty()                  #送信済みフラグ
    schema_ver = db.IntegerProperty()                  #スキーマ・バージョン



#メイン処理
class DeleteDS(webapp.RequestHandler):
  def get(self):
    # DataStoreの削除
    deleteCheck = TimelineData.all().filter('sent =', 1).fetch(limit=500)
    
    if deleteCheck :
      for dc in deleteCheck:
        try:
          db.delete(dc)
          print "deleted"
        except:
          print "no delete"
    else:
      print "no delete data"


application = webapp.WSGIApplication(
                                [
                                  ('/db/delete', DeleteDS),
                                ],
                                debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
    main()

default.py
print "Content-Type: text/plain"
print ""
print "TwitMail"

まだまだ見直す必要があるコードですが、参考になれば。