ppc 0.3.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 (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