それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

DoCoMoの請求書を毎月Evernoteに送信してチェックする

紙は死んだ?

紙で明細が毎月印刷されて届く郵送サービスは偉大だと思う。
アプリで明細確認や、WEB明細はハッキリ言って見ない。
印刷を節約することでコスト削減・環境保護ってわかりやすいお題目だけど誰も得してない。

郵送をやめても環境保護にはならない。

だって郵便局のサービスとルート配送が、DoCoMoの請求書に関係なく動いているもの。
社会インフラ事業は利用者が多いほど環境負荷が減って、効率が良くなるものです。

紙請求書を復活して欲しいけれど、無理なのでPDFをEvernoteに擬似郵送する

Evernoteに送信しておけば間違いなくPDFを見忘れない!

DoCoMoに請求書をPDF取得して保存するスクリプト

gistに投げておいた→docomo.rb

#!/usr/bin/env ruby
#coding: utf-8
$KCODE='u'         if  RUBY_VERSION.to_f < 1.9
require 'rubygems' if RUBY_VERSION.to_f < 1.9

module BillScraper

	class MyDoCoMo
		require 'pp'
		require 'mechanize'
		require 'nkf'
		require 'kconv'
		require 'scanf'
		class Mechanize::HTTP::Agent
			def post_connect uri, response, body_io # :yields: agent, uri, response, body
				@post_connect_hooks.each do |hook|
					begin
						hook.call self, uri, response, body_io
					ensure
						body_io.rewind
					end
				end
			end
		end
		attr_accessor :m
		def initialize( id=nil, password=nil )
			@m = Mechanize.new
			@m.user_agent_alias = 'Windows IE 7'
			@@id = id
			@@password = password
			self.enable_force_encoding
		end
		def enable_force_encoding
			@m.post_connect_hooks << lambda{|ua,uri,res,body_io|
				if res["Content-Type"] =~ /^text\/.*$/
					body =  NKF.nkf('-wxm0',body_io.read)
					body.gsub! /shift-jis/i,"utf-8"
					body_io.truncate body_io.pos
					body_io.rewind
					body_io.puts body
				end
			}

		end
		def disable_force_encoding
			@m.post_connect_hooks.clear
		end

		def login(id=nil,password=nil)
			id ||= @@id
			password ||= @@password
			@m.get "http://www.mydocomo.com/web/home/"
			@m.page.links_with( :text => "ログイン").first.click
			#@m.page.body = @m.page.body.toutf8
			@m.page.forms[0].fields_with(:name=>"MDCM_UID").first.value = id
			@m.page.forms[0].fields_with(:name=>"MDCM_PWD").first.value = password
			@m.page.forms[0].submit
			self.go_through_refresh_page
		end

		def go_through_refresh_page
			#クッションページ・リフレッシュがある。
			return unless @m.page.search("meta[http-equiv='refresh']").size>0
			redirect_to  =  @m.page.search("meta[http-equiv='refresh']").attr("content").to_s.split(/;/).last.scanf("url=%s").first
			redirect_to  =  URI.join(@m.page.uri.to_s,redirect_to)
			@m.get redirect_to
			#@m.page.body = m.page.body.toutf8
			@m.page.body
		end

		def ryokin_page
			@m.page.links_with( :text=>"ご利用料金の確認").first.click
			self.go_through_refresh_page
		end


		def ryokin_matome_page #一括請求ページ
			# 一括
			form = @m.page.forms_with(:name=>"form1").first
			form.fields_with(:name=>"root_GKFAGW001_DENWABANGOPULLDOWN").last.options[0].select
			form.action = form.action+"&root_GKFAGW001SubmitHyoujiPull="
			# puts form.action
			form.submit
			#puts m.page.body = m.page.body.tosjis
			#@m.page.body = m.page.body.toutf8
			@m.page.body
		end




		def latest_ryokin_meisai # go
			#直近で請求が確定している月
			table =  @m.page.search('table.new-amountclaimschedule').last
			year_month = table.search("tr th p.strong")[1]
			year_month = year_month.text()
			q =  table.search("tr img[alt='利用内訳']").first["onclick"][/setSeikyuNengtsu\('(\d+)'\)/, 1]
			form = @m.page.forms_with(:name=>"form1").first
			form.action = form.action+"&root_GKFAGW001SubmitShosaiUtiwake="
			form.fields_with(:name=>"root_GKFAGW001_HIBUTTONNENGETU").first.value = q
			# p q
			# exit
			form.submit
			@m.page.body = @m.page.body.toutf8
			year_month
		end

		def get_latest_meisai_pdf
			# 位置をリセット
			self.go_home
			#料金ページヘ
			self.ryokin_page
			self.ryokin_matome_page
			#取得可能な最新月
			y_m = self.latest_ryokin_meisai
			#
			#半角カナがフォームの値にあるので、変換すると化けるので、utf-8強制変換をオフ
			#
			self.disable_force_encoding
			#PDF ダウンロード リンク
			form = @m.page.forms_with(:name=>"form1").first
			form.action = form.action+"&root_GKFAGW001SubmitPdf="
			form.submit

			#doui() 同意する
			form = @m.page.forms_with(:name=>"form1").first
			form.action = form.action+"&root_GKHCGW001SubmitAgree="
			form.submit
			#ダウンロード
			form = @m.page.forms_with(:name=>"form1").first
			form.action = form.action+"&root_GKHCGW001SubmitAgree="
			form.action = form.action+"&BisAutoSubmissionREQUEST="
			form.submit

			#
			# utf-8強制変換をもとに戻す
			#
			self.enable_force_encoding
			return {"file_name" => "docomo-#{y_m}-meisai.pdf", "body"=> @m.page.body , "month" => y_m }
		end




		def get_latest_gaiyo_pdf
			# 位置をリセット
			self.go_home
			#料金ページヘ
			self.ryokin_page
			self.ryokin_matome_page
			#取得可能な最新月
			y_m = self.latest_ryokin_gaiyou


			self.disable_force_encoding # ⇐ 重要

			#PDF ダウンロード リンク
			form = @m.page.forms_with(:name=>"form1").first
			form.action = form.action+"&root_GKFBGW001SubmitPdf="

			form.submit
			#m.page.body = m.page.body.toutf8 unless RUBY_VERSION.to_f < 1.9

			#doui() 同意する
			form = @m.page.forms_with(:name=>"form1").first
			form.action = form.action+"&root_GKHCGW001SubmitAgree="
			form.submit
			#ダウンロード
			form = @m.page.forms_with( :name=>"form1")
			form = @m.page.forms_with(:name=>"form1").first
			form.action = form.action+"&root_GKHCGW001SubmitAgree="
			form.action = form.action+"&BisAutoSubmissionREQUEST="
			form.submit
			# 再び、強制変換オン
			self.enable_force_encoding
			return {"file_name" => "docomo-#{y_m}-gaiyo.pdf", "body"=> @m.page.body , "month" => y_m }
		end

		def latest_ryokin_gaiyou # go
			# 一括料金表示ページを解析
			#直近で請求が確定している月

			table =  @m.page.search('table.new-amountclaimschedule').last
			year_month = table.search("tr th p.strong")[1]
			year_month = year_month.text()
			q =  table.search("tr img[alt='お知らせ']").first["onclick"][/setSeikyuNengtsu\('(\d+)'\)/, 1]
			#puts q
			form = @m.page.forms_with(:name=>"form1").first
			form.action = form.action+"&root_GKFAGW001SubmitSeikyuGaiyou="
			form.fields_with(:name=>"root_GKFAGW001_HIBUTTONNENGETU").first.value = q
			form.submit
			#@m.page.body = @m.page.body.toutf8
			#puts @m.page.body

			year_month
		end






		def get_latest_pdf_download
			# 最新の料金の概要と明細をダウンロードして、1枚のPDFに結合する

			# 料金概要
			gaiyo = nil
			gaiyo = self.get_latest_gaiyo_pdf
			## # ファイル保存
			open(gaiyo["file_name"], "w"){|f| f.print gaiyo["body"] }

			#y_m = gaiyo["month"];
			gaiyo_path = gaiyo["file_name"]


			# 明細を取得する
			meisai = nil
			meisai = self.get_latest_meisai_pdf

			meisai_path = meisai["file_name"]

			# ファイルの保存
			open(meisai["file_name"], "w"){|f| f.print meisai["body"] }
			y_m = meisai["month"];

			out_path = "docomo-#{y_m}.pdf"


			#puts cmd = "/usr/bin/env pdftk #{gaiyo_path} #{meisai_path} cat output #{out_path} "
			`/usr/bin/env pdftk #{gaiyo_path} #{meisai_path} cat output #{out_path} `

			body = open(out_path).read

			File.unlink meisai_path
			File.unlink gaiyo_path
			File.unlink out_path
			return { "file_name"=> out_path, "month" => "#{y_m}", "body"=>body }
		end
		def go_home()
			@m.get "https://www.mydocomo.com/dcm/dfw/web/pub3/r/header/home.html"
			self.go_through_refresh_page
		end


	end

end

if $0 == __FILE__ then

# docomo = BillScraper::cMyDoCoMo.new "0901234567","password"
# docomo.login
end

実行サンプル

以下のようにすることでEvernoteに送信できる

#!/usr/bin/env ruby
#coding:utf-8
require 'rubygems'
$:.unshift "/usr/local/lib/site_ruby/1.9.1/local/scrapers/lib/"
require "scrapers"
require "scrapers/docomo"


docomo = BillScraper::MyDoCoMo.new "090xxxxxxxx", "xxPasswordxx"
docomo.login
ret = docomo.get_latest_pdf_download

out_path = ret["file_name"]
open(ret["file_name"], "w"){|f| f.print ret["body"] }

name = File.basename out_path, ".pdf"


gem "mail" , "< 2.5.3 "
require 'mail'

options = { :address              => "smtp.gmail.com",
            :port                 => 587,
            :user_name            => 'takuya@xxxx.xx',
            :password             => 'xxxxpasswordxxxx',
            :authentication       => 'plain',
            :enable_starttls_auto => true  }



Mail.defaults do
  delivery_method :smtp, options
end
mail = Mail.new do
  from     'takuya@xxxx.xxx'
  to       'takuyaxxxx@m.evernote.com'
  subject  "docomo 料金 [#{name}] #アカウント"
  body      "メール経由。"
  add_file :filename => out_path, :content => File.read(out_path)
end

mail.deliver!

File.unlink out_path


puts :end

2013-11-19 追記

複数枚のPDF(表紙と明細)をまとめるので pdftk をシェル呼び出して使っていあmス。
利用にはpdftk が必要。