mizuho_bank 0.1.1 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +11 -1
- data/VERSION +1 -1
- data/lib/mizuho_bank.rb +154 -6
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -6,7 +6,6 @@
|
|
6
6
|
== 使い方 (こんな感じで)
|
7
7
|
|
8
8
|
# encoding: utf-8
|
9
|
-
Encoding.default_external = Encoding.default_internal = "UTF-8"
|
10
9
|
require 'mizuho_bank'
|
11
10
|
require 'pit'
|
12
11
|
|
@@ -31,6 +30,17 @@
|
|
31
30
|
p bank.info.main_account.money
|
32
31
|
}
|
33
32
|
|
33
|
+
== 用例集
|
34
|
+
1. 口座残高取得したいとき
|
35
|
+
bank.info.main_account.money
|
36
|
+
|
37
|
+
2. 最近の取引履歴を配列で取得したいとき
|
38
|
+
bank.info.main_account.cache_flows
|
39
|
+
|
40
|
+
3. 口座番号とか種別しりたいとき
|
41
|
+
bank.info.main_account.number
|
42
|
+
bank.info.main_account.type
|
43
|
+
|
34
44
|
== 既知の問題
|
35
45
|
まだ画像認証に対応してない。画像認証は秘密の質問に失敗しまくってるとやらなきゃいけなくなる
|
36
46
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.3
|
data/lib/mizuho_bank.rb
CHANGED
@@ -4,6 +4,8 @@ require 'kconv'
|
|
4
4
|
require 'logger'
|
5
5
|
require 'retry-handler'
|
6
6
|
require 'moji'
|
7
|
+
require 'chronic'
|
8
|
+
require 'open-uri'
|
7
9
|
|
8
10
|
# utility class
|
9
11
|
class String
|
@@ -12,12 +14,6 @@ class String
|
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
15
|
-
class Time
|
16
|
-
def self.mizuho_time_parse(string)
|
17
|
-
p string
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
17
|
class Integer
|
22
18
|
def humanize
|
23
19
|
case
|
@@ -42,12 +38,39 @@ class MizuhoBank
|
|
42
38
|
@logger = Logger.new(nil)
|
43
39
|
@logger = logger unless logger.nil?
|
44
40
|
|
41
|
+
unless MizuhoBank.is_available?
|
42
|
+
raise "MizuhoBank is not available"
|
43
|
+
end
|
44
|
+
|
45
45
|
if login(keiyaku_no, password, aikotoba_dict)
|
46
46
|
block.call(self) if block_given?
|
47
47
|
end
|
48
48
|
self
|
49
49
|
end
|
50
50
|
|
51
|
+
def self.new_with_pit(logger = nil, &block)
|
52
|
+
pit = Pit.get("MizuhoBank",
|
53
|
+
:require => {
|
54
|
+
"keiyaku_no" => "keiyaku_no",
|
55
|
+
"password" => "password",
|
56
|
+
"aikotoba1_question" => "aikotoba1_question",
|
57
|
+
"aikotoba2_question" => "aikotoba2_question",
|
58
|
+
"aikotoba3_question" => "aikotoba3_question",
|
59
|
+
"aikotoba1_answer" => "aikotoba1_answer",
|
60
|
+
"aikotoba2_answer" => "aikotoba2_answer",
|
61
|
+
"aikotoba3_answer" => "aikotoba3_answer",
|
62
|
+
})
|
63
|
+
|
64
|
+
aikotoba_dict = {
|
65
|
+
pit['aikotoba1_question'] => pit['aikotoba1_answer'],
|
66
|
+
pit['aikotoba2_question'] => pit['aikotoba2_answer'],
|
67
|
+
pit['aikotoba3_question'] => pit['aikotoba3_answer']
|
68
|
+
}
|
69
|
+
self.new(pit['keiyaku_no'].to_s, pit['password'].to_s, aikotoba_dict, logger){ |bank|
|
70
|
+
block.call(bank)
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
51
74
|
def login(keiyaku_no, password, aikotoba_dict={})
|
52
75
|
@login_result = false
|
53
76
|
Proc.new do
|
@@ -72,6 +95,8 @@ class MizuhoBank
|
|
72
95
|
auth_password(password)
|
73
96
|
when :logout_fail_info
|
74
97
|
raise "Logout fail info page!!"
|
98
|
+
when :not_available_page
|
99
|
+
raise "not available page"
|
75
100
|
when :unknown
|
76
101
|
@logger.info "unknown page reached: #{@agent.page.title}"
|
77
102
|
@login_result = true
|
@@ -88,6 +113,123 @@ class MizuhoBank
|
|
88
113
|
@login_result
|
89
114
|
end
|
90
115
|
|
116
|
+
def self.is_available?(time = Time.now)
|
117
|
+
get_jikangai_ranges(time).each{ |range|
|
118
|
+
if range.cover? time
|
119
|
+
return false
|
120
|
+
end
|
121
|
+
}
|
122
|
+
return true
|
123
|
+
end
|
124
|
+
|
125
|
+
class RepeatDate
|
126
|
+
attr_accessor :wday
|
127
|
+
attr_accessor :hour
|
128
|
+
attr_accessor :minute
|
129
|
+
|
130
|
+
def to_s
|
131
|
+
if @wday.nil?
|
132
|
+
"%02d:%02d" % [@hour, @minute]
|
133
|
+
else
|
134
|
+
"%s %02d:%02d" % [wday, @hour, @minute]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class RepeatDateRange
|
140
|
+
attr_accessor :start
|
141
|
+
attr_accessor :end
|
142
|
+
|
143
|
+
def initialize
|
144
|
+
@start = RepeatDate.new
|
145
|
+
@end = RepeatDate.new
|
146
|
+
end
|
147
|
+
|
148
|
+
def cover? (time, context = Time.now)
|
149
|
+
s = start_time(context)
|
150
|
+
e = end_time(s)
|
151
|
+
(s .. e).cover? (time)
|
152
|
+
end
|
153
|
+
|
154
|
+
def include? (*args)
|
155
|
+
cover? *args
|
156
|
+
end
|
157
|
+
|
158
|
+
def start_time(context = Time.now)
|
159
|
+
Chronic.parse(translate_in_this_month(@start.to_s, context), :now => context)
|
160
|
+
end
|
161
|
+
|
162
|
+
def end_time(context = Time.now)
|
163
|
+
Chronic.parse(translate_in_this_month(@end.to_s, context), :now => context)
|
164
|
+
end
|
165
|
+
|
166
|
+
def translate_in_this_month(text, context=Time.now)
|
167
|
+
if text.match(/(.*?)(.+) (.+) in this month(.*)/)
|
168
|
+
month = context.strftime("%B")
|
169
|
+
previous = Regexp.last_match(1)
|
170
|
+
n = Regexp.last_match(2)
|
171
|
+
wday = Regexp.last_match(3)
|
172
|
+
last = Regexp.last_match(4)
|
173
|
+
|
174
|
+
time = Chronic.parse("#{n} #{wday} in #{month}")
|
175
|
+
time.strftime("#{previous} %Y/%m/%d #{last}")
|
176
|
+
else
|
177
|
+
text
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def to_s(context = Time.now)
|
182
|
+
s = start_time(context)
|
183
|
+
e = end_time(s)
|
184
|
+
"#{s} - #{e}"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def self.get_jikangai_ranges(context = Time.now)
|
189
|
+
url = "http://www.mizuhobank.co.jp/direct/jikangai.html"
|
190
|
+
body = open(url).read.toutf8
|
191
|
+
doc = Nokogiri(body)
|
192
|
+
unless body.include? "以下の時間帯は、インターネットバンキングをご利用いただけません。"
|
193
|
+
raise "page format error"
|
194
|
+
end
|
195
|
+
|
196
|
+
dates = doc.search("#contents > div.section > div.inner > table :first-child > th > ul.normal > li > strong").map(&:text)
|
197
|
+
|
198
|
+
ranges = []
|
199
|
+
if dates.first =~ /土曜日(\d+)時(\d+)分~翌日曜日(\d+)時(\d+)分/
|
200
|
+
range = RepeatDateRange.new
|
201
|
+
range.start.wday = "last saturday"
|
202
|
+
range.start.hour = Regexp.last_match(1).to_i
|
203
|
+
range.start.minute = Regexp.last_match(2).to_i
|
204
|
+
range.end.wday = "next sunday"
|
205
|
+
range.end.hour = Regexp.last_match(3).to_i
|
206
|
+
range.end.minute = Regexp.last_match(4).to_i
|
207
|
+
ranges << range
|
208
|
+
end
|
209
|
+
|
210
|
+
if dates.second =~ /第1・第4土曜日(\d+)時(\d+)分~(\d+)時(\d+)分/
|
211
|
+
range = RepeatDateRange.new
|
212
|
+
range.start.wday = "1st saturday in this month"
|
213
|
+
range.start.hour = Regexp.last_match(1).to_i
|
214
|
+
range.start.minute = Regexp.last_match(2).to_i
|
215
|
+
range.end.wday = nil
|
216
|
+
range.end.hour = Regexp.last_match(3).to_i
|
217
|
+
range.end.minute = Regexp.last_match(4).to_i
|
218
|
+
ranges << range
|
219
|
+
|
220
|
+
range = RepeatDateRange.new
|
221
|
+
range.start.wday = "4th saturday in this month"
|
222
|
+
range.start.hour = Regexp.last_match(1).to_i
|
223
|
+
range.start.minute = Regexp.last_match(2).to_i
|
224
|
+
range.end.wday = nil
|
225
|
+
range.end.hour = Regexp.last_match(3).to_i
|
226
|
+
range.end.minute = Regexp.last_match(4).to_i
|
227
|
+
ranges << range
|
228
|
+
end
|
229
|
+
|
230
|
+
ranges
|
231
|
+
end
|
232
|
+
|
91
233
|
private
|
92
234
|
# 契約者番号の認証ページ処理
|
93
235
|
def is_auth_keiyaku_no_page?
|
@@ -137,6 +279,10 @@ class MizuhoBank
|
|
137
279
|
@agent.page.body.toutf8.include? "ログインできませんでした。前回の操作で正しくログアウトされていない可能性があります。"
|
138
280
|
end
|
139
281
|
|
282
|
+
def is_not_available_page?
|
283
|
+
@agent.page.body.toutf8.include? "以下の時間帯は、インターネットバンキングをご利用いただけません"
|
284
|
+
end
|
285
|
+
|
140
286
|
def auth_password(password)
|
141
287
|
@agent.page.form_with(:name => 'FORM1'){ |f|
|
142
288
|
f.field_with(:name => 'Anshu1No').value = password.tosjis
|
@@ -157,6 +303,8 @@ class MizuhoBank
|
|
157
303
|
return :auth_password
|
158
304
|
elsif is_auth_keiyaku_no_page?
|
159
305
|
return :auth_keiyaku_no
|
306
|
+
elsif is_not_available_page?
|
307
|
+
return :not_available
|
160
308
|
else
|
161
309
|
return :unknown
|
162
310
|
end
|