-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.rb
executable file
·218 lines (201 loc) · 7.67 KB
/
main.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# frozen_string_literal: true
require 'bundler/setup'
require 'rubygems'
require 'net/http'
require 'nokogiri'
require 'open-uri'
require 'csv'
require 'yaml'
# 検索画面全般の処理
class SearchPagedisplay
def initialize(config_path = './config.yml')
puts 'Init...'
@access_page = 'https://www.hellowork.mhlw.go.jp/kensaku/GECA110010.do'
@job_offer_page_dir = 'https://www.hellowork.mhlw.go.jp/kensaku/'
@sleep_time = 3 # 岡崎市立中央図書館事件対策
@job_offer_url_list = [] # 求人情報詳細画面のURLリスト
@display_count_to_page = 10
@config = YAML.load_file(config_path)
@param_const = @config['param_const'] # 定数やシステムによって変更されるパラメーター類
@param_list = @config['param_list'] # 検索条件
@param_list2 = @config['param_list2'] # 詳細検索条件
end
def create_url_parm(key, value)
# config.ymlの検索条件の整形
# Array, String, Integer, NilClassの形式をURLパラメータとして整形。
# 空白(条件指定なし)は検索条件として省略できるので''を返す。
case value
when Array
# Array
if value.empty?
output_parm = ''
else
connected_parm = ''
value.each do |var|
connected_parm += key + '=' + var.to_s + '&'
end
output_parm = connected_parm
end
when String
# String
#
output_parm = if value.empty?
''
else
# ASCII文字以外はURLパラメータとして使えないので、エンコード。
key + '=' + URI.encode_www_form_component(value) + '&'
end
when Integer
# Integer
output_parm = key + '=' + value.to_s + '&'
when NilClass
# NilClass
output_parm = ''
end
output_parm
end
def param_creater(hash)
# URLパラメータの作成。
# 型判別が思ったより長くなったので隔離。
param = ''
hash.each do |key, value|
param += create_url_parm(key, value)
end
param
end
def url_generator(mode = 1)
# 初回の検索画面では詳細検索条件まで指定しないと正しく検索されないが、
# 2ページ目以降は詳細検索条件を指定すると正しく検索されなくなる。
# 初回を1,2ページ目以降を2とし、詳細検索条件の有無を切り替える。
case mode
when 1
url = @access_page + '?' + param_creater(@param_const) + param_creater(@param_list) + param_creater(@param_list2).chop!
puts "検索結果URL: #{url}"
when 2
url = @access_page + '?' + param_creater(@param_const) + param_creater(@param_list).chop!
end
url
end
def get_cookie(url)
# 初回の検索時にクッキーが発行され、それを使うことで詳細検索条件を指定せずとも
# 2ページ目以降の検索結果を表示することが出来る。
# 未調査: 一般に公開していない求人情報の表示にも必要?
res = Net::HTTP.get_response(URI(displayurl))
sleep @sleep_time
@cookie = res['set-Cookie']
puts "Cookie: #{@cookie}"
@cookie
end
def parse_result_num(url)
# 検索件数を取得する関数。
page = Nokogiri::HTML.parse(URI.open(url))
sleep @sleep_time
nodes = page.css('div.m05 > span.fb')
@index_num = nodes.text.scan(/(\d+)/)[0].join('').to_i # 検索結果の件数を取ってくる。
@index_max_num = (@index_num / @display_count_to_page.to_f).ceil # 最大ページ数を計算。
puts "検索結果: #{@index_num}件"
puts "検索ページ数: #{@index_max_num}ページ"
@index_num
end
def make_seach_url_array
# 検索結果ページのURLを一つの配列にまとめ、後でForでぶん回す
@url_array = []
1.upto(@index_max_num) do |page_no|
@param_const['fwListNaviBtnNext'] = '次へ>'
@param_const['kyujinkensu'] = @index_num
@param_const['fwListNowPage'] = page_no - 1
@param_const['fwListNaviCount'] = page_no + 5
@param_const['searchBtn'] = ''
@url_array.push url_generator(2)
end
@url_array
end
def parse_result_url
# 検索結果ページにアクセスし、その中の求人情報ページのリンクを取得し、別の配列に追加する。
job_offer_url_list = []
@url_array.each do |url|
document = Nokogiri::HTML.parse(URI.open(url, 'Cookie' => @cookie))
sleep @sleep_time
document.css('div.flex a#ID_dispDetailBtn').each do |anchor|
page_url = @job_offer_page_dir + anchor[:href].delete_prefix!('./')
job_offer_url_list.push(page_url)
end
end
job_offer_url_list
end
end
# 求人情報画面全般の処理
class JobPage
def initialize(cookie, max_count)
@csv_hash = []
@csv_hash[0] = eval File.read 'job_info.rb'
@csv_array = []
@sleep_time = 3
@cookie = cookie
@max_count = max_count
end
def string_scraper(url)
# 求人情報ページの各種情報を取得。
# CSVにしたときにトラブらないように、制御文字等を予め削除しおく。
# 連想配列で出力
document = Nokogiri::HTML.parse(URI.open(url, 'Cookie' => @cookie))
output = {}
@csv_hash[0].each_key do |key|
value = document.css('#' + key).text.gsub(/\r\n|\r|\n|\s|\t/, '')
output[key] = value
end
output
end
def page_accesser(list)
# 求人情報にアクセスする際の親関数。
# string_scraperで得た連想配列を配列に追加。
puts '求人ページから情報を取得しています…'
hash_index = 1
list.each do |url|
@csv_hash[hash_index] = string_scraper(url)
hash_index += 1
progress(hash_index)
sleep @sleep_time
end
end
def generate_csv
# 配列からCSV形式に整形
puts 'CSVに変換しています...'
array_index = 0
@csv_hash.map do |value|
value = value.values
@csv_array[array_index] = value
array_index += 1
end
puts 'CSVへの変換が完了しました。'
end
def save_csv(filename = 'output.csv')
# 出力
CSV.open(filename, 'w') do |csv|
@csv_array.each do |bo|
csv << bo
end
end
puts "#{filename} に保存されました。"
end
def progress(count)
# 進捗状況確認用の雑実装プログレスバー
count -= 1
percent = count / @max_count.to_f * 100
scale = 2
bar = percent / scale
hide_bar = 100 / scale - bar.floor
print "\r#{count}件目 [#{'=' * bar}#{' ' * hide_bar}] #{percent.floor(1)}%完了"
puts '' if count == @max_count
end
end
main = SearchPage.new
result_url = main.url_generator
cookie = main.get_cookie(result_url)
result_num = main.parse_result_num(result_url)
main.make_seach_url_array
url_list = main.parse_result_url
main = JobPage.new(cookie, result_num)
main.page_accesser(url_list)
main.generate_csv
main.save_csv