Ruby - PrawnでTweetリストPDF作成!

Updated:


少し前に「Ruby - PrawnでPDF作成!」で公開したとおり、Rubyで「Pwarn」Gemパッケージを使用してPDFを作成する方法を紹介しました。

今回はPDF作成処理を実用化してみました。

独学で習得したものなので、あまり綺麗ではありませんがソース(Linux版)を公開します。 参考になれば幸いです。

前提条件

  • Linux(当方はScientificLinux6.0)を使用している。
  • LinuxにRuby(当方はRuby1.9.2-p290)がインストールされている。
  • LinuxにMySQLがインストールされていて、使用するテーブルが作成されている。
  • Ruby Gemパッケージ「mysql2」がインストールされている。
  • Ruby Gemパッケージ「sanitize」がインストールされている。 (過去記事「Ruby - Sanitize Gemパッケージのインストール!」も参照)
  • Ruby Gemパッケージ「prawn」がインストールされている。

Rubyスクリプト

MySQLに保存している自分のTwitterのツイートを一覧にするPDF作成スクリプトです。 Windows版でもほぼ同じですが、MySQLのGemパッケージは異なりますしコーディングも若干異なります。

  • 「IPA P明朝」というフォントが必要です。
  • Rubyスクリプト、フォントファイルの配置場所は”/home/src”ディレクトリ配下です。
  • 引数を指定せずに実行すると、前月1日から前月末日の1ヶ月分を取得します。
  • 引数を2つ( YYYYMMDD, YYYYMMMDD )指定すると第1引数から第2引数までの期間のデータを取得します。
  • 出来上がるPDFのファイル名は”TweetList_YYYYMMDD-YYYYMMDD.pdf”で保存先は”/home/src/twitter”です。

ファイル名:twitter_make_pdf_tweet.rb

# -*- coding: utf-8 -*-
#-------------------------------------
# 引数 :  無し
#           or
#         第1:99999999(取得開始年月日(YYYYMMDD))
#         第2:99999999(取得終了年月日(YYYYMMDD))
#-------------------------------------

require 'mysql2'
require 'date'
require 'sanitize'
require 'kconv'
require 'prawn'

class TwitterMakePdfTweet

  # DB(MySQL)接続情報
  $DB       = 'hoge'
  $HOST     = '127.0.0.1'
  $USER     = 'hoge'
  $PASSWORD = 'hogehoge'

  # [CLASS] 引数
  class Arg

    # INITIALIZE
    def initialize()

      # 引数取得
      @date_f = ARGV[0].to_s
      @date_t = ARGV[1].to_s

    end

    # 引数チェック
    def get_date()

      begin

        # 引数が無い場合
        #   取得開始年月日:前月1日
        #   取得終了年月日:前月末日
        if @date_f == "" && @date_t == ""

          # 今日日付取得
          date_today = Date.today

          # 今月1日取得
          date_this_month_first = Date.new(date_today.year, date_today.month, 1)

          # 前月1日取得
          date_last_month_first = date_this_month_first << 1
          date_f                = date_last_month_first.strftime( "%Y%m%d" )

          # 前月末日取得
          date_last_month_last  = date_this_month_first - 1
          date_t                = date_last_month_last.strftime( "%Y%m%d" )

        # 引数がある場合
        #   第1引数[取得開始年月日]の妥当性チェック
        #   第2引数[取得終了年月日]の存在チェック
        #   第2引数[取得終了年月日]の妥当性チェック
        #   (第3引数以降は無視)
        else

          # 第1引数[取得開始年月日]が8桁の数字かチェック
          if !( @date_f.to_s =~ /^\d{8}$/ )
            
            # エラーメッセージ
            str_msg = "引数[0]エラー[#{@date_f.to_s}] : 8桁の数字を指定して下さい。"
            STDERR.puts( str_msg )
            exit 1
          
          end

          # 第1引数[取得開始年月日]が妥当な日付かチェック
          y = @date_f[0,4].to_i
          m = @date_f[4,2].to_i
          d = @date_f[6,2].to_i
          if !Date.valid_date?( y, m, d ) # 妥当な日付ならtrue、それ以外はnilが返ってくる

            # エラーメッセージ
            str_msg = "引数[0]エラー[#{@date_f.to_s}] : 8桁で妥当な日付を指定して下さい。"
            STDERR.puts( str_msg )
            exit 1

          end

          date_f = @date_f

          # 第2引数[取得終了年月日]の存在チェック
          # 第2引数[取得終了年月日]が8桁の数字かチェック
          if @date_t == "" || !( @date_t.to_s =~ /^\d{8}$/ )

            # エラーメッセージ
            str_msg =  "引数[0] : [#{@date_f.to_s}] OK!\n"
            str_msg << "引数[1]エラー[#{@date_t.to_s}] : 8桁の数字を指定して下さい。"
            STDERR.puts( str_msg )
            exit 1

          end

          # 第2引数[取得終了年月日]が妥当な日付かチェック
          y = @date_t[0,4].to_i
          m = @date_t[4,2].to_i
          d = @date_t[6,2].to_i
          if !Date.valid_date?( y, m, d ) # 妥当な日付ならtrue、それ以外はnilが返ってくる

            # エラーメッセージ
            str_msg =  "引数[0] : [#{@date_f.to_s}] OK!\n"
            str_msg << "引数[1]エラー[#{@date_t.to_s}] : 8桁で妥当な日付を指定して下さい。"
            STDERR.puts( str_msg )
            exit 1

          end

          date_t = @date_t

        end

        # 大小チェック
        #   第1引数[取得開始年月日] > 第2引数[取得終了年月日] はエラー
        if @date_f.to_i > @date_t.to_i

            # エラーメッセージ
            str_msg =  "引数[0] : [#{@date_f.to_s}], 引数[1] : [#{@date_t.to_s}]\n"
            str_msg << "引数[0] ≦ 引数[1] としてください。"
            STDERR.puts( str_msg )
            exit 1

        end

        return { :date_f => date_f,
                 :date_t => date_t  }

      rescue => e

        # エラーメッセージ
        str_msg = "[例外発生][" + self.class.name + ".get_date()] " + e.to_s
        STDERR.puts( str_msg )
        exit 1

      end

    end

  end

  # [CLASS] twitter_timelineテーブル
  class TwitterTimeline

    # INITIALIZE
    def initialize( hash = {} )

      @date_f = hash[:date_f]
      @date_t = hash[:date_t]

    end

    # データ取得
    def read_data()

      begin

        # データ取得開始・終了年月日
        date_f = "#{@date_f[0,4]}-#{@date_f[4,2]}-#{@date_f[6,2]} 00:00:00"
        date_t = "#{@date_t[0,4]}-#{@date_t[4,2]}-#{@date_t[6,2]} 23:59:59"

        # MySQL 接続
        my = Mysql2::Client.new( :host     => $HOST,
                                 :username => $USER,
                                 :password => $PASSWORD,
                                 :database => $DB        )

        # SQL クエリ実行 ( SELECT )
        sql =  "SELECT tweet_id, "
        sql << "       text, "
        sql << "       created_at, "
        sql << "       source "
        sql << "  FROM twitter_timelines "
        sql << " WHERE created_at between '" + date_f + "' AND '" + date_t + "' "
        res = my.query( sql, :as => :array )

        return res

      rescue => e

        # エラーメッセージ
        str_msg = "[例外発生][" + self.class.name + ".read_date()] " + e.to_s
        STDERR.puts( str_msg )
        exit 1

      end

    end

  end

  #################
  #### メイン処理 ####
  #################
  begin

    puts( "STARTED!!" )

    # 引数取得・チェック
    obj_arg = Arg.new()
    res = obj_arg.get_date()
    # 計算対象年月日[From, To]
    date_f = res[:date_f]
    date_t = res[:date_t]
    puts( "[DATE_FROM] #{date_f}" )
    puts( "[DATE_TO  ] #{date_t}" )

    # twitter_timelineテーブル
    hash = { :date_f => date_f,
             :date_t => date_t }
    tbl_twitter_timeline = TwitterTimeline.new( hash )

    # タイムラインデータ取得
    res = tbl_twitter_timeline.read_data()

    # 取得データ0件の場合は終了
    if res.count == 0
      puts( "Data Count = 0" )
      puts( "FINISHED!")
      exit
    end

    #### [START] PDF作成処理 ####

    # フォントファイル設定(IPA P明朝)
    FONT_FILE = 'ipamp.ttf' # Windows
    # FONT_FILE = '/home/src/ipamp.ttf' # Linux
    # 作成するPDFファイル名
    PDF_FILE  = 'TweetList_' + date_f + "-" + date_t + '.pdf' # Windows
    # PDF_FILE  = '/home/src/twitter/TweetList_' + date_f + "-" + date_t + '.pdf' # Linux

    # pdfオブジェクトを生成
    pdf = Prawn::Document.new(
      :page_size       => "A4",      # 用紙サイズ
      :page_layout     => :portrait, # 用紙向き ( 縦:portrait、横:landscape )
      :top_margin      => 60,        # 余白(上)
      :left_margin     => 40,        # 余白(左)
      :right_margin    => 30         # 余白(右)
    )

    # フォント指定
    pdf.font FONT_FILE

    # 取得データ分ループ
    res.each do |row|

      tweet_time = Time.parse( row[2].to_s ).strftime( "%Y/%m/%d %H:%M:%S" ) # Linux対応
      pdf.text "#{ tweet_time}        ID[ #{row[0].to_s} ]        Source[ #{Sanitize.clean(row[3].to_s)} ]"
      pdf.pad(5) { pdf.text "#{Kconv.tosjis( row[1].to_s )}" }

      # 下へ5px移動
      pdf.move_down 5

      # 罫線
      pdf.stroke_horizontal_rule

      # 下へ5px移動
      pdf.move_down 5

    end

    # ページヘッダ
    pdf.page_count.times do |i|

      pdf.go_to_page( i + 1 )

      # ページタイトル
      pdf.bounding_box( [ 0, 780 ], :width => 215, :height => 15 ) do
        pdf.text "Tweet一覧 [ #{ date_f.to_s } - #{ date_t.to_s } ]",
          :align => :left
        pdf.stroke do
          pdf.line pdf.bounds.bottom_left, pdf.bounds.bottom_right
        end
      end

      # ページ番号
      pdf.number_pages "<page> / <total>",
        :at          => [pdf.bounds.right - 50, 780],
        :width       => 50,
        :align       => :right,
        :page_filter => :all

    end

    pdf.render_file( PDF_FILE )

    #### [E N D] PDF作成処理 ####

    puts( "FINISHED!")

  rescue => e

    # エラーメッセージ
    str_msg = "[例外発生]" + e.to_s
    STDERR.puts( str_msg )
    exit 1

  end

end

出来栄えサンプルはTweetList_20110701-20110731。 PDF作成について、もっと細かな設定も可能ですが、今のところこれで十分だと思っています。

普段はこのRubyスクリプトをLinuxサーバ上でcron登録し、毎月1日午前0:10に引数無しで起動するようにしています。 これにより毎月自動で前月分のTweet一覧PDFが作成されます。 cron設定(/etc/cron.d/twitter)

10 0 1 * * root /usr/local/bin/ruby /home/src/twitter_make_pdf_tweet.rb > /dev/null </code></pre>

個別に出力する必要が生じた場合には、引数を指定して実行させれば対応可能です。

以上。





 

Sponsored Link

 

Comments