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,17 @@
1
+ require 'ppc/api'
2
+ require 'ppc/operation'
3
+ require 'ppc/ext'
4
+ module PPC
5
+ VERSION = "0.3.0"
6
+
7
+ protected
8
+ def print_debug(var,varname=nil)
9
+ puts '=' * 10 + varname.to_s + '=' * 10
10
+ if var.is_a? String
11
+ puts var
12
+ else
13
+ ap var
14
+ end
15
+ puts '=' * 10 + varname.to_s + '=' * 10
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ require 'ppc/api/baidu'
2
+ require 'ppc/api/sogou'
3
+ require 'ppc/api/qihu'
4
+
5
+ module PPC
6
+ module API
7
+ attr_reader :header,:body,:rquota,:quota,:status,:desc,:oprs,:oprtime,:code,:message
8
+ attr_accessor :username,:password,:token,:debug
9
+ end
10
+ end
@@ -0,0 +1,138 @@
1
+ # -*- coding:utf-8 -*-
2
+ require 'ppc/api/baidu/account'
3
+ require 'ppc/api/baidu/plan'
4
+ require 'ppc/api/baidu/bulk'
5
+ require 'ppc/api/baidu/group'
6
+ require 'ppc/api/baidu/keyword'
7
+ require 'ppc/api/baidu/report'
8
+ require 'ppc/api/baidu/creative'
9
+ require 'awesome_print'
10
+ require 'net/http'
11
+ require 'net/https'
12
+ require 'json'
13
+ module PPC
14
+ module API
15
+ class Baidu
16
+
17
+ @map = nil
18
+ @@debug = false
19
+
20
+ def self.debug_on
21
+ @@debug = true
22
+ end
23
+
24
+ def self.debug_off
25
+ @@debug = false
26
+ end
27
+
28
+ def self.request( auth, service, method, params = {} )
29
+ '''
30
+ request should return whole http response including header
31
+ '''
32
+ uri = URI("https://api.baidu.com/json/sms/v3/#{service}Service/#{method}")
33
+ http_body = {
34
+ header: {
35
+ username: auth[:username],
36
+ password: auth[:password],
37
+ token: auth[:token]
38
+ },
39
+ body: params
40
+ }.to_json
41
+
42
+ http_header = {
43
+ 'Content-Type' => 'application/json; charset=UTF-8'
44
+ }
45
+
46
+ http = Net::HTTP.new(uri.host, 443)
47
+ # 是否显示http通信输出
48
+ http.set_debug_output( $stdout ) if @@debug
49
+ http.use_ssl = true
50
+
51
+ response = http.post(uri.path, http_body, http_header)
52
+ response = JSON.parse( response.body )
53
+ end
54
+
55
+ def self.process( response, key, &func)
56
+ '''
57
+ Process Http response. If operation successes, return value of given keys.
58
+ You can process the result using function &func, or do nothing by passing
59
+ block {|x|x}
60
+ ===========================
61
+ @Output: resultType{ desc: boolean, failure: Array, result: Array }
62
+
63
+ failure is the failures part of response\'s header
64
+ result is the processed response body.
65
+ '''
66
+ result = {}
67
+ result[:succ] = response['header']['desc']=='success'? true : false
68
+ result[:failure] = response['header']['failures']
69
+ result[:result] = func[ response['body'][key] ]
70
+ return result
71
+ end # process
72
+
73
+ def self.make_type( params, map = @map)
74
+ '''
75
+ tranfesr ppc api to search engine api
76
+ @ input
77
+ params : list of hash complying with PPC gem api
78
+ map : list of pairs(lists) of symbol complying with following api
79
+ map = [
80
+ [ ppc_key, api_key ],
81
+ [ ppc_key, api_key ],
82
+ [ ppc_key, api_key ],
83
+ ...
84
+ ]
85
+ Ex:
86
+ baidu_group_map = [ [ :id, :adgroupId],
87
+ [ :price, :maxPrice],
88
+ ... ]
89
+ ===================
90
+ @ output:
91
+ types : list of hash that complying with search engine api
92
+ '''
93
+ params = [ params ] unless params.is_a? Array
94
+
95
+ types = []
96
+ params.each do |param|
97
+ type = {}
98
+
99
+ map.each do |key|
100
+ value = param[ key[0] ]
101
+ type[ key[1] ] = value if value != nil
102
+ end
103
+
104
+ types << type
105
+ end
106
+ return types
107
+ end
108
+
109
+ def self.reverse_type( types, map = @map )
110
+ '''
111
+ transfer search engine api to ppc api
112
+ @ input
113
+ types : list of hash that complying with search engine api
114
+ map : list of pairs(lists) of symbol, for more details please
115
+ read docs of make_type()
116
+ ===================
117
+ @ output:
118
+ params : list of hash complying with PPC gem api
119
+ '''
120
+ types = [ types ] unless types.is_a? Array
121
+
122
+ params = []
123
+ types.each do |type|
124
+ param = {}
125
+
126
+ map.each do |key|
127
+ value = type[ key[1].to_s ]
128
+ param[ key[0] ] = value if value != nil
129
+ end
130
+
131
+ params << param
132
+ end
133
+ return params
134
+ end
135
+
136
+ end # Baidu
137
+ end # API
138
+ end # PPC
@@ -0,0 +1,47 @@
1
+ module PPC
2
+ module API
3
+ class Baidu
4
+ class Account< Baidu
5
+ Service = 'Account'
6
+
7
+ @map = [
8
+ [:id,:userid],
9
+ [:balance,:balance],
10
+ [:cost,:cost],
11
+ [:payment,:payment],
12
+ [:status,:userStat],
13
+ [:budget_type,:budgetType],
14
+ [:budget,:budget],
15
+ [:region,:regionTarget],
16
+ [:exclude_ip,:excludeIp],
17
+ [:isdynamic,:isDynamicCreative],
18
+ [:dynamic_param,:dynamicCreativeParam],
19
+ [:open_domains,:openDomains],
20
+ [:reg_domain,:regDomain],
21
+ [:offline_time,:budgetOfflineTime],
22
+ [:weekly_budget,:weeklyBudget],
23
+ [:opt,:opt]
24
+ ]
25
+
26
+ def self.info( auth )
27
+ response = request(auth,Service,'getAccountInfo' )
28
+ return process( response, 'accountInfoType' ){ |x|reverse_type(x)[0] }
29
+ end
30
+
31
+ def self.update(auth, param = {} )
32
+ """
33
+ update account info
34
+ @ params : account_info_type
35
+ @return : account info_type
36
+ """
37
+ # for account service, there is not bulk operation
38
+ infoType = make_type( param )[0]
39
+ body = { accountInfoType: infoType }
40
+ response = request(auth,Service,'updateAccountInfo', body)
41
+ return process( response, 'accountInfoType' ){ |x|reverse_type(x)[0] }
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,41 @@
1
+ module PPC
2
+ module API
3
+ class Baidu
4
+ class Bulk < Baidu
5
+ Service = 'BulkJob'
6
+
7
+ def self.get_all_object( auth,params = {})
8
+
9
+ plan_ids = params[:plan_ids]
10
+
11
+ unless plan_ids.nil?
12
+ plan_ids = plan_ids.class == Array ? plan_ids : [plan_ids]
13
+ end
14
+
15
+ options = {
16
+ campaignIds: plan_ids || [] ,
17
+ includeQuality: params[:quality] || true ,
18
+ includeTemp: params[:temp] || false ,
19
+ format: params[:format] || 1 ,
20
+ newCreativeFiles: params[:adcopy] || 0 ,
21
+ includeTempNewCreatives: params[:temp_adcopy] || 0 ,
22
+ includePhraseType: params[:phrase] || 0 ,
23
+ extended: params[:extended] || 0
24
+ }
25
+ response = request( auth, Service, 'getAllObjects',options )
26
+ response[:get_all_objects_response][:file_id]
27
+ end
28
+
29
+ def self.state( auth, id)
30
+ raise "empty id" if id.nil? or id.empty?
31
+ request(auth, Service, 'getFileState',{fileId:id})[:get_file_state_response][:is_generated]
32
+ end
33
+
34
+ def self.path( auth, id)
35
+ request( auth, Service, 'getFilePath',{fileId:id})[:get_file_path_response][:file_paths]
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,125 @@
1
+ # -*- coding:utf-8 -*-
2
+ module PPC
3
+ module API
4
+ class Baidu
5
+ class Creative< Baidu
6
+ Service = 'Creative'
7
+
8
+ @map =[
9
+ [:id,:creativeId],
10
+ [:group_id,:adgroupId],
11
+ [:title,:title],
12
+ [:description1,:description1],
13
+ [:description2,:description2],
14
+ [:pc_destination,:pcDestinationUrl],
15
+ [:pc_display,:pcDisplayUrl],
16
+ [:moile_destination,:mobileDestinationUrl],
17
+ [:mobile_display,:mobileDisplayUrl],
18
+ [:pause,:pause],
19
+ [:preference,:devicePreference]
20
+ ]
21
+
22
+ def self.add( auth, creatives )
23
+ body = { creativeTypes: make_type( creatives ) }
24
+ response = request( auth, Service, 'addCreative', body )
25
+ process( response, 'creativeTypes' ){ |x| reverse_type(x) }
26
+ end
27
+
28
+ def self.get( auth, ids, getTemp = 0 )
29
+ '''
30
+ \'getCreativeByCreativeId\'
31
+ @ input : creative ids
32
+ @ output: creative informations
33
+ '''
34
+ ids = [ ids ] unless ids.is_a? Array
35
+ body = { creativeIds: ids, getTemp: getTemp }
36
+ response = request( auth, Service, 'getCreativeByCreativeId', body )
37
+ process( response, 'creativeTypes' ){ |x| reverse_type(x) }
38
+ end
39
+
40
+ def self.update( auth, creatives )
41
+ '''
42
+ 根据实际使用情况,更新的时候creative title为必填选
43
+ '''
44
+ body = { creativeTypes: make_type( creatives ) }
45
+ response = request( auth, Service, 'updateCreative', body )
46
+ process( response, 'creativeTypes' ){ |x| reverse_type(x) }
47
+ end
48
+
49
+ def self.delete( auth, ids )
50
+ ids = [ ids ] unless ids.is_a? Array
51
+ body = { creativeIds: ids }
52
+ response = request( auth, Service, 'deleteCreative', body )
53
+ process( response, 'result' ){ |x| x }
54
+ end
55
+
56
+ def self.activate( auth, ids )
57
+ ids = [ ids ] unless ids.is_a? Array
58
+ body = { creativeIds: ids }
59
+ response = request( auth, Service, 'activateCreative', body )
60
+ process( response, 'creativeTypes' ){ |x| reverse_type(x) }
61
+ end
62
+
63
+ def self.status( auth, ids, type )
64
+ ids = [ ids ] unless ids.is_a? Array
65
+
66
+ type = case type
67
+ when 'plan' then 3
68
+ when 'group' then 5
69
+ when 'creative' then 7
70
+ else
71
+ Exception.new( 'type must among: \'plan\',\'group\' and \'key\' ')
72
+ end
73
+
74
+ body = { ids: ids, type: type }
75
+ response = request( auth, Service, 'getCreativeStatus', body )
76
+ process( response, 'CreativeStatus' ){ |x| x }
77
+ end
78
+
79
+ def self.search_id_by_group_id( auth, ids, getTemp = 0 )
80
+ '''
81
+ \'getCreativeIdByAdgroupId\'
82
+ @ input: group ids
83
+ @ output: groupCreativeIds
84
+ '''
85
+ ids = [ ids ] unless ids.is_a? Array
86
+ body = { adgroupIds: ids, getTemp: getTemp }
87
+ response = request( auth, Service, 'getCreativeIdByAdgroupId', body )
88
+ process( response, 'groupCreativeIds' ){ |x| make_groupCreativeIds( x ) }
89
+ end
90
+
91
+ def self.search_by_group_id( auth, ids, getTemp = 0 )
92
+ ids = [ ids ] unless ids.is_a? Array
93
+ body = { adgroupIds: ids, getTemp: getTemp }
94
+ response = request( auth, Service, 'getCreativeByAdgroupId', body )
95
+ process( response, 'groupCreatives' ){ |x| make_groupCreatives( x ) }
96
+ end
97
+
98
+ private
99
+ def self.make_groupCreativeIds( groupCreativeIds )
100
+ group_creative_ids = []
101
+ groupCreativeIds.each do |groupCreativeId|
102
+ group_creative_id = { }
103
+ group_creative_id[:group_id] = groupCreativeId['adgroupIds']
104
+ group_creative_id[:creative_ids] = groupCreativeId['creativeIds']
105
+ group_creative_ids << group_creative_id
106
+ end
107
+ return group_creative_ids
108
+ end
109
+
110
+ private
111
+ def self.make_groupCreatives( groupCreatives )
112
+ group_creatives = []
113
+ groupCreatives.each do |groupCreative |
114
+ group_creative = {}
115
+ group_creative[:group_id] = groupCreative['adgroupId']
116
+ group_creative[:creatives] = reverse_type( groupCreative['creativeTypes'] )
117
+ group_creatives << group_creative
118
+ end
119
+ return group_creatives
120
+ end
121
+
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,111 @@
1
+ # -*- coding:utf-8 -*-
2
+ module PPC
3
+ module API
4
+ class Baidu
5
+ class Group< Baidu
6
+ Service = 'Adgroup'
7
+
8
+ @map =[
9
+ [:plan_id, :campaignId],
10
+ [:id, :adgroupId],
11
+ [:name, :adgroupName],
12
+ [:price, :maxPrice],
13
+ [:negative, :negativeWords],
14
+ [:exact_negative, :exactNegativeWords],
15
+ [:pause, :pause],
16
+ [:status, :status],
17
+ [:reserved, :reserved]
18
+ ]
19
+
20
+ def self.ids(auth )
21
+ """
22
+ @return : Array of campaignAdgroupIds
23
+ """
24
+ response = request( auth, Service , "getAllAdgroupId" )
25
+ process( response, 'campaignAdgroupIds' ){ |x| make_planGroupIds( x ) }
26
+ end
27
+
28
+ def self.get( auth, ids )
29
+ ids = [ ids ] unless ids.is_a? Array
30
+ body = { adgroupIds: ids }
31
+ response = request(auth, Service, "getAdgroupByAdgroupId",body )
32
+ process( response, 'adgroupTypes' ){ |x| reverse_type(x) }
33
+ end
34
+
35
+ def self.add( auth, groups )
36
+ """
37
+ @ input : one or list of AdgroupType
38
+ @ output : list of AdgroupType
39
+ """
40
+ adgrouptypes = make_type( groups )
41
+
42
+ body = {adgroupTypes: adgrouptypes }
43
+
44
+ response = request( auth, Service, "addAdgroup", body )
45
+ process( response, 'adgroupTypes' ){ |x| reverse_type(x) }
46
+ end
47
+
48
+ def self.update( auth, groups )
49
+ """
50
+ @ input : one or list of AdgroupType
51
+ @ output : list of AdgroupType
52
+ """
53
+ adgrouptypes = make_type( groups )
54
+ body = {adgroupTypes: adgrouptypes}
55
+
56
+ response = request( auth, Service, "updateAdgroup",body )
57
+ process( response, 'adgroupTypes' ){ |x| reverse_type(x) }
58
+ end
59
+
60
+ def self.delete( auth, ids )
61
+ """
62
+ delete group body has no message
63
+ """
64
+ ids = [ ids ] unless ids.is_a? Array
65
+ body = { adgroupIds: ids }
66
+ response = request( auth, Service,"deleteAdgroup", body )
67
+ process( response, 'nil' ){ |x| x }
68
+ end
69
+
70
+ def self.search_by_plan_id( auth, ids )
71
+ ids = [ ids ] unless ids.class == Array
72
+ body = { campaignIds: ids }
73
+ response = request( auth, Service ,"getAdgroupByCampaignId", body )
74
+ process( response, 'campaignAdgroups' ){ |x| make_planGroups( x ) }
75
+ end
76
+
77
+ def self.search_id_by_plan_id( auth, ids )
78
+ ids = [ ids ] unless ids.class == Array
79
+ body = { campaignIds: ids }
80
+ response = request( auth, Service ,"getAdgroupIdByCampaignId", body )
81
+ process( response, 'campaignAdgroupIds' ){ |x| make_planGroupIds( x ) }
82
+ end
83
+
84
+ private
85
+ def self.make_planGroupIds( campaignAdgroupIds )
86
+ planGroupIds = []
87
+ campaignAdgroupIds.each do |campaignAdgroupId|
88
+ planGroupId = { }
89
+ planGroupId[:plan_id] = campaignAdgroupId['campaignId']
90
+ planGroupId[:group_ids] = campaignAdgroupId['adgroupIds']
91
+ planGroupIds << planGroupId
92
+ end
93
+ return planGroupIds
94
+ end
95
+
96
+ private
97
+ def self.make_planGroups( campaignAdgroups )
98
+ planGroups = []
99
+ campaignAdgroups.each do |campaignAdgroup|
100
+ planGroup = {}
101
+ planGroup[:plan_id] = campaignAdgroup['campaignId']
102
+ planGroup[:groups] = reverse_type( campaignAdgroup['adgroupTypes'] )
103
+ planGroups << planGroup
104
+ end
105
+ return planGroups
106
+ end
107
+
108
+ end # class group
109
+ end # class baidu
110
+ end # API
111
+ end # module