gscomp 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ *.gem
2
+ <<<<<<< HEAD
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
6
+ =======
7
+ *.rbc
8
+ .bundle
9
+ .config
10
+ coverage
11
+ InstalledFiles
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+
20
+ # YARD artifacts
21
+ .yardoc
22
+ _yardoc
23
+ doc/
24
+ >>>>>>> 9632f3f284daadba0f9055f01f538b1f2b5e6dd3
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in gscomp.gemspec
4
+ gemspec
5
+
6
+ gem nokogiri
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ gscomp
2
+ ======
3
+
4
+ gscomp
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/gscomp ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ system("gem install gscomp")
4
+
5
+ require 'gscomp'
6
+
7
+ tt = Gscomp::Taras.new()
8
+ tt.main()
data/gscomp.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "gscomp/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "gscomp"
7
+ s.version = Gscomp::VERSION
8
+ s.authors = ["Global System"]
9
+ s.email = ["gs@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{GS computation}
12
+ s.description = %q{GS computation}
13
+
14
+ s.rubyforge_project = "gscomp"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ # s.add_runtime_dependency "rest-client"
24
+ end
@@ -0,0 +1,3 @@
1
+ module Gscomp
2
+ VERSION = "0.0.1"
3
+ end
data/lib/gscomp.rb ADDED
@@ -0,0 +1,305 @@
1
+ # encoding: utf-8
2
+ require "gscomp/version"
3
+
4
+ require 'rubygems'
5
+ require 'nokogiri'
6
+ require 'open-uri'
7
+ require 'net/https'
8
+ require 'net/http'
9
+ require 'json'
10
+ require 'gtk2'
11
+
12
+
13
+ module Gscomp
14
+ class Taras
15
+ private
16
+ def initialize
17
+ # Разрешаем отображение окна со всеми дочерними элементами
18
+ @status = Gtk::StatusIcon.new
19
+ @status.stock = Gtk::Stock::EXECUTE
20
+ @status.tooltip = "Обработчик данных GS"
21
+
22
+ # Связывание сигналов иконки с обработчиками
23
+ @status.signal_connect('activate') { on_activate }
24
+ @status.signal_connect('popup-menu') {|statusicon, button, time| on_right_click statusicon, button, time }
25
+
26
+ # Создание меню
27
+ @menu = Gtk::Menu.new
28
+ @menu.append(preferences = Gtk::ImageMenuItem.new(Gtk::Stock::PREFERENCES))
29
+ @menu.append(about = Gtk::ImageMenuItem.new(Gtk::Stock::ABOUT))
30
+ @menu.append(Gtk::SeparatorMenuItem.new)
31
+ @menu.append(quit = Gtk::ImageMenuItem.new(Gtk::Stock::QUIT))
32
+
33
+ # Связывание обработчиков с пунктами меню
34
+ preferences.signal_connect('activate') { on_click_preferences }
35
+ about.signal_connect('activate') { on_click_about }
36
+ quit.signal_connect('activate') { Gtk.main_quit }
37
+
38
+ # @window = Gtk::Window.new
39
+ # @window.border_width = 10
40
+ # @window.signal_connect('delete_event') { @window.hide_all; true }
41
+
42
+ @processed = 0
43
+ @power = 3
44
+ end
45
+ protected
46
+ def on_right_click(statusicon, button, time)
47
+ @menu.popup(nil, nil, button, time) {|menu, x, y, push_in| @status.position_menu(@menu)}
48
+ @menu.show_all
49
+ @menu.reposition
50
+ end
51
+
52
+ def on_click_preferences
53
+ pref = Gtk::Dialog.new(
54
+ "Параметры",
55
+ nil,
56
+ Gtk::Dialog::MODAL,
57
+ [ Gtk::Stock::APPLY, Gtk::Dialog::RESPONSE_APPLY ],
58
+ [ Gtk::Stock::CLOSE, Gtk::Dialog::RESPONSE_CLOSE ]
59
+ )
60
+ pref.default_response = Gtk::Dialog::RESPONSE_APPLY
61
+
62
+ label = Gtk::Label.new ("Нагрузка:")
63
+ hscale = Gtk::HScale.new(10, 100, 10)
64
+ hscale.width_request = 350
65
+ hscale.value = @power * 10
66
+ table = Gtk::Table.new(1, 2)
67
+ table.attach_defaults(label, 0, 1, 0, 1)
68
+ table.attach_defaults(hscale, 1, 2, 0, 1)
69
+ table.row_spacings = 5
70
+ table.column_spacings = 5
71
+ table.border_width = 10
72
+ pref.vbox.add table
73
+ pref.show_all
74
+
75
+ exit = true
76
+ while exit do
77
+ pref.run do |response|
78
+ case response
79
+ when Gtk::Dialog::RESPONSE_APPLY
80
+ @power = hscale.value / 10
81
+ when Gtk::Dialog::RESPONSE_CLOSE
82
+ exit = false
83
+ end
84
+ end
85
+ end
86
+ pref.destroy
87
+
88
+ end
89
+
90
+ def on_click_about
91
+ about = Gtk::AboutDialog.new
92
+ about.name = "GSComp"
93
+ about.version = "0.0.1"
94
+ about.copyright = "(c) Global System, 2012"
95
+ about.comments = "Программа является частью распределенной сети обработки данных"
96
+ about.signal_connect('response') { about.destroy }
97
+ about.show_all
98
+ end
99
+
100
+ def on_activate
101
+ # @window.show_all
102
+ end
103
+
104
+ # Инициализация
105
+ def get_client_id
106
+ # Регистрация на сервере
107
+ uri = URI.parse('http://localhost:3000/idfactory')
108
+ uri.user = 'tester'
109
+ uri.password = 'qwzxas'
110
+ begin
111
+ Net::HTTP.get(uri)
112
+ rescue
113
+ nil
114
+ end
115
+ end
116
+
117
+ # Запрос задания
118
+ def get_job (client_id)
119
+ uri = URI.parse('http://localhost:3000/products')
120
+ uri.user = 'tester'
121
+ uri.password = 'qwzxas'
122
+ uri.query = URI.encode_www_form({:id => client_id})
123
+ begin
124
+ JSON::parse(Net::HTTP.get(uri))
125
+ rescue
126
+ nil
127
+ end
128
+ end
129
+
130
+ # Выбрать название товара
131
+ def get_product_name(node = nil, recurse_level = 0)
132
+ # Выйти если рекурсия достигла предела
133
+ return if (recurse_level == 0)
134
+
135
+ n = node
136
+ images = nil
137
+ recurse_level.times do
138
+ break unless (images = n.css("a img")).nil?
139
+ n = n.parent
140
+ end
141
+
142
+ # images = node.css("a img")
143
+ result = []
144
+ node.css("a").each do |x|
145
+ weight = 0
146
+ # Признак: цифры в ссылке (обычно это id товара)
147
+ weight += 1 if (not x["href"].nil?) and x["href"].partition(/\d{0,}/)[1].length > 0
148
+ # Признак: цифры, -, () в названии товара
149
+ weight += 10 if x.content.partition(/[\-\.\(\)\d+\"]/u)[1].length > 0
150
+ # Признак: ссылка в картинке совпадает с ссылкой в названии товара
151
+ weight += 100 if (not images.nil?) and (images.map { |i| i.parent["href"] == x["href"] }).find_index(true)
152
+ # Если сработал хотя-бы один признак записать результат
153
+ result << {:content => x.content, :weight => weight, :href => x["href"]} if weight >= 10
154
+ end
155
+
156
+
157
+ max = {:weight => 0}
158
+ result.each do |i|
159
+ max = i if i[:weight] > max[:weight]
160
+ end
161
+
162
+ # puts result.to_s
163
+ return max if max[:weight] > 10
164
+
165
+ # Выйти если признаки не обнаружены
166
+ # return result if (not result[:content].nil?) and result[:content].length > 0
167
+
168
+ # Если названий нет, то переместиться выше
169
+ get_product_name node.parent, recurse_level - 1
170
+ end
171
+
172
+ # Выбрать цену товара
173
+ def get_product_price(node = nil, recurse_level = 0, result = {:price => "", :currency => ""})
174
+ # Выйти если рекурсия достигла предела
175
+ return result if (recurse_level == 0)
176
+
177
+ # Выбрать суммы
178
+ node.parent.children.each do |n|
179
+ result[:price] = n.content.partition(/(?i)\d+.*\.{0,}\,{0,}\d{2}+/)[1].gsub(/\s/,'') if result[:price].length == 0
180
+ result[:currency] = n.content.partition(/(?i)\b\D{3}\b/)[1] if result[:currency].length == 0
181
+
182
+ exit =
183
+ (not result[:price].length == 0) and
184
+ (not result[:currency].length == 0)
185
+ return result if exit
186
+ end
187
+ # Если сумм нет, то переместиться на уровень выше
188
+ get_product_price node.parent, recurse_level - 1, result
189
+ end
190
+
191
+ # Загузить содежимое станицы по URL
192
+ def html_get(uri)
193
+ page = nil
194
+ begin
195
+ Timeout::timeout(80) do
196
+ open(URI(uri), {:redirect => true, :read_timeout => 60}) do |cite|
197
+ # Получть заголовок
198
+ cite.meta
199
+ break unless cite.content_type["text/html"]
200
+ page = cite.read
201
+ end
202
+ # @debug_log.debug "Страница #{uri} загружена успешно..."
203
+ end
204
+ rescue Exception => err
205
+ # error = "file: #{__FILE__} line: #{__LINE__} comment: load html page '#{uri.to_s}'; #{err}"
206
+ # @log.error error
207
+ return nil
208
+ end
209
+ return page
210
+ end
211
+
212
+
213
+ # Обработка задания
214
+ def process_job(job)
215
+ records = job['records']
216
+
217
+ prices = []
218
+ records.each do |r|
219
+ # @debug_log.debug "Обработка страницы: #{url.to_s}"
220
+
221
+ html_data = html_get(r['link'])
222
+ # puts r['link']
223
+ # Парсинг страницы
224
+ data = html_data.to_s.force_encoding('UTF-8').encode("utf-16be", :undef => :replace, :invalid => :replace, :replace => "?").encode("utf-8", :undef => :replace, :invalid => :replace, :replace => "?")
225
+ html = Nokogiri::HTML(data, nil, 'UTF-8')
226
+ html.search('script').remove
227
+
228
+ # Выбрать все ноды содержимое которых = грн.
229
+ nodes = html.css("[text()*='грн.']")
230
+
231
+ # Попытаться попдобрать цены и название товаров
232
+ nodes.each do |node|
233
+ name = get_product_name(node, 7)
234
+ price = get_product_price(node, 2)
235
+
236
+ # next if name.length == 0 or price.length == 0
237
+
238
+ prices << {
239
+ :name => name.nil? ? '' : name,
240
+ :price => price.nil? ? '' : price[:price],
241
+ :currency => price.nil? ? '' : price[:currency],
242
+ :page_id => r['page_id'].to_s,
243
+ :link => r['link']
244
+ }
245
+ end
246
+ @processed += 1
247
+ end
248
+ return prices
249
+ end
250
+
251
+ # Отправка результатов
252
+ def send_job(result)
253
+ uri = URI.parse('http://localhost:3000/products')
254
+ uri.user = 'tester'
255
+ uri.password = 'qwzxas'
256
+ return Net::HTTP.post_form(uri, {:result => result.to_json})
257
+ end
258
+ public
259
+ def process_packet
260
+ sleep 1 while not (client_id = get_client_id())
261
+ #puts client_id
262
+
263
+ attempt = 10
264
+ sleep 1 while not (job = get_job(client_id) and attempt -= 1)
265
+ false unless job
266
+ # puts job
267
+
268
+ records = process_job(job)
269
+ # puts records
270
+
271
+ result = {
272
+ :client_id => client_id,
273
+ :records_count => records.length,
274
+ :records => records
275
+ }
276
+
277
+ send_result = send_job(result)
278
+ case send_result
279
+ when Net::HTTPSuccess, Net::HTTPRedirection
280
+ p 'Good'
281
+ else
282
+ # p result.error
283
+ end
284
+ end
285
+
286
+ def main
287
+ uu = Thread.new do
288
+ # Запускаем цикл обработки событий
289
+ loop do
290
+ process_packet()
291
+ sleep @power
292
+ end
293
+ end
294
+
295
+ GLib::Timeout.add(1000) { on_timer }
296
+
297
+ Gtk.main
298
+ end
299
+
300
+ def on_timer
301
+ @status.tooltip = "Global System\nОбработано: #{@processed.to_s} единц"
302
+ true
303
+ end
304
+ end
305
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gscomp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Global System
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-16 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: GS computation
15
+ email:
16
+ - gs@gmail.com
17
+ executables:
18
+ - gscomp
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - README.md
25
+ - Rakefile
26
+ - bin/gscomp
27
+ - gscomp.gemspec
28
+ - lib/gscomp.rb
29
+ - lib/gscomp/version.rb
30
+ homepage: ''
31
+ licenses: []
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubyforge_project: gscomp
50
+ rubygems_version: 1.8.17
51
+ signing_key:
52
+ specification_version: 3
53
+ summary: GS computation
54
+ test_files: []