#令和3年3月31日付告発状 補充書01### 2021年4月7日の朝から翌8日未明まで20時間ほど掛かって作成した,ツイートをテキスト保存するスクリプト

:CATEGORIES: @kanazawabengosi #金沢弁護士会 @JFBAsns 日本弁護士連合会(日弁連) #法務省 @MOJ_HOUMU #スクリプト #プログラミング

 寝ていた時間も含めてですが20時間ほど掛かったように思います。次のツイートがようやく完成した頃の投稿になります。タイムラインには4時間前と表示されています。


> (py37_env) ➜ twilog wc -l *.csv
> 227225 hirono_hideki20210408054207.csv
> 137286 kk_hirono20210408054209.csv
> 79830 s_hirono20210407224547.csv
> 444341 合計

 今回はこのあとソースコードを公開しようと思います。告発状でもご紹介したTwilogのテキストデータですが,TwitterAPIからツイートを取得して追加をするようにしました。3件のアカウントで10分程掛かっていた処理が1秒足らずで終わるようになりました。

(py37_env) ➜  twilog wc -l *.csv
   227259 hirono_hideki20210408102712.csv
   137294 kk_hirono20210408104001.csv
    79835 s_hirono20210408102047.csv
   444388 合計

 20210408104001という部分が最終更新時刻になりますが,やはり読みづらく勘違いする可能性もありそうなので,これは早めに修正をしておいた方がよいかと考えました。

now_time = Time.now.strftime("%Y-%m-%d_%H%M%S")
newFile = "#{@dir}#{user}#{now_time}.csv"
check = Dir.glob("#{@dir}#{user}[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{6}.csv").join
check = Dir.glob("#{@dir}#{user}[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{6}.csv").join

 上記の箇所に問題があることに気が付きました。Dir.globでは正規表現が使えないということです。

 次の方法でうまくいきそうです。もっと簡単に済ませる方法はあるのですが,プログラミングの上達のためによりよい方法を模索しています。

Dir.glob("#{@dir}*").grep(/s_hirono[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{6}.csv/)

 ようやくうまくいきました。.joinは必要なさそうでしたが,これは返却値が配列になっているのを文字列に型変換する処理です。文字列として扱うことを明示しておいた方がよいのかと考えていましたが,配列のままでもcheck.empty?の条件式は同じでした。

(py37_env) ➜  twilog wc -l *.csv
   227262 hirono_hideki2021-04-08_114623.csv
   137300 kk_hirono2021-04-08_114405.csv
    79836 s_hirono2021-04-08_114625.csv
   444398 合計

 それではソースコードの掲載です。今朝になっての思いつきですが,江村正之検察官について先に取り上げておこうかと思います。

#!/usr/bin/env ruby
#encoding:UTF-8
#告訴状-2013-金沢地方検察庁御中_API
require 'twitter'
require 'open-uri'
require 'time'
require "fileutils"

@users = ['hirono_hideki','kk_hirono','s_hirono']
@dir = "/home/a66/twilog/"
@dir=ARGV[0].dup if ARGV[0]

if @dir !~ /^\/.+/ then
  puts "ディレクトリは絶対パスで指定して下さい!"
  exit 1
end

if @dir !~ /.+\/$/ then
  @dir.sub!(/(.+)/){ $1 + '/'}
end

#@users = ['s_hirono']

def twilogFileAdd(user)
    tweets = Array.new
    # ログイン
    client = Twitter::REST::Client.new do |config|
    config.consumer_key = 'カスタマーキー'
    config.consumer_secret = 'カスタマーシークレット'
    config.access_token = 'アクセストークン'
    config.access_token_secret = 'トークンシークレット'
    end

    client.user_timeline("#{user}", {:count => "300", :page => "1", :tweet_mode =>"extended"}).each do |tweet|
        tw_url =  "https://twitter.com/#{tweet.user.screen_name}/status/#{tweet.id}"
        tw_date = "#{(tweet.created_at + (60 * 60 * 9)).strftime("%Y-%m-%d %H:%M:%S")}"
        user = tweet.user.screen_name
        name = tweet.user.name
        tweet_text = tweet.full_text
        tweets << "#{tw_date} \"#{tweet_text.gsub(/(\r\n|\r|\n|\f)/,'\n').gsub('"', '\\\"')}\" #{tw_url}"
    end

    puts "#{user} #{tweets.size}件を取得しました。"

    now_time = Time.now.strftime("%Y-%m-%d_%H%M%S")
    newFile = "#{@dir}#{user}#{now_time}.csv"
    check = Dir.glob("#{@dir}*").grep(/s_hirono[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{6}.csv/).join

    unless File.directory?(@dir) then
      puts "#{@dir}#{user}[0-9]*.csv"
      FileUtils.mkdir_p(@dir)
          `touch "#{newFile}"`
    end

    if check.empty? then
          File.open(newFile, "w") do |io|
            tweets.each do |x|
              io.puts(x)
            end
          end

          puts "#{newFile}を新規に作成しました。\n\n"
          return
    end

    twilogFile = `find "#{@dir}" -name '*.csv' | grep -E "#{@dir}#{user}[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{6}.csv"`
    puts twilogFile.chomp!

    oldFile = twilogFile.chomp
    lastDate = `head -n 1 "#{twilogFile.chomp}"`
    lastDatePoint = lastDate.scan(/^([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}) .+/)[0]
    search_text = lastDatePoint.join
    n = tweets.index(tweets.select { |e| e =~ %r{^#{search_text}.*} }.join)
    now_time = Time.now.strftime("%Y-%m-%d_%H%M%S")
    updateFile = "#{@dir}#{user}#{now_time}.csv"

    if n == 0 then
      puts "更新なし\n\n"
      return
    else
      puts "#{n}件の更新です。"
    end

    #tweets.reverse!
    tweets[0..n-1].each do |x|
      puts x
    end

    cmd = "cp #{oldFile} #{updateFile}"
    `#{cmd}`

    File.open(updateFile, "r+") do |io|  ## ブロックにすると最後に"io.close"を書く手間が省けます
      line = io.read  ## 引数なしのreadは行末まで読み込みます
      io.seek(0) ## io#seekは先頭からのオフセットを指定する場合1引数で書けます
      tweets[0..n-1].each do |x|
        io.write(x)
        io.write("\n")
      end

      io.write(line)
    end

    if oldFile == updateFile then
      return
    end

    FileUtils.rm(oldFile)

    puts "#{n}件を追加した#{updateFile}を新規作成し,#{oldFile}を削除しました。\n\n"
end

#twilog/hirono_hideki210407.csv  twilog/kk_hirono210407.csv  twilog/s_hirono210407.csv
@users.each do |u|
    twilogFileAdd(u)
end

 :count => "300"とハッシュ値の値を指定していますが,200件しか取得できないと思います。ただ,2,3日前同じ処理をするコマンドで300件の取得が出来たことがあり,TwitterAPIの仕様が変わったのかと思いました。多めに指定してもエラーはでないようです。

 時刻は12時03分ですが,昨日4月7日のほぼ同じ時間に,このスクリプトの本体は出来上がっていました。そのあと難儀し時間がかかったのは,ディレクトリーを指定し,新規にファイルを作成する場合の処理です。

 共通したコードを数箇所に貼り付けていけば,簡単に処理の分岐ができたのですが,無駄にコードが増えると全体の可読性が悪くなるので,その辺りも勉強のつもりで取り組んでみました。