market_bot 0.17.0 → 1.0.0

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/Guardfile +70 -0
  4. data/README.markdown +45 -95
  5. data/Rakefile +0 -89
  6. data/bin/app_categories +17 -0
  7. data/bin/benchmark_parser_app +24 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +7 -0
  10. data/bin/update_test_data +30 -0
  11. data/lib/market_bot.rb +20 -15
  12. data/lib/market_bot/exceptions.rb +2 -1
  13. data/lib/market_bot/play/app.rb +188 -0
  14. data/lib/market_bot/play/app/constants.rb +33 -0
  15. data/lib/market_bot/play/chart.rb +118 -0
  16. data/lib/market_bot/play/chart/constants.rb +74 -0
  17. data/lib/market_bot/play/constants.rb +7 -0
  18. data/lib/market_bot/play/developer.rb +32 -0
  19. data/lib/market_bot/util.rb +17 -0
  20. data/lib/market_bot/version.rb +1 -1
  21. data/market_bot.gemspec +6 -3
  22. data/spec/market_bot/play/app_spec.rb +201 -0
  23. data/spec/market_bot/play/chart_spec.rb +126 -0
  24. data/spec/market_bot/play/data/app-com.bluefroggaming.popdat.txt +99 -0
  25. data/spec/market_bot/play/data/app-com.mg.android.txt +103 -0
  26. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-0.txt +97 -0
  27. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-1.txt +97 -0
  28. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-2.txt +97 -0
  29. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-3.txt +97 -0
  30. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-4.txt +97 -0
  31. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-5.txt +97 -0
  32. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-6.txt +97 -0
  33. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-7.txt +97 -0
  34. data/spec/market_bot/play/data/developer-zynga.txt +97 -0
  35. data/spec/market_bot/play/developer_spec.rb +52 -0
  36. data/spec/market_bot_spec.rb +14 -0
  37. data/spec/spec_helper.rb +5 -11
  38. metadata +57 -52
  39. data/NOTES.txt +0 -61
  40. data/lib/market_bot/android/app.rb +0 -273
  41. data/lib/market_bot/android/developer.rb +0 -32
  42. data/lib/market_bot/android/leaderboard.rb +0 -232
  43. data/lib/market_bot/android/leaderboard/constants.rb +0 -59
  44. data/lib/market_bot/android/search_query.rb +0 -35
  45. data/lib/market_bot/movie/leaderboard.rb +0 -167
  46. data/lib/market_bot/movie/leaderboard/constants.rb +0 -30
  47. data/lib/market_bot/movie/search_query.rb +0 -32
  48. data/spec/market_bot/android/app_spec.rb +0 -253
  49. data/spec/market_bot/android/data/app_1.txt +0 -99
  50. data/spec/market_bot/android/data/app_2.txt +0 -100
  51. data/spec/market_bot/android/data/app_3.txt +0 -103
  52. data/spec/market_bot/android/data/app_4.txt +0 -117
  53. data/spec/market_bot/android/data/developer-zynga.txt +0 -97
  54. data/spec/market_bot/android/data/leaderboard-apps_editors_choice.txt +0 -97
  55. data/spec/market_bot/android/data/leaderboard-apps_topselling_paid-page1.txt +0 -97
  56. data/spec/market_bot/android/data/leaderboard-apps_topselling_paid-page2.txt +0 -97
  57. data/spec/market_bot/android/data/leaderboard-apps_topselling_paid-page3.txt +0 -97
  58. data/spec/market_bot/android/data/leaderboard-apps_topselling_paid-page4.txt +0 -97
  59. data/spec/market_bot/android/developer_spec.rb +0 -57
  60. data/spec/market_bot/android/leaderboard_spec.rb +0 -140
  61. data/spec/market_bot/android/search_query_spec.rb +0 -6
  62. data/spec/market_bot/movie/data/leaderboard-movies_comedy_topselling_paid.txt +0 -327
  63. data/spec/market_bot/movie/leaderboard_spec.rb +0 -67
@@ -0,0 +1,52 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
2
+
3
+ describe MarketBot::Play::Developer do
4
+ shared_context('parsing a developer') do
5
+ it 'should be a valid length' do
6
+ expect(@parsed.length).to be > 1
7
+ end
8
+
9
+ it 'should have attributes' do
10
+ expect(@parsed).to all(have_key(:package)).and \
11
+ all(have_key(:title)).and all(have_key(:store_url)).and \
12
+ all(have_key(:developer)).and all(have_key(:icon_url))
13
+ end
14
+ end
15
+
16
+ describe "(zynga)" do
17
+ include_context 'parsing a developer'
18
+
19
+ before(:all) do
20
+ @name = 'zynga'
21
+ @html = read_play_data('developer-zynga.txt')
22
+ @parsed = MarketBot::Play::Chart.parse(@html)
23
+ end
24
+ end
25
+
26
+ it 'should generate store_urls' do
27
+ name ='zynga'
28
+ dev = MarketBot::Play::Developer.new(name)
29
+
30
+ expect(dev.store_urls.length).to eq(1)
31
+
32
+ dev.store_urls.each_with_index do |url, i|
33
+ msg = "i=#{i}, url=#{url}"
34
+ pattern = /\Ahttps:\/\/play\.google\.com\/store\/apps\/developer\?id=zynga&start=0&gl=us&num=100&hl=en\z/
35
+ expect(url).to match(Regexp.new(pattern)), msg
36
+ end
37
+ end
38
+
39
+ it 'should update' do
40
+ name = 'zynga'
41
+ dev = MarketBot::Play::Developer.new(name)
42
+ code = 200
43
+
44
+ dev.store_urls.each_with_index do |url, i|
45
+ html = read_play_data('developer-zynga.txt')
46
+ response = Typhoeus::Response.new(code: code, headers: '', body: html)
47
+ Typhoeus.stub(url).and_return(response)
48
+ end
49
+
50
+ dev.update
51
+ end
52
+ end
@@ -1,4 +1,18 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe "MarketBot" do
4
+ it 'should support changing the default request timeout' do
5
+ MarketBot.timeout = 5
6
+ expect(MarketBot.timeout).to eq(5)
7
+ end
8
+
9
+ it 'should support changing the default request connect timeout' do
10
+ MarketBot.connect_timeout = 5
11
+ expect(MarketBot.connect_timeout).to eq(5)
12
+ end
13
+
14
+ it 'should support changing the default request user agent' do
15
+ MarketBot.user_agent = 'My Custom Bot'
16
+ expect(MarketBot.user_agent).to eq('My Custom Bot')
17
+ end
4
18
  end
data/spec/spec_helper.rb CHANGED
@@ -7,13 +7,7 @@ require 'rspec'
7
7
 
8
8
  begin
9
9
  require 'byebug'
10
- rescue Exception => e
11
- end
12
-
13
- begin
14
- require 'simplecov'
15
- SimpleCov.start
16
- rescue Exception => e
10
+ rescue Exception
17
11
  end
18
12
 
19
13
  require 'market_bot'
@@ -29,8 +23,8 @@ Typhoeus.configure do |config|
29
23
  config.block_connection = true
30
24
  end
31
25
 
32
- def read_file(*path)
33
- data = nil
34
- File.open(File.join(path), 'r') { |f| data = f.read }
35
- return data
26
+ def read_play_data(name)
27
+ path = File.join(File.expand_path(File.dirname(__FILE__)),
28
+ 'market_bot', 'play', 'data', name)
29
+ File.read(path)
36
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: market_bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chad Remesch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-06 00:00:00.000000000 Z
11
+ date: 2016-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus
@@ -42,49 +42,54 @@ dependencies:
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.10'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.10'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">"
60
60
  - !ruby/object:Gem::Version
61
61
  version: '10.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '10.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '='
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 2.8.0
75
+ version: '3.4'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '='
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 2.8.0
82
+ version: '3.4'
83
83
  description: Market Bot is a high performance Ruby scraper for Google's Android Market
84
84
  with a simple to use API. It is built on top of Nokogiri and Typhoeus.
85
85
  email:
86
86
  - chad@remesch.com
87
- executables: []
87
+ executables:
88
+ - app_categories
89
+ - benchmark_parser_app
90
+ - console
91
+ - setup
92
+ - update_test_data
88
93
  extensions: []
89
94
  extra_rdoc_files: []
90
95
  files:
@@ -92,38 +97,40 @@ files:
92
97
  - ".rspec"
93
98
  - ".travis.yml"
94
99
  - Gemfile
100
+ - Guardfile
95
101
  - LICENSE.txt
96
- - NOTES.txt
97
102
  - README.markdown
98
103
  - Rakefile
104
+ - bin/app_categories
105
+ - bin/benchmark_parser_app
106
+ - bin/console
107
+ - bin/setup
108
+ - bin/update_test_data
99
109
  - lib/market_bot.rb
100
- - lib/market_bot/android/app.rb
101
- - lib/market_bot/android/developer.rb
102
- - lib/market_bot/android/leaderboard.rb
103
- - lib/market_bot/android/leaderboard/constants.rb
104
- - lib/market_bot/android/search_query.rb
105
110
  - lib/market_bot/exceptions.rb
106
- - lib/market_bot/movie/leaderboard.rb
107
- - lib/market_bot/movie/leaderboard/constants.rb
108
- - lib/market_bot/movie/search_query.rb
111
+ - lib/market_bot/play/app.rb
112
+ - lib/market_bot/play/app/constants.rb
113
+ - lib/market_bot/play/chart.rb
114
+ - lib/market_bot/play/chart/constants.rb
115
+ - lib/market_bot/play/constants.rb
116
+ - lib/market_bot/play/developer.rb
117
+ - lib/market_bot/util.rb
109
118
  - lib/market_bot/version.rb
110
119
  - market_bot.gemspec
111
- - spec/market_bot/android/app_spec.rb
112
- - spec/market_bot/android/data/app_1.txt
113
- - spec/market_bot/android/data/app_2.txt
114
- - spec/market_bot/android/data/app_3.txt
115
- - spec/market_bot/android/data/app_4.txt
116
- - spec/market_bot/android/data/developer-zynga.txt
117
- - spec/market_bot/android/data/leaderboard-apps_editors_choice.txt
118
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page1.txt
119
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page2.txt
120
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page3.txt
121
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page4.txt
122
- - spec/market_bot/android/developer_spec.rb
123
- - spec/market_bot/android/leaderboard_spec.rb
124
- - spec/market_bot/android/search_query_spec.rb
125
- - spec/market_bot/movie/data/leaderboard-movies_comedy_topselling_paid.txt
126
- - spec/market_bot/movie/leaderboard_spec.rb
120
+ - spec/market_bot/play/app_spec.rb
121
+ - spec/market_bot/play/chart_spec.rb
122
+ - spec/market_bot/play/data/app-com.bluefroggaming.popdat.txt
123
+ - spec/market_bot/play/data/app-com.mg.android.txt
124
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-0.txt
125
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-1.txt
126
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-2.txt
127
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-3.txt
128
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-4.txt
129
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-5.txt
130
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-6.txt
131
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-7.txt
132
+ - spec/market_bot/play/data/developer-zynga.txt
133
+ - spec/market_bot/play/developer_spec.rb
127
134
  - spec/market_bot_spec.rb
128
135
  - spec/spec_helper.rb
129
136
  homepage: https://github.com/chadrem/market_bot
@@ -150,21 +157,19 @@ signing_key:
150
157
  specification_version: 4
151
158
  summary: 'Market Bot: High performance Ruby scraper for Google''s Android Market'
152
159
  test_files:
153
- - spec/market_bot/android/app_spec.rb
154
- - spec/market_bot/android/data/app_1.txt
155
- - spec/market_bot/android/data/app_2.txt
156
- - spec/market_bot/android/data/app_3.txt
157
- - spec/market_bot/android/data/app_4.txt
158
- - spec/market_bot/android/data/developer-zynga.txt
159
- - spec/market_bot/android/data/leaderboard-apps_editors_choice.txt
160
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page1.txt
161
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page2.txt
162
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page3.txt
163
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page4.txt
164
- - spec/market_bot/android/developer_spec.rb
165
- - spec/market_bot/android/leaderboard_spec.rb
166
- - spec/market_bot/android/search_query_spec.rb
167
- - spec/market_bot/movie/data/leaderboard-movies_comedy_topselling_paid.txt
168
- - spec/market_bot/movie/leaderboard_spec.rb
160
+ - spec/market_bot/play/app_spec.rb
161
+ - spec/market_bot/play/chart_spec.rb
162
+ - spec/market_bot/play/data/app-com.bluefroggaming.popdat.txt
163
+ - spec/market_bot/play/data/app-com.mg.android.txt
164
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-0.txt
165
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-1.txt
166
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-2.txt
167
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-3.txt
168
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-4.txt
169
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-5.txt
170
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-6.txt
171
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-7.txt
172
+ - spec/market_bot/play/data/developer-zynga.txt
173
+ - spec/market_bot/play/developer_spec.rb
169
174
  - spec/market_bot_spec.rb
170
175
  - spec/spec_helper.rb
data/NOTES.txt DELETED
@@ -1,61 +0,0 @@
1
- URLs:
2
- - id can be one of the below IDs or an application ID which usually starts with com.
3
- - category is optional and works with a subset of the below IDs.
4
- https://market.android.com/details?id=&cat=
5
- https://market.android.com/details?id=com.angrymobgames.muffinknightfree
6
-
7
- Data Models:
8
- Android::Leaderboard
9
- Android::Leaderboard::Stat
10
- Android::App
11
- Android::App::Stat
12
-
13
- IDs:
14
- apps_topselling_paid
15
- apps_topselling_free
16
- apps_topselling_new_free
17
- apps_topselling_new_paid
18
- apps_editors_choice
19
- apps_topselling_paid_game
20
- apps_movers_shakers
21
- apps_featured
22
- apps_tablet_featured
23
- apps_topgrossing
24
-
25
- Categories:
26
- GAME
27
- ARCADE
28
- BRAIN
29
- CARDS
30
- CASUAL
31
- GAME_WALLPAPER
32
- RACING
33
- SPORTS_GAMES
34
- GAME_WIDGETS
35
- APPLICATION
36
- BOOKS_AND_REFERENCE
37
- BUSINESS
38
- COMICS
39
- COMMUNICATION
40
- EDUCATION
41
- ENTERTAINMENT
42
- FINANCE
43
- HEALTH_AND_FITNESS
44
- LIBRARIES_AND_DEMO
45
- LIFESTYLE
46
- APP_WALLPAPER
47
- MEDIA_AND_VIDEO
48
- MEDICAL
49
- MUSIC_AND_AUDIO
50
- NEWS_AND_MAGAZINES
51
- PERSONALIZATION
52
- PHOTOGRAPHY
53
- PRODUCTIVITY
54
- SHOPPING
55
- SOCIAL
56
- SPORTS
57
- TOOLS
58
- TRANSPORTATION
59
- TRAVEL_AND_LOCAL
60
- WEATHER
61
- APP_WIDGETS
@@ -1,273 +0,0 @@
1
- module MarketBot
2
- module Android
3
-
4
- class App
5
- MARKET_ATTRIBUTES = [
6
- :title,
7
- :rating,
8
- :updated,
9
- :current_version,
10
- :requires_android,
11
- :category,
12
- :installs,
13
- :size,
14
- :price,
15
- :content_rating,
16
- :description,
17
- :votes,
18
- :developer,
19
- :more_from_developer,
20
- :users_also_installed,
21
- :related,
22
- :banner_icon_url,
23
- :banner_image_url,
24
- :website_url,
25
- :email,
26
- :screenshot_urls,
27
- :whats_new,
28
- :permissions,
29
- :rating_distribution,
30
- :html,
31
- :category_url,
32
- :full_screenshot_urls,
33
- :reviews,
34
- ]
35
-
36
- attr_reader :app_id
37
- attr_reader *MARKET_ATTRIBUTES
38
- attr_reader :hydra
39
- attr_reader :lang
40
- attr_reader :callback
41
- attr_reader :error
42
- attr_reader :result
43
-
44
- def self.parse(html)
45
- result = {}
46
-
47
- doc = Nokogiri::HTML(html)
48
- meta_info = doc.css('.meta-info')
49
- meta_info.each do |info|
50
- field_name = info.css('.title').text.strip
51
-
52
- case field_name
53
- when 'Updated'
54
- result[:updated] = info.css('.content').text.strip
55
- when 'Installs'
56
- result[:installs] = info.css('.content').text.strip
57
- when 'Size'
58
- result[:size] = info.css('.content').text.strip
59
- when 'Current Version'
60
- result[:current_version] = info.css('.content').text.strip
61
- when 'Requires Android'
62
- result[:requires_android] = info.css('.content').text.strip
63
- when 'Contact Developer', 'Developer'
64
- info.css('.dev-link').each do |node|
65
- node_href = node[:href]
66
- if node_href =~ /^mailto:/
67
- result[:email] = node_href.gsub(/^mailto:/,'')
68
- else
69
- if q_param = URI(node_href).query.split('&').select{ |p| p =~ /q=/ }.first
70
- actual_url = q_param.gsub('q=', '')
71
- end
72
-
73
- result[:website_url] = actual_url
74
- end
75
- end
76
-
77
- end
78
- end
79
-
80
- result[:content_rating] = doc.css("div.content[itemprop='contentRating']").text
81
-
82
- node = doc.xpath("//meta[@itemprop='price']").first
83
- result[:price] = node[:content].strip rescue 'Free'
84
-
85
- category_div = doc.css('.category').first
86
- result[:category] = category_div.text.strip rescue ''
87
- cat_link = category_div["href"]
88
- path, cat_name = File.split(cat_link)
89
- result[:category_url] = cat_name
90
-
91
- result[:description] = doc.xpath("//div[@itemprop='description']").first.inner_html.strip
92
- result[:title] = doc.css('div.id-app-title').text
93
-
94
- score = doc.css('.score-container').first
95
- unless score.nil?
96
- node = score.css('.score').first
97
- result[:rating] = node.text.strip
98
- node = score.xpath("//meta[@itemprop='ratingCount']").first
99
- result[:votes] = node[:content].strip
100
- end
101
-
102
- node = doc.xpath("//div[@itemprop='author']")
103
- result[:developer] = node.css('.primary').first.text.strip
104
-
105
- result[:more_from_developer] = []
106
- result[:users_also_installed] = []
107
- result[:related] = []
108
-
109
- node = doc.css('.recommendation')
110
- node.css('.rec-cluster').each do |recommended|
111
- assoc_app_type = recommended.css('.heading').first.text.strip.eql?('Similar' ) ? :related : :more_from_developer
112
- recommended.css('.card').each do |card|
113
- assoc_app = {}
114
- assoc_app[:app_id] = card['data-docid'].strip
115
-
116
- result[assoc_app_type] << assoc_app
117
- end
118
- end
119
- # Users also installed is no longer on the page, adding this for backwards compatibility, well, sort of....
120
- result[:users_also_installed] = result[:related]
121
-
122
- node = doc.css('.cover-image').first
123
- unless node.nil?
124
- url = fix_content_url(node[:src])
125
- result[:banner_icon_url] = url
126
- result[:banner_image_url] = url
127
- end
128
-
129
- result[:screenshot_urls] = []
130
- doc.css('.screenshot').each do |node|
131
- result[:screenshot_urls] << fix_content_url(node[:src])
132
- end
133
-
134
- result[:full_screenshot_urls] = []
135
- doc.css('.full-screenshot').each do |node|
136
- result[:full_screenshot_urls] << fix_content_url(node[:src])
137
- end
138
-
139
- node = doc.css('.whatsnew').first
140
- result[:whats_new] = node.inner_html.strip unless node.nil?
141
-
142
- # Stubbing out for now, can't find them in the redesigned page.
143
- result[:permissions] = permissions = []
144
-
145
- result[:reviews] = []
146
- doc.css('.single-review').each do |node|
147
- review = {}
148
- review[:author_name] = node.css('.author-name').text.strip if node.css('.author-name')
149
- raw_tag = node.css('.current-rating').to_s
150
- if raw_tag.match(/100%;/i)
151
- review[:review_score] = 5
152
- elsif raw_tag.match(/80%;/i)
153
- review[:review_score] = 4
154
- elsif raw_tag.match(/60%;/i)
155
- review[:review_score] = 3
156
- elsif raw_tag.match(/40%;/i)
157
- review[:review_score] = 2
158
- elsif raw_tag.match(/20%;/i)
159
- review[:review_score] = 1
160
- end
161
- if node.css('.review-title')
162
- review[:review_title] = node.css('.review-title').text.strip
163
- end
164
- if node.css('.review-body')
165
- review[:review_text] = node.css('.review-body').text
166
- .sub!(review[:review_title],'')
167
- .sub!(node.css('.review-link').text,'')
168
- .strip
169
- end
170
- if review
171
- result[:reviews] << review
172
- end
173
- end
174
-
175
- result[:rating_distribution] = { 5 => nil, 4 => nil, 3 => nil, 2 => nil, 1 => nil }
176
-
177
- histogram = doc.css('div.rating-histogram')
178
- cur_index = 5
179
- %w(five four three two one).each do |slot|
180
- node = histogram.css(".#{slot.to_s}")
181
- result[:rating_distribution][cur_index] = node.css('.bar-number').text.gsub(/,/,'').to_i
182
- cur_index -= 1
183
-
184
- end
185
-
186
- result[:html] = html
187
-
188
- result
189
- end
190
-
191
- def initialize(app_id, options={})
192
- @app_id = app_id
193
- @hydra = options[:hydra] || MarketBot.hydra
194
- @lang = options[:lang] || 'en'
195
- @callback = nil
196
- @error = nil
197
- @request_opts = options[:request_opts] || {}
198
- @request_opts[:timeout] ||= MarketBot.timeout
199
- @request_opts[:connecttimeout] ||= MarketBot.connecttimeout
200
- end
201
-
202
- def market_url
203
- "https://play.google.com/store/apps/details?id=#{@app_id}&hl=#{lang}"
204
- end
205
-
206
- def update
207
- req = Typhoeus::Request.new(market_url, @request_opts)
208
- req.run
209
- result = handle_response(req.response)
210
- update_callback(result)
211
-
212
- self
213
- end
214
-
215
- def enqueue_update(&block)
216
- @callback = block
217
- @error = nil
218
-
219
- request = Typhoeus::Request.new(market_url, @request_opts)
220
-
221
- request.on_complete do |response|
222
- result = nil
223
-
224
- begin
225
- result = handle_response(response)
226
- rescue Exception => e
227
- @error = e
228
- end
229
-
230
- update_callback(result)
231
- end
232
-
233
- hydra.queue(request)
234
-
235
- self
236
- end
237
-
238
- private
239
-
240
- def self.fix_content_url(url)
241
- url =~ /\A\/\// ? "https:#{url}" : url
242
- end
243
-
244
- def handle_response(response)
245
- if response.success?
246
- App.parse(response.body)
247
- else
248
- codes = "code=#{response.code}, return_code=#{response.return_code}"
249
- case response.code
250
- when 404
251
- raise MarketBot::AppNotFoundError.new("Unable to find app in store: #{codes}")
252
- else
253
- raise MarketBot::ResponseError.new("Unhandled response: #{codes}")
254
- end
255
- end
256
- end
257
-
258
- def update_callback(result)
259
- unless @error
260
- @result = result
261
-
262
- MARKET_ATTRIBUTES.each do |a|
263
- attr_name = "@#{a}"
264
- attr_value = result[a]
265
- instance_variable_set(attr_name, attr_value)
266
- end
267
- end
268
-
269
- @callback.call(self) if @callback
270
- end
271
- end
272
- end
273
- end