ppc 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +37 -0
  3. data/.rspec +2 -0
  4. data/LICENSE +339 -0
  5. data/README.md +78 -0
  6. data/lib/ppc.rb +17 -0
  7. data/lib/ppc/api.rb +10 -0
  8. data/lib/ppc/api/baidu.rb +138 -0
  9. data/lib/ppc/api/baidu/account.rb +47 -0
  10. data/lib/ppc/api/baidu/bulk.rb +41 -0
  11. data/lib/ppc/api/baidu/creative.rb +125 -0
  12. data/lib/ppc/api/baidu/group.rb +111 -0
  13. data/lib/ppc/api/baidu/keyword.rb +204 -0
  14. data/lib/ppc/api/baidu/plan.rb +68 -0
  15. data/lib/ppc/api/baidu/report.rb +143 -0
  16. data/lib/ppc/api/qihu.rb +107 -0
  17. data/lib/ppc/api/qihu/account.rb +86 -0
  18. data/lib/ppc/api/qihu/creative.rb +106 -0
  19. data/lib/ppc/api/qihu/group.rb +113 -0
  20. data/lib/ppc/api/qihu/keyword.rb +111 -0
  21. data/lib/ppc/api/qihu/plan.rb +64 -0
  22. data/lib/ppc/api/qihu/report.rb +159 -0
  23. data/lib/ppc/api/shenma.rb +64 -0
  24. data/lib/ppc/api/shenma/report.rb +135 -0
  25. data/lib/ppc/api/sogou.rb +122 -0
  26. data/lib/ppc/api/sogou/account.rb +42 -0
  27. data/lib/ppc/api/sogou/creative.rb +117 -0
  28. data/lib/ppc/api/sogou/group.rb +116 -0
  29. data/lib/ppc/api/sogou/keyword.rb +182 -0
  30. data/lib/ppc/api/sogou/plan.rb +66 -0
  31. data/lib/ppc/api/sogou/report.rb +129 -0
  32. data/lib/ppc/ext.rb +9 -0
  33. data/lib/ppc/operation.rb +196 -0
  34. data/lib/ppc/operation/account.rb +53 -0
  35. data/lib/ppc/operation/creative.rb +28 -0
  36. data/lib/ppc/operation/group.rb +59 -0
  37. data/lib/ppc/operation/keyword.rb +32 -0
  38. data/lib/ppc/operation/plan.rb +47 -0
  39. data/lib/ppc/operation/report.rb +19 -0
  40. data/ppc.gemspec +26 -0
  41. data/spec/baidu/api_baidu_account_spec.rb +15 -0
  42. data/spec/baidu/api_baidu_creative_spec.rb +67 -0
  43. data/spec/baidu/api_baidu_group_spec.rb +45 -0
  44. data/spec/baidu/api_baidu_keyword_spec.rb +61 -0
  45. data/spec/baidu/api_baidu_plan_spec.rb +43 -0
  46. data/spec/baidu/api_baidu_report_spec.rb +44 -0
  47. data/spec/baidu/api_baidu_spec.rb +55 -0
  48. data/spec/operation/operation_baidu_report_spec.rb +17 -0
  49. data/spec/operation/operation_baidu_spec.rb +78 -0
  50. data/spec/operation/operation_qihu_report_spec.rb +18 -0
  51. data/spec/operation/operation_qihu_spec.rb +51 -0
  52. data/spec/operation/operation_sogou_report_spec.rb +17 -0
  53. data/spec/operation/operation_sogou_spec.rb +51 -0
  54. data/spec/operation/operation_spec_helper.rb +51 -0
  55. data/spec/qihu/api_qihu_account_spec.rb +25 -0
  56. data/spec/qihu/api_qihu_creative_spec.rb +48 -0
  57. data/spec/qihu/api_qihu_group_spec.rb +40 -0
  58. data/spec/qihu/api_qihu_keyword_spec.rb +50 -0
  59. data/spec/qihu/api_qihu_plan_spec.rb +39 -0
  60. data/spec/qihu/api_qihu_report_spec.rb +54 -0
  61. data/spec/sogou/api_sogou_account_spec.rb +15 -0
  62. data/spec/sogou/api_sogou_creative_spec.rb +48 -0
  63. data/spec/sogou/api_sogou_group_spec.rb +45 -0
  64. data/spec/sogou/api_sogou_keyword_spec.rb +50 -0
  65. data/spec/sogou/api_sogou_plan_spec.rb +39 -0
  66. data/spec/sogou/api_sogou_report_spec.rb +51 -0
  67. data/spec/spec_helper.rb +134 -0
  68. metadata +177 -0
@@ -0,0 +1,66 @@
1
+ module PPC
2
+ module API
3
+ class Sogou
4
+ class Plan< Sogou
5
+ Service = 'CpcPlan'
6
+
7
+ @map = [
8
+ [:id,:cpcPlanId],
9
+ [:name,:cpcPlanName],
10
+ [:budget,:budget],
11
+ [:region,:regions],
12
+ [:ip,:excludeIps] ,
13
+ [:negative,:negativeWords],
14
+ [:exact_negative,:exactNegativeWords],
15
+ [:schedule,:schedule],
16
+ [:budget_offline_time,:budgetOfflineTime],
17
+ [:show_prob,:showProb],
18
+ [:join_union ,:joinUnion],
19
+ [:device,:device],
20
+ [:price_ratio,:mobilePriceRate ],
21
+ [:pause,:pause],
22
+ [:status,:status],
23
+ ]
24
+
25
+ def self.all( auth, debug = false )
26
+ response = request( auth, Service, 'getAllCpcPlan' )
27
+ process( response, 'cpcPlanTypes' , debug ){ |x| reverse_type(x) }
28
+ end
29
+
30
+ def self.ids( auth, debug = false )
31
+ response = request( auth, Service, 'getAllCpcPlanId' )
32
+ process( response, 'cpcPlanIds' , debug ){ |x| x }
33
+ end
34
+
35
+ def self.get( auth, ids, debug = false )
36
+ ids = [ ids ] unless ids.is_a? Array
37
+ body = { cpcPlanIds: ids }
38
+ response = request( auth, Service, 'getCpcPlanByCpcPlanId', body)
39
+ process( response, 'cpcPlanTypes' , debug ){ |x| reverse_type(x) }
40
+ end
41
+
42
+ def self.add( auth, plans, debug = false )
43
+ cpcPlanTypes = make_type( plans )
44
+ body = { cpcPlanTypes: cpcPlanTypes }
45
+ response = request( auth, Service, 'addCpcPlan', body)
46
+ process( response, 'cpcPlanTypes' , debug ){ |x| reverse_type(x) }
47
+ end
48
+
49
+ def self.update(auth,plans, debug = false )
50
+ cpcPlanTypes = make_type( plans )
51
+ body = { cpcPlanTypes: cpcPlanTypes }
52
+ response = request( auth, Service, 'updateCpcPlan', body)
53
+ process( response, 'cpcPlanTypes' , debug ){ |x| reverse_type(x) }
54
+ end
55
+
56
+ def self.delete(auth, ids, debug = false )
57
+ ids = [ ids ] unless ids.class == Array
58
+ body = { cpcPlanIds: ids }
59
+ response = request( auth, Service, 'deleteCpcPlan', body)
60
+ process( response, '' , debug ){ |x| x }
61
+ end
62
+
63
+ end # Service
64
+ end # baidu
65
+ end # API
66
+ end # PPC
@@ -0,0 +1,129 @@
1
+ # -*- coding:utf-8 -*-
2
+ module PPC
3
+ module API
4
+ class Sogou
5
+ class Report< Sogou
6
+ Service = 'Report'
7
+
8
+ # 需要用到的映射集合
9
+ Type_map = { 'account' => 1, 'plan'=> 2, 'group'=> 3,
10
+ 'keyword'=> 5, 'creative'=> 4, 'pair'=> 15,
11
+ 'query'=> 3 }
12
+
13
+ Range_map = { 'account' => 1, 'plan' => 2, 'group' => 3,
14
+ 'creative' => 4, 'keyword' => 5 }
15
+
16
+ Device_map = { 'all' => 0, 'pc' => 1, 'mobile' => 2 }
17
+
18
+ Unit_map = { 'day' => 1, 'week' => 2, 'month' => 3 }
19
+
20
+ def self.get_id( auth, params, debug = false )
21
+ request = make_reportrequest( params )
22
+ body = { reportRequestType: request }
23
+ response = request( auth, Service, 'getReportId' ,body)
24
+ process( response, 'reportId', debug ){ |x| x }
25
+ end
26
+
27
+ def self.get_state( auth, id, debug = false)
28
+ '''
29
+ input id should be string
30
+ '''
31
+ status = {'-1'=>'Waiting' ,'0'=>'Opearting' ,'1'=>'Finished'}
32
+ body = { reportId: id }
33
+ response = request( auth, Service, 'getReportState' ,body)
34
+ process( response, 'isGenerated', debug ){ |x| status[x] }
35
+ end
36
+
37
+ def self.get_url( auth, id, debug = false )
38
+ body = { reportId: id }
39
+ response = request( auth, Service, 'getReportPath' ,body)
40
+ process( response, 'reportFilePath', debug ){ |x| x }
41
+ end
42
+
43
+ private
44
+ def self.make_reportrequest( param )
45
+ '''
46
+ make RepoerRequestType
47
+ ======================
48
+ For more docs please have a look at
49
+ ::PPC::API::Baidu::Report:make_reportrequest()
50
+ '''
51
+ requesttype = {}
52
+ requesttype[:performanceData] = param[:fields] || %w(click)
53
+ requesttype[:reportType] = Type_map[ param[:type] ] if param[:type]
54
+ requesttype[:statRange] = Range_map[ param[:range] ] if param[:range]
55
+ requesttype[:unitOfTime] = Unit_map[ param[:unit] ] if param[:unit]
56
+ requesttype[:platform] = Device_map[ param[:device] ] if param[:device]
57
+ requesttype[:idOnly] = param[:id_only] if param[:id_only]!=nil
58
+ requesttype[:startDate] = parse_date( param[:startDate] )
59
+ requesttype[:endDate] = parse_date( param[:endDate] )
60
+ return requesttype
61
+ end
62
+
63
+ private
64
+ def self.parse_date( date )
65
+ """
66
+ Cast string to time:
67
+ 'YYYYMMDD' => Time
68
+ """
69
+ if date
70
+ y = date[0..3]
71
+ m = date[4..5]
72
+ d = date[6..7]
73
+ date = Time.new( y, m, d )
74
+ else
75
+ date = (Time.now - 24*3600)
76
+ end
77
+ date.utc.iso8601
78
+ end
79
+
80
+ ###########################
81
+ # intreface for Operation #
82
+ ###########################
83
+ def self.download_report( auth, param, debug = false )
84
+ response = get_id( auth, param )
85
+ if response[:succ]
86
+ id = response[:result]
87
+ p "Got report id:" + id.to_s if debug
88
+ loop do
89
+ sleep 2
90
+ break if get_state( auth, id )[:result] == 'Finished'
91
+ p "Report is not generated, waiting..." if debug
92
+ end
93
+
94
+ url = get_url( auth, id )[:result]
95
+ ActiveSupport::Gzip.decompress( open(url).read )
96
+ else
97
+ raise response[:failure][:message]
98
+ end
99
+ end
100
+
101
+ def self.query_report( auth, param = nil, debug = false )
102
+ param = {} if not param
103
+ param[:type] ||= 'query'
104
+ param[:fields] ||= %w(click)
105
+ param[:range] ||= 'account'
106
+ param[:unit] ||= 'day'
107
+ download_report( auth, param, debug )
108
+ end
109
+
110
+ def self.creative_report( auth, param = nil, debug = false )
111
+ param = {} if not param
112
+ param[:type] ||= 'creative'
113
+ param[:fields] ||= %w( cost cpc click impression ctr )
114
+ param[:range] ||= 'account'
115
+ download_report( auth, param, debug )
116
+ end
117
+
118
+ def self.keyword_report( auth, param = nil, debug = false )
119
+ param = {} if not param
120
+ param[:type] ||= 'keyword'
121
+ param[:fields] ||= %w( cost cpc click impression ctr )
122
+ param[:range] ||= 'account'
123
+ download_report( auth, param, debug )
124
+ end
125
+
126
+ end # Repost
127
+ end # Baidu
128
+ end # API
129
+ end # PPC
@@ -0,0 +1,9 @@
1
+ class String
2
+ def snake_case
3
+ self.gsub(/::/, '/').
4
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
5
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
6
+ tr("-", "_").
7
+ downcase
8
+ end
9
+ end
@@ -0,0 +1,196 @@
1
+ module PPC
2
+ module Operation
3
+
4
+ attr_accessor :id
5
+
6
+ def initialize( params )
7
+
8
+ if params[:se] == nil
9
+ raise 'please specific a search engine'
10
+ else
11
+ @se = params[:se]
12
+ end
13
+ @id = params[:id]
14
+ @auth = {
15
+ username: params[:username],
16
+ password: params[:password],
17
+ # 在qihu360的api中,apikey就是auth[:token]
18
+ token: params[:token]
19
+ }
20
+ # add support for qihu360
21
+ if @se == 'qihu' && params[:accessToken] == nil
22
+ raise "you are using qihu service, please enter cipherkey" if params[:cipherkey] == nil
23
+ raise "you are using qihu service, please enter cipheriv" if params[:cipheriv] == nil
24
+ cipher = { key: params[:cipherkey], iv: params[:cipheriv] }
25
+ @auth[:accessToken] = qihu_refresh_token( @auth, cipher )
26
+ else
27
+ @auth[:accessToken] = params[:accessToken]
28
+ end
29
+ end
30
+
31
+ def qihu_refresh_token( auth, cipher )
32
+ cipher_aes = OpenSSL::Cipher::AES.new(128, :CBC)
33
+ cipher_aes.encrypt
34
+ cipher_aes.key = cipher[:key]
35
+ cipher_aes.iv = cipher[:iv]
36
+ encrypted = (cipher_aes.update(Digest::MD5.hexdigest( auth[:password] )) + cipher_aes.final).unpack('H*').join
37
+ url = "https://api.e.360.cn/account/clientLogin"
38
+ response = HTTParty.post(url,
39
+ :body => {
40
+ :username => auth[:username],
41
+ :passwd => encrypted[0,64]
42
+ },
43
+ :headers => {'apiKey' => auth[:token] }
44
+ )
45
+ data = response.parsed_response
46
+ data["account_clientLogin_response"]["accessToken"]
47
+ end
48
+
49
+ def call(service)
50
+ eval "::PPC::API::#{@se.capitalize}::#{service.capitalize}"
51
+ end
52
+
53
+ def download(params = {})
54
+ bulk = ::PPC::Baidu::Bulk.new({
55
+ username: @username,
56
+ password: @password,
57
+ token: @token,
58
+ debug: @debug
59
+ })
60
+
61
+ params[:extended] = params[:extended] || 2
62
+
63
+ begin
64
+ file_id = bulk.file_id_of_all(params)
65
+ puts "file_id: #{file_id}" if @debug
66
+
67
+ loop do
68
+ state = bulk.state(file_id)
69
+ raise "invalid file state: #{state}" unless %w(1 2 3 null).include? state
70
+ break if state == '3'
71
+ puts "waiting for #{file_id} to be ready. current state:#{state}" if @debug
72
+ sleep 3
73
+ end
74
+ puts "#{file_id} is ready" if @debug
75
+ return bulk.path(file_id)
76
+ rescue
77
+ raise BulkException.new(file_id,bulk)
78
+ end
79
+
80
+ return false
81
+ end
82
+
83
+ # ++++++++ #
84
+ # Lazy Code #
85
+ # ++++++++ #
86
+
87
+ # helper fucntion
88
+ def get_obj( ids, service )
89
+ '''
90
+ Return service object.
91
+ Providing single id, return single object.
92
+ Providing multiple ids, return Array of objects
93
+ '''
94
+ class_obj = eval "::PPC::Opeartion::#{service.capitalize}"
95
+ param = @auth
96
+ param[:se] = @se
97
+ objs = []
98
+
99
+ ids.each do |id|
100
+ param[:id] = id
101
+ objs << class_obj.new( param )
102
+ end
103
+
104
+ return objs.length == 1 ? objs[0] : objs
105
+ end
106
+
107
+ # +++++ Plan opeartion funcitons +++++ #
108
+ module Plan_operation
109
+ def get_plan( ids )
110
+ ::PPC::Opeartion::get_obj( ids, 'plan')
111
+ end
112
+
113
+ def add_plan( plans )
114
+ call('plan').add(@auth,plans)
115
+ end
116
+
117
+ def update_plan( plans )
118
+ call('plan').update(@auth,plans)
119
+ end
120
+
121
+ def delete_plan( ids )
122
+ call('plan').delete(@auth,ids)
123
+ end
124
+ end
125
+
126
+ # +++++ Group opeartion funcitons +++++ #
127
+ module Group_operation
128
+ def get_group( ids )
129
+ ::PPC::Opeartion::get_obj( ids, 'group')
130
+ end
131
+
132
+ def add_group( groups )
133
+ call('group').add(@auth,groups )
134
+ end
135
+
136
+ def update_group( groups )
137
+ call('group').update( @auth, groups )
138
+ end
139
+
140
+ def delete_group( ids )
141
+ call('group').delete( @auth, ids )
142
+ end
143
+ end
144
+
145
+ # +++++ Keyword opeartion funcitons +++++ #
146
+ module Keyword_operation
147
+ def get_keyword( ids )
148
+ ::PPC::Opeartion::get_obj( ids, 'keyword')
149
+ end
150
+
151
+ def add_keyword( keywords )
152
+ call('keyword').add( @auth, keywords )
153
+ end
154
+
155
+ def update_keyword( keywords)
156
+ call('keyword').update( @auth, keywords )
157
+ end
158
+
159
+ def delete_keyword( ids )
160
+ call('keyword').delete( @auth, ids )
161
+ end
162
+ end
163
+
164
+ # +++++ Creative opeartion funcitons +++++ #
165
+ module Creative_operation
166
+ def get_creative( ids )
167
+ ::PPC::Opeartion::get_obj( ids, 'creative')
168
+ end
169
+
170
+ def add_creative( creatives )
171
+ call('creative').add( @auth, creatives )
172
+ end
173
+
174
+ def update_creative( creatives )
175
+ call('creative').update( @auth, creatives )
176
+ end
177
+
178
+ def delete_creative( ids )
179
+ call('creative').delete( @auth, ids )
180
+ end
181
+ end
182
+
183
+ end # Opeartion
184
+ end # PPC
185
+
186
+ # requires are moved to the end of the file
187
+ # because if we load files before defining the
188
+ # module ::PPC::Operation. Errors of 'uninitialized constance'
189
+ # will occur
190
+ require 'ppc/operation/report'
191
+ require 'ppc/operation/account'
192
+ require 'ppc/operation/group'
193
+ require 'ppc/operation/plan'
194
+ require 'ppc/operation/keyword'
195
+ require 'ppc/operation/creative'
196
+
@@ -0,0 +1,53 @@
1
+ module PPC
2
+ module Operation
3
+ class Account
4
+ include ::PPC::Operation
5
+
6
+ # self operations
7
+ def info
8
+ info = call('account').info(@auth)
9
+ p info
10
+ @id = info[:result][:id] if @id == nil
11
+ return info
12
+ end
13
+
14
+ def update(account)
15
+ call('account').update(@auth,account)
16
+ end
17
+
18
+ # subobject(plan) operations
19
+ def plans
20
+ call('plan').all(@auth)
21
+ end
22
+
23
+ def plan_ids
24
+ call('plan').ids(@auth)
25
+ end
26
+
27
+ # some useful keyword operations
28
+ def keywords(group_id)
29
+ call( 'keyword' ).search_by_group_id( @auth, group_id )
30
+ end
31
+
32
+ def keyword_ids(group_id)
33
+ call( 'keyword' ).search_id_by_group_id( @auth, group_id )
34
+ end
35
+
36
+ # plan operations
37
+ include ::PPC::Operation::Plan_operation
38
+
39
+ # group opeartions
40
+ include ::PPC::Operation::Group_operation
41
+
42
+ # keyword opeartions
43
+ include ::PPC::Operation::Keyword_operation
44
+
45
+ # creative opeartions
46
+ include ::PPC::Operation::Creative_operation
47
+
48
+ # report operations
49
+ include ::PPC::Operation::Report
50
+
51
+ end
52
+ end
53
+ end