adops_report_scrapper 0.2.44 → 0.2.45
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.
- checksums.yaml +4 -4
- data/CHANGELOG +3 -0
- data/Gemfile +1 -0
- data/lib/adops_report_scrapper/openx_client.rb +33 -146
- data/lib/adops_report_scrapper/version.rb +1 -1
- data/lib/helpers/ox3client.rb +184 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6e398fac6bfeffceed28f29887aa913d02fd2942
|
|
4
|
+
data.tar.gz: 7498776ba363f9d5533ad8418641435274114718
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 00493541a04fdbefd643278a45ab21c190ca71cb6eadafaf12346c8a1f5643b6179e72b4b573e9f4f2173955f1a214cb3d66f4c6105294b452fbc824f80e64fe
|
|
7
|
+
data.tar.gz: bf4723da5f70aeee4ea5ed12cc4728b6cf8fb34be7d72467242446723c98a5fb60770099cd78f526fa4da89fdbe3c3cf3936ba1d66970129a868d9dae8dc1bc5
|
data/CHANGELOG
CHANGED
data/Gemfile
CHANGED
|
@@ -1,165 +1,52 @@
|
|
|
1
1
|
require 'date'
|
|
2
2
|
require_relative 'base_client'
|
|
3
|
+
require_relative '../helpers/ox3client'
|
|
4
|
+
require 'csv'
|
|
3
5
|
|
|
4
6
|
class AdopsReportScrapper::OpenxClient < AdopsReportScrapper::BaseClient
|
|
5
|
-
|
|
7
|
+
def date_supported?(date = nil)
|
|
8
|
+
_date = date || @date
|
|
9
|
+
return true if _date >= Date.today - 2
|
|
10
|
+
false
|
|
11
|
+
end
|
|
6
12
|
|
|
7
13
|
private
|
|
8
14
|
|
|
9
|
-
def
|
|
10
|
-
|
|
11
|
-
fail 'please specify openx
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@
|
|
15
|
-
@
|
|
16
|
-
@
|
|
17
|
-
|
|
18
|
-
@client.find :xpath, '//*[text()="Reports"]'
|
|
19
|
-
rescue Exception => e
|
|
20
|
-
raise e, 'Openx login error'
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def scrap
|
|
25
|
-
request_report
|
|
15
|
+
def init_client
|
|
16
|
+
fail 'please specify openx consumer_key' unless @options['consumer_key']
|
|
17
|
+
fail 'please specify openx consumer_secret' unless @options['consumer_secret']
|
|
18
|
+
fail 'please specify openx realm' unless @options['realm']
|
|
19
|
+
fail 'please specify openx site_url' unless @options['site_url']
|
|
20
|
+
@consumer_key = @options['consumer_key']
|
|
21
|
+
@consumer_secret = @options['consumer_secret']
|
|
22
|
+
@realm = @options['realm']
|
|
23
|
+
@site_url = @options['site_url']
|
|
26
24
|
end
|
|
27
25
|
|
|
28
|
-
def
|
|
29
|
-
sleep 5
|
|
30
|
-
@client.visit 'http://yahoo.com'
|
|
31
|
-
sleep 5
|
|
32
|
-
@client.visit "http://#{@account_prefix}.openx.net/#/reports?tab=my_reports"
|
|
33
|
-
sleep 5
|
|
34
|
-
|
|
35
|
-
begin
|
|
36
|
-
tries ||= 6
|
|
37
|
-
@client.find(:css, '#report_frame')
|
|
38
|
-
rescue Exception => e
|
|
39
|
-
retry unless (tries -= 1).zero?
|
|
40
|
-
fail 'cannot find report frame'
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
create_report_if_not_exist
|
|
44
|
-
|
|
45
|
-
@client.within_frame @client.find(:css, '#report_frame') do
|
|
46
|
-
@client.find(:xpath, "//a[text()=\"#{REPORT_NAME}\"]").click
|
|
47
|
-
|
|
48
|
-
begin
|
|
49
|
-
tries ||= 6
|
|
50
|
-
@client.find(:css, '.myFrame')
|
|
51
|
-
rescue Exception => e
|
|
52
|
-
retry unless (tries -= 1).zero?
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
@client.within_frame @client.find(:css, '.myFrame') do
|
|
56
|
-
begin
|
|
57
|
-
tries ||= 18
|
|
58
|
-
@client.find(:xpath, '//option[text()="500"]')
|
|
59
|
-
rescue Exception => e
|
|
60
|
-
retry unless (tries -= 1).zero?
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
@client.find(:xpath, '//option[text()="500"]').select_option
|
|
64
|
-
extract_data_from_report
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
sleep 5
|
|
26
|
+
def before_quit_with_error
|
|
68
27
|
end
|
|
69
28
|
|
|
70
|
-
def
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
begin
|
|
74
|
-
tries ||= 6
|
|
75
|
-
ready_elem = @client.find(:xpath, '//*[text()="Preconfigured Reports"]')
|
|
76
|
-
rescue Exception => e
|
|
77
|
-
retry unless (tries -= 1).zero?
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
fail 'openx report page not ready' unless ready_elem
|
|
29
|
+
def scrap
|
|
30
|
+
start_date_str = @date.strftime('%Y-%m-%d 00:00:00')
|
|
31
|
+
end_date_str = @date.strftime('%Y-%m-%d 23:59:59')
|
|
81
32
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
# create report if not exist
|
|
85
|
-
@client.find(:xpath, '//*[contains(text(),"Create Report")]').click
|
|
86
|
-
@client.find(:xpath, '//li/*[text()="Ad Server Report"]').click
|
|
33
|
+
ox3 = OX3APIClient.new(@login, @secret, @site_url, @consumer_key, @consumer_secret, @realm)
|
|
87
34
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
retry unless (tries -= 1).zero?
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
@client.within_frame @client.find(:css, '.myFrame') do
|
|
35
|
+
response = ox3.get("/report/run?report=inv_rev&start_date=#{URI.escape(start_date_str)}&end_date=#{URI.escape(end_date_str)}&report_format=csv&do_break=AdUnit,Country&saleschannel=SALESCHANNEL.OPENXMARKET")
|
|
36
|
+
report_pickup_url = @site_url + JSON.parse(response)['url']
|
|
37
|
+
report_csv_data = nil;
|
|
38
|
+
open(report_pickup_url) { |f| report_csv_data = f.read }
|
|
96
39
|
|
|
97
|
-
|
|
98
|
-
@client.find(:xpath, '//*[text()="Yesterday"]').click
|
|
99
|
-
@client.find(:xpath, '//*[@value="Next"]').trigger('click')
|
|
100
|
-
sleep 2
|
|
40
|
+
@data = CSV.parse(report_csv_data)
|
|
101
41
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
@client.find(:xpath, '//*[text()="Device Category"]').click
|
|
106
|
-
@client.find(:xpath, '//*[@value="Next"]').trigger('click')
|
|
107
|
-
sleep 2
|
|
108
|
-
|
|
109
|
-
@client.find(:xpath, '//*[text()="Paid Impressions"]').click
|
|
110
|
-
@client.find(:xpath, '//*[text()="Impressions Delivered"]').click
|
|
111
|
-
@client.find(:xpath, '//*[text()="Ad Requests"]').click
|
|
112
|
-
@client.find(:xpath, '//img[../../td//*[text()="Revenue"]]').click
|
|
113
|
-
@client.find(:xpath, '//*[text()="Publisher Revenue"]').click
|
|
114
|
-
@client.find(:xpath, '//img[../../td//*[text()="Clicks"]]').click
|
|
115
|
-
@client.find(:xpath, '//div[text()="Clicks"]').click
|
|
116
|
-
@client.find(:xpath, '//*[@value="Next"]').trigger('click')
|
|
117
|
-
sleep 2
|
|
118
|
-
|
|
119
|
-
@client.find(:xpath, '//*[@value="Save"]').trigger('click')
|
|
120
|
-
|
|
121
|
-
begin
|
|
122
|
-
tries ||= 6
|
|
123
|
-
@client.find(:xpath, '//*[text()="Save Report"]')
|
|
124
|
-
rescue Exception => e
|
|
125
|
-
retry unless (tries -= 1).zero?
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
@client.fill_in 'saveAsReportName', :with => REPORT_NAME
|
|
129
|
-
@client.find(:xpath, '//*[@value="Save Report"]').trigger('click')
|
|
130
|
-
|
|
131
|
-
begin
|
|
132
|
-
tries ||= 6
|
|
133
|
-
@client.find(:xpath, '//*[text()="Report Saved"]')
|
|
134
|
-
rescue Exception => e
|
|
135
|
-
retry unless (tries -= 1).zero?
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
@client.find(:xpath, '//*[text()="Back to My Reports"]').trigger('click')
|
|
139
|
-
end
|
|
140
|
-
sleep 2
|
|
141
|
-
end
|
|
42
|
+
while @data.count > 0
|
|
43
|
+
row = @data.shift
|
|
44
|
+
break if row.first == 'Report Data:'
|
|
142
45
|
end
|
|
143
|
-
end
|
|
144
46
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
18.times do
|
|
149
|
-
sleep 10
|
|
150
|
-
break if @client.find_all(:xpath, '//table[@id="table_UniqueReportID"]/*/tr').count > 0
|
|
151
|
-
end
|
|
152
|
-
rows = @client.find_all :xpath, '//table[@id="table_UniqueReportID"]/*/tr'
|
|
153
|
-
rows = rows.to_a
|
|
154
|
-
header = rows.shift
|
|
155
|
-
if @data.count == 0
|
|
156
|
-
n_header = header.find_css('td,th').map { |td| td.visible_text }
|
|
157
|
-
@data << n_header
|
|
158
|
-
end
|
|
159
|
-
@data += rows.map { |tr| tr.find_css('td,th').map { |td| td.visible_text } }.reject { |row| row[0] == 'Total' }
|
|
160
|
-
pagee = @client.find(:xpath, '//*[contains(text(),"Showing rows")]').text.match(/-(\d+) of (\d+)\./).captures
|
|
161
|
-
break if pagee[0] == pagee[1]
|
|
162
|
-
@client.find_all(:css, '#paginationNext').first.trigger('click')
|
|
47
|
+
while @data.count > 0
|
|
48
|
+
break if @data.last.first == 'Real-time Buyer'
|
|
49
|
+
@data.pop
|
|
163
50
|
end
|
|
164
51
|
end
|
|
165
|
-
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# https://raw.githubusercontent.com/openx/OX3-Ruby-API-Client/master/ox3client.rb
|
|
2
|
+
|
|
3
|
+
require 'oauth'
|
|
4
|
+
require 'yaml'
|
|
5
|
+
|
|
6
|
+
class OX3APIClient < OAuth::Consumer
|
|
7
|
+
|
|
8
|
+
def initialize(email, password, site_url, consumer_key, consumer_secret, realm,
|
|
9
|
+
version='v2', sso_domain='sso.openx.com', callback='oob', scheme='https', debug=false)
|
|
10
|
+
|
|
11
|
+
@version, @callback, @site, @debug = version, callback, site_url, debug
|
|
12
|
+
@site = @site.end_with?('/') ? @site.chop : @site
|
|
13
|
+
|
|
14
|
+
super(consumer_key, consumer_secret, {
|
|
15
|
+
:http_method => :post,
|
|
16
|
+
:scheme => :header,
|
|
17
|
+
:oauth_version => "1.0",
|
|
18
|
+
:signature_method => "HMAC-SHA1",
|
|
19
|
+
:site => @site,
|
|
20
|
+
:request_token_url => scheme + '://' + sso_domain + '/api/index/initiate',
|
|
21
|
+
:access_token_url => scheme + '://' + sso_domain + '/api/index/token',
|
|
22
|
+
:authorize_path => scheme + '://' + sso_domain + '/login/process',
|
|
23
|
+
:realm => realm
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
# Step 1. Fetch temporary request token.
|
|
27
|
+
fetch_request_token
|
|
28
|
+
|
|
29
|
+
# Step 2. Log in to SSO server and authorize token.
|
|
30
|
+
authorize_token(email, password)
|
|
31
|
+
|
|
32
|
+
# Step 3. Swap temporary request token for permanent access token.
|
|
33
|
+
fetch_access_token
|
|
34
|
+
|
|
35
|
+
# Step 4. Validate your access token.
|
|
36
|
+
validate_session
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
################################################################################################################
|
|
40
|
+
def perform_request
|
|
41
|
+
http = self.create_http(@site)
|
|
42
|
+
http.open_timeout = 5 * 60
|
|
43
|
+
http.read_timeout = 15 * 60
|
|
44
|
+
params = Hash.new
|
|
45
|
+
params['Content-Type'] = 'application/json'
|
|
46
|
+
params['Cookie'] = 'openx3_access_token=' + @acccess_token.token + '; domain=' + get_domain + '; path=/'
|
|
47
|
+
prefix = "/ox/4.0"
|
|
48
|
+
response = http.request yield prefix, params
|
|
49
|
+
response.body
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def get(path)
|
|
53
|
+
perform_request do |prefix, params|
|
|
54
|
+
self.create_http_request(
|
|
55
|
+
:get,
|
|
56
|
+
prefix + path,
|
|
57
|
+
params
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def post(path, body = {})
|
|
63
|
+
if body.is_a?(Hash)
|
|
64
|
+
body = JSON.dump(body)
|
|
65
|
+
end
|
|
66
|
+
perform_request do |prefix, params|
|
|
67
|
+
self.create_http_request(
|
|
68
|
+
:post,
|
|
69
|
+
prefix + path,
|
|
70
|
+
body,
|
|
71
|
+
params
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def put(path, body = {})
|
|
77
|
+
if body.is_a?(Hash)
|
|
78
|
+
body = JSON.dump(body)
|
|
79
|
+
end
|
|
80
|
+
perform_request do |prefix, params|
|
|
81
|
+
self.create_http_request(
|
|
82
|
+
:put,
|
|
83
|
+
prefix + path,
|
|
84
|
+
body,
|
|
85
|
+
params
|
|
86
|
+
)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def delete(path)
|
|
91
|
+
perform_request do |prefix, params|
|
|
92
|
+
self.create_http_request(
|
|
93
|
+
:delete,
|
|
94
|
+
prefix + path,
|
|
95
|
+
params
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def logoff
|
|
101
|
+
get "/login/logout"
|
|
102
|
+
end
|
|
103
|
+
################################################################################################################
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
def fetch_request_token
|
|
107
|
+
@request_token = self.get_request_token(
|
|
108
|
+
{:oauth_callback => @callback},
|
|
109
|
+
{'Content-Type' => 'application/x-www-form-urlencoded'}
|
|
110
|
+
)
|
|
111
|
+
if @debug
|
|
112
|
+
puts YAML::dump(@request_token)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def authorize_token(email, password)
|
|
117
|
+
authorize = self.request(:post, self.authorize_path, nil,
|
|
118
|
+
{:oauth_token => @request_token.token, :oauth_callback => @callback},
|
|
119
|
+
{:email => email, :password => password, :oauth_token => @request_token.token},
|
|
120
|
+
{'Content-Type' => 'application/x-www-form-urlencoded'}
|
|
121
|
+
)
|
|
122
|
+
if authorize.code.to_s == '200'
|
|
123
|
+
response = authorize
|
|
124
|
+
else
|
|
125
|
+
response = self.request(:post, authorize.header['Location'], nil,
|
|
126
|
+
{:oauth_token => @request_token.token, :oauth_callback => @callback}, nil,
|
|
127
|
+
{
|
|
128
|
+
'Content-Type' => 'application/x-www-form-urlencoded',
|
|
129
|
+
'Cookie' => authorize.get_fields('set-cookie')[0],
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
end
|
|
133
|
+
if @debug
|
|
134
|
+
puts YAML::dump(response)
|
|
135
|
+
end
|
|
136
|
+
@oauth_verifier = parse_tokens(response.body)[:oauth_verifier]
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def fetch_access_token
|
|
140
|
+
@acccess_token = @request_token.get_access_token(
|
|
141
|
+
{:oauth_verifier => @oauth_verifier, :oauth_token => @request_token.token, :oauth_callback => @callback},
|
|
142
|
+
{'Content-Type' => 'application/x-www-form-urlencoded'}
|
|
143
|
+
)
|
|
144
|
+
if @debug
|
|
145
|
+
puts YAML::dump(@acccess_token)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def validate_session
|
|
150
|
+
=begin
|
|
151
|
+
path = "/ox/4.0/session"
|
|
152
|
+
method = :get
|
|
153
|
+
response = self.request(method.to_sym, @site + path, nil, {}, nil,
|
|
154
|
+
{
|
|
155
|
+
'Content-Type' => 'application/json',
|
|
156
|
+
'Cookie' => 'openx3_access_token=' + @acccess_token.token + '; domain=' + get_domain + '; path=/'
|
|
157
|
+
}
|
|
158
|
+
)
|
|
159
|
+
=end
|
|
160
|
+
response = perform_request do |prefix, params|
|
|
161
|
+
self.create_http_request(
|
|
162
|
+
:get,
|
|
163
|
+
prefix + "/session",
|
|
164
|
+
nil,
|
|
165
|
+
params
|
|
166
|
+
)
|
|
167
|
+
end
|
|
168
|
+
if @debug
|
|
169
|
+
puts YAML::dump(response)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def parse_tokens(keys)
|
|
174
|
+
keys.split("&").inject({}) do |hash, pair|
|
|
175
|
+
key, value = pair.split("=")
|
|
176
|
+
hash.merge({ key.to_sym => CGI.unescape(value) })
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def get_domain
|
|
181
|
+
URI.parse(@site).host
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: adops_report_scrapper
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.45
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stayman Hou
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-11-
|
|
11
|
+
date: 2017-11-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: httpclient
|
|
@@ -291,6 +291,7 @@ files:
|
|
|
291
291
|
- lib/adops_report_scrapper/undertone_client.rb
|
|
292
292
|
- lib/adops_report_scrapper/version.rb
|
|
293
293
|
- lib/adops_report_scrapper/zedo_client.rb
|
|
294
|
+
- lib/helpers/ox3client.rb
|
|
294
295
|
- secret.sample.yml
|
|
295
296
|
- tmp/.keep
|
|
296
297
|
homepage: https://github.com/StaymanHou/adops_report_scrapper
|