ppc 1.3.2 → 2.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +21 -339
  3. data/README.md +46 -28
  4. data/Rakefile +1 -0
  5. data/lib/ppc.rb +1 -1
  6. data/lib/ppc/api.rb +18 -14
  7. data/lib/ppc/api/baidu.rb +5 -14
  8. data/lib/ppc/api/baidu/account.rb +28 -23
  9. data/lib/ppc/api/baidu/bulk.rb +1 -1
  10. data/lib/ppc/api/baidu/creative.rb +47 -86
  11. data/lib/ppc/api/baidu/group.rb +43 -74
  12. data/lib/ppc/api/baidu/keyword.rb +73 -166
  13. data/lib/ppc/api/baidu/phone_new_creative.rb +8 -7
  14. data/lib/ppc/api/baidu/plan.rb +51 -34
  15. data/lib/ppc/api/baidu/report.rb +9 -29
  16. data/lib/ppc/api/qihu.rb +7 -111
  17. data/lib/ppc/api/qihu/account.rb +31 -25
  18. data/lib/ppc/api/qihu/bulk.rb +1 -2
  19. data/lib/ppc/api/qihu/creative.rb +57 -74
  20. data/lib/ppc/api/qihu/group.rb +40 -63
  21. data/lib/ppc/api/qihu/keyword.rb +58 -74
  22. data/lib/ppc/api/qihu/plan.rb +52 -32
  23. data/lib/ppc/api/qihu/rank.rb +11 -10
  24. data/lib/ppc/api/qihu/report.rb +41 -94
  25. data/lib/ppc/api/qihu/sublink.rb +44 -41
  26. data/lib/ppc/api/sm.rb +3 -12
  27. data/lib/ppc/api/sm/account.rb +20 -19
  28. data/lib/ppc/api/sm/creative.rb +36 -50
  29. data/lib/ppc/api/sm/group.rb +40 -61
  30. data/lib/ppc/api/sm/keyword.rb +44 -102
  31. data/lib/ppc/api/sm/phone_new_creative.rb +9 -8
  32. data/lib/ppc/api/sm/plan.rb +36 -26
  33. data/lib/ppc/api/sm/report.rb +5 -24
  34. data/lib/ppc/api/sogou.rb +5 -55
  35. data/lib/ppc/api/sogou/account.rb +17 -17
  36. data/lib/ppc/api/sogou/creative.rb +52 -75
  37. data/lib/ppc/api/sogou/group.rb +44 -91
  38. data/lib/ppc/api/sogou/keyword.rb +60 -143
  39. data/lib/ppc/api/sogou/plan.rb +37 -23
  40. data/lib/ppc/api/sogou/report.rb +2 -19
  41. data/lib/ppc/ext.rb +0 -8
  42. data/lib/ppc/operation.rb +60 -83
  43. data/lib/ppc/operation/account.rb +13 -19
  44. data/lib/ppc/operation/creative.rb +0 -20
  45. data/lib/ppc/operation/group.rb +18 -27
  46. data/lib/ppc/operation/keyword.rb +0 -27
  47. data/lib/ppc/operation/plan.rb +34 -22
  48. data/lib/ppc/operation/report.rb +4 -4
  49. data/lib/ppc/operation/sublink.rb +8 -0
  50. data/ppc.gemspec +5 -5
  51. metadata +16 -10
  52. data/lib/ppc/api/shenma.rb +0 -64
  53. data/lib/ppc/api/shenma/report.rb +0 -135
@@ -5,102 +5,86 @@ module PPC
5
5
  class Keyword< Qihu
6
6
  Service = 'keyword'
7
7
 
8
- @map = [
9
- [:id, :id],
10
- [:group_id, :groupId],
11
- [:keyword, :word],
12
- [:price, :price],
13
- [:match_type, :matchType],
14
- [:pc_destination, :url],
15
- [:mobile_destination, :mobileUrl],
16
- [:status, :status]
17
- ]
8
+ KeywordType = {
9
+ id: :id,
10
+ group_id: :groupId,
11
+ keyword: :word,
12
+ price: :price,
13
+ match_type: :matchType,
14
+ pc_destination: :url,
15
+ "pc_destination" => :destinationUrl,
16
+ mobile_destination: :mobileUrl,
17
+ "mobile_destination" => :mobileDestinationUrl,
18
+ pause: :status,
19
+ mobile_pause: :mobileStatus,
20
+ add_time: :addTime,
21
+ update_time: :updateTime,
22
+ }
23
+ @map = KeywordType
18
24
 
19
- @status_map = [
20
- [:id,:id],
21
- [:quality,:qualityScore],
22
- [:status,:status]
23
- ]
25
+ @status_map = {
26
+ id: :id,
27
+ pc_quality: :qualityScore,
28
+ mobile_quality: :mobileQualityScore,
29
+ pause: :status,
30
+ mobile_pause: :mobileStatus,
31
+ pc_lowest_price: :pcLowestPrice,
32
+ mobile_lowest_price: :mobileLowestPrice,
33
+ }
34
+
35
+ def self.info( auth, ids )
36
+ response = request( auth, Service, 'getInfoByIdList', { idList: ids } )
37
+ process( response, 'keywordList'){ |x| reverse_type(x)[0] }
38
+ end
39
+
40
+ # combine search_id and get to provide another method
41
+ def self.all( auth, group_id )
42
+ results = self.ids( auth, group_id )
43
+ return results unless results[:succ]
44
+ self.get( auth , results[:result] )
45
+ end
46
+
47
+ def self.ids( auth, group_id )
48
+ response = request( auth, Service, 'getIdListByGroupId', {'groupId' => group_id[0]} )
49
+ process( response, 'keywordIdList' ){ |x| x.map(&:to_i) }
50
+ end
24
51
 
25
52
  def self.get( auth, ids )
26
- ids = to_json_string( ids )
27
- body = { 'idList' => ids }
28
- response = request( auth, Service, 'getInfoByIdList', body )
53
+ response = request( auth, Service, 'getInfoByIdList', { idList: ids } )
29
54
  process( response, 'keywordList'){ |x| reverse_type(x) }
30
55
  end
31
56
 
32
57
  def self.add( auth, keywords )
33
- keyword_types = make_type( keywords ).to_json
34
- body = { 'keywords' => keyword_types}
35
- response = request( auth, Service, 'add', body )
36
- p response
37
- process( response, 'keywordIdList'){ |x| to_id_hash_list(x) }
58
+ response = request( auth, Service, 'add', { keywords: make_type( keywords )} )
59
+ process( response, 'keywordIdList'){ |x| x.map.with_index{|id, index| {id: id, keyword: keywords[index][:word]}} }
38
60
  end
39
61
 
40
- # helper function for self.add() method
41
- private
42
- def self.to_id_hash_list( str )
43
- reuturn [] if str == nil
44
- str = [str] unless str.is_a?Array
45
- x= []
46
- str.each{ |i| x << { id: i.to_i } }
47
- return x
62
+ def self.update( auth, keywords )
63
+ response = request( auth, Service, 'update', { keywords: make_type( keywords )} )
64
+ process( response, 'affectedRecords', 'failKeywordIds' ){ |x| x == keywords.size ? keywords.map{|keyword| {id: keyword[:id]}} : nil }
48
65
  end
49
66
 
50
- def self.update( auth, keywords )
51
- keyword_types = make_type( keywords ).to_json
52
- body = { 'keywords' => keyword_types}
53
- response = request( auth, Service, 'update', body )
54
- process( response, 'affectedRecords', 'failKeywordIds' ){ |x| x }
67
+ def self.delete( auth, ids )
68
+ response = request( auth, Service, 'deleteByIdList', { idList: ids } )
69
+ process( response, 'affectedRecords' ){ |x| x == keywords.size ? keywords.map{|keyword| {id: keyword[:id]}} : nil }
55
70
  end
56
71
 
57
- # 对update的再封装实现activate方法
58
- def self.activate( auth, ids )
59
- keywords = []
60
- ids.each{ |id| keywords << { id: id, status:'enable'} }
61
- update( auth, keywords )
72
+ def self.enable( auth, ids )
73
+ self.update( auth, ids.map{ |id| { id: id, pause:'enable'} } )
62
74
  end
63
75
 
64
- def self.delete( auth, ids )
65
- body = { 'idList' => to_json_string( ids ) }
66
- response = request( auth, Service, 'deleteByIdList', body )
67
- process( response, 'affectedRecords' ){ |x| x }
76
+ def self.pause( auth, ids )
77
+ self.update( auth, ids.map{ |id| { id: id, pause:'pause'} } )
68
78
  end
69
79
 
70
80
  def self.status( auth, ids )
71
- body = { idList: to_json_string( ids ) }
72
- response = request( auth, Service, 'getStatusByIdList', body )
73
- process( response, 'keywordList' ){ |x| reverse_type(x, @status_map) }
81
+ response = request( auth, Service, 'getStatusByIdList', { idList: ids } )
82
+ process( response, 'keywordList' ){ |x| reverse_type(x, @status_map) }
74
83
  end
75
84
 
76
85
  # quality 本质上和 status 在一个方法里面
77
86
  def self.quality( auth, ids )
78
- status( auth, ids)
79
- end
80
-
81
- def self.search_id_by_group_id( auth, id, status = nil, match_type = nil )
82
- # 处理条件
83
- body = {}
84
- body['status'] = status if status
85
- body['matchType'] = match_type if match_type
86
- body['groupId'] = id
87
- response = request( auth, Service, 'getIdListByGroupId', body )
88
- # 伪装成百度接口
89
- process( response, 'keywordIdList' ){
90
- |x|
91
- [{group_id:id, keyword_ids:to_id_list(x)}]
92
- }
93
- end
94
-
95
- # combine search_id and get to provide another method
96
- def self.search_by_group_id( auth, id )
97
- keyword_ids = search_id_by_group_id( auth, id )[:result][0][:keyword_ids]
98
- response = get( auth, keyword_ids )
99
- if response[:succ]
100
- # 伪装成百度接口
101
- response[:result] = [ { group_id:id, keywords:response[:result] } ]
102
- end
103
- return response
87
+ self.status( auth, ids)
104
88
  end
105
89
 
106
90
  def self.getChangedIdList
@@ -5,59 +5,79 @@ module PPC
5
5
  class Plan < Qihu
6
6
  Service = 'campaign'
7
7
 
8
- @map = [
9
- [:id, :id],
10
- [:name,:name],
11
- [:budget, :budget],
12
- [:region, :region],
13
- [:schedule, :schedule],
14
- [:startDate, :startDate],
15
- [:endDate, :endDate ],
16
- [:status,:status],
17
- [:extend_ad_type,:extendAdType]
18
- ]
8
+ PlanType = {
9
+ id: :id,
10
+ name: :name,
11
+ budget: :budget,
12
+ region: :region,
13
+ search_intention: :searchIntention,
14
+ schedule: :schedule,
15
+ start_date: :startDate,
16
+ end_date: :endDate,
17
+ status: :sysStatus,
18
+ pause: :status,
19
+ add_time: :addTime,
20
+ update_time: :updateTime,
21
+ price_ratio: :mobilePriceRate,
22
+ extend_adtype: :extendAdType,
23
+ "negative" => :negtiveWords,
24
+ negative: :negativeWords,
25
+ "exact_negative" => :exactNegtiveWords,
26
+ exact_negative: :exactNegativeWords,
27
+ device: :device,
28
+ is_precise: :isPrecise,
29
+ }
30
+ @map = PlanType
19
31
 
32
+ def self.info(auth, ids)
33
+ response = request( auth, Service, 'getInfoByIdList', {idList: ids} )
34
+ process( response, 'campaignList' ){ |x| reverse_type(x)[0] }
35
+ end
20
36
 
21
- def self.get(auth, ids)
22
- '''
23
- :Type ids: ( Array of ) String or integer
24
- '''
25
- ids = to_json_string( ids )
26
- body = {'idList' => ids}
27
- response = request( auth, Service, 'getInfoByIdList', body )
28
- process( response, 'campaignList' ){ |x| reverse_type(x) }
37
+ # combine two original method to provice new method
38
+ def self.all( auth )
39
+ self.get( auth, self.ids( auth )[:result] )
29
40
  end
30
41
 
31
- # move getCampaignId to plan module for operation call
42
+ # move getCampaignId to plan module for operation call
32
43
  def self.ids( auth )
33
44
  response = request( auth, 'account', 'getCampaignIdList' )
34
- process( response, 'campaignIdList' ){ |x| to_id_list(x)}
45
+ process( response, 'campaignIdList' ){ |x| x.map(&:to_i) }
35
46
  end
36
47
 
37
- # combine two original method to provice new method
38
- def self.all( auth )
39
- plan_ids = ids( auth )[:result]
40
- get( auth, plan_ids )
48
+ def self.get(auth, ids)
49
+ response = request( auth, Service, 'getInfoByIdList', {idList: ids} )
50
+ process( response, 'campaignList' ){ |x| reverse_type(x) }
41
51
  end
42
52
 
43
53
  # 奇虎计划API不提供批量服务
44
54
  def self.add( auth, plan )
45
- response = request( auth, Service, 'add', make_type( plan )[0])
46
- # 这里将返回的简单int做一个array和hash的封装一保证接口和百度,搜狗的一致性
47
- process( response, 'id' ){ |x| [ { id:x.to_i } ] }
55
+ plan[0][:negative] = {exact: plan[0].delete(:exact_negative), phrase: plan[0].delete(:negative)}.to_json if plan[0][:exact_negative] || plan[0][:negative]
56
+ params = make_type(plan)[0]
57
+ response = request( auth, Service, 'add', params )
58
+ process( response, 'id' ){ |x| [ { id:x.to_i, name: plan[0][:name]} ] }
48
59
  end
49
60
 
50
- def self.update( auth, plan )
51
- response = request( auth, Service, 'update', make_type( plan )[0])
52
- #同上,保证接口一致性
61
+ def self.update( auth, plan )
62
+ plan[0][:negative] = {exact: plan[0].delete(:exact_negative), phrase: plan[0].delete(:negative)}.to_json if plan[0][:exact_negative] || plan[0][:negative]
63
+ params = make_type(plan)[0]
64
+ response = request( auth, Service, 'update', params )
53
65
  process( response, 'id' ){ |x| [ { id:x.to_i } ] }
54
66
  end
55
67
 
56
68
  def self.delete( auth, id )
57
- response = request( auth, Service, 'deleteById', { id: id } )
69
+ response = request( auth, Service, 'deleteById', { id: id[0] } )
58
70
  process( response, 'affectedRecords' ){ |x| x == '1'? 'success' : 'fail' }
59
71
  end
60
72
 
73
+ def self.enable( auth, id )
74
+ self.update(auth, {id: id[0], pause: "enable"})
75
+ end
76
+
77
+ def self.pause( auth, id )
78
+ self.update(auth, {id: id[0], pause: "pause"})
79
+ end
80
+
61
81
  end
62
82
  end
63
83
  end
@@ -4,19 +4,20 @@ module PPC
4
4
  class Rank < Qihu
5
5
  Service = 'tool'
6
6
 
7
- @map = [
8
- [:id,:id] ,
9
- [:group_id, :groupId],
10
- [:anchor,:text],
11
- [:url, :link],
12
- [:image, :image],
13
- [:status, :status]
14
- ]
7
+ RankType = {
8
+ id: :id,
9
+ group_id: :groupId,
10
+ anchor: :text,
11
+ url: :link,
12
+ image: :image,
13
+ status: :status,
14
+ }
15
+ @map = RankType
15
16
 
16
17
  def self.getRank( auth, region, queryInfo )
17
18
  body = {'region'=> region, 'queryInfo' => queryInfo}
18
- response = request(auth, Service, 'realTimeQueryResult', body)
19
- # process( response, 'sublinkList'){ |x| reverse_type( x['item'] ) }
19
+ response = request( auth, Service, 'realTimeQueryResult', body)
20
+ process( response, "" ){|x| x["left"]["ranking"]}
20
21
  end
21
22
 
22
23
  end
@@ -7,44 +7,41 @@ module PPC
7
7
  class Report< Qihu
8
8
  Service = 'report'
9
9
 
10
- @map =[
11
- [:queryword,:queryword],
12
- [:plan_id,:campaignId],
13
- [:creative_id,:creativeId],
14
- [:keyword,:keyword],
15
- [:views,:views],
16
- [:clicks,:clicks],
17
- [:startDate,:startDate],
18
- [:endDate,:endDate],
19
- [:date,:date],
20
- [:keyword_id,:keywordId],
21
- [:group_id,:groupId],
22
- [:cost,:totalCost],
23
- [:position,:avgPosition],
24
- [:total_num,:totalNumber],
25
- [:total_page,:totalPage]
26
- ]
10
+ ReportType = {
11
+ queryword: :queryword,
12
+ plan_id: :campaignId,
13
+ creative_id: :creativeId,
14
+ keyword: :keyword,
15
+ views: :views,
16
+ clicks: :clicks,
17
+ startDate: :startDate,
18
+ endDate: :endDate,
19
+ date: :date,
20
+ keyword_id: :keywordId,
21
+ group_id: :groupId,
22
+ cost: :totalCost,
23
+ position: :avgPosition,
24
+ total_num: :totalNumber,
25
+ total_page: :totalPage,
26
+ }
27
+ @map = ReportType
27
28
 
28
29
  ###################
29
30
  # API abstraction #
30
31
  ###################
31
32
  def self.abstract( auth, type_name, method_name, key, param = nil, &func )
32
- body = make_type( param )
33
- response = request( auth, Service, method_name, body )
33
+ response = request( auth, Service, method_name, make_type( param ) )
34
34
  process( response, key ){ |x| func[ x ] }
35
35
  end
36
36
 
37
- type_list = ['keyword', 'query', 'creative', 'sublink']
38
- type_list.each do |type|
37
+ %w(keyword query creative sublink).each do |type|
39
38
  # type
40
39
  define_singleton_method type.to_sym do |auth, param|
41
40
  abstract( auth, type, type, type+'List', param ){ |x| x}
42
41
  end
43
42
  # typeCount
44
43
  define_singleton_method (type+'_count').to_sym do |auth, param|
45
- response = abstract( auth, type, type+'Count', '', param ){ |x| get_item(x) }
46
- response[:result] = response[:result][0]
47
- return response
44
+ abstract( auth, type, type+'Count', '', param ){ |x| reverse_type( x )[0] }
48
45
  end
49
46
  # typeNow
50
47
  define_singleton_method (type+'_now').to_sym do |auth, param|
@@ -52,9 +49,7 @@ module PPC
52
49
  end
53
50
  # typeNowCount
54
51
  define_singleton_method (type+'_now_count').to_sym do |auth, param|
55
- response = abstract( auth, type, type+'NowCount', '', param ){ |x| get_item(x) }
56
- response[:result] = response[:result][0]
57
- return response
52
+ abstract( auth, type, type+'NowCount', '', param ){ |x| reverse_type( x )[0] }
58
53
  end
59
54
  end
60
55
 
@@ -71,86 +66,38 @@ module PPC
71
66
 
72
67
  def self.download_report(auth, type, param, debug = false)
73
68
  # deal_with time
74
- now = Time.now.to_s[0...10]
75
- is_now = now==parse_date(param[:startDate])
69
+ is_now = Date.today == Date.parse(param[:startDate])
76
70
 
77
71
  # get page num
78
- if is_now
79
- method = (type+'_now_count').to_sym
80
- count = send(method, auth, param)[:result]
81
- method = (type+'_now').to_sym
82
- else
83
- method = (type+'_count').to_sym
84
- count = send(method, auth, param)[:result]
85
- method = type.to_sym
86
- end
72
+ method = (type+ (is_now ? '_now' : '') + '_count').to_sym
73
+ response = send(method, auth, param)
74
+ count = response[:result]
75
+ method = (type+ (is_now ? '_now' : '')).to_sym
87
76
 
88
- report = []
89
- count[:total_page].to_i.times do | page_i|
90
- p "Start downloading #{page_i+1}th page, totally #{count[:total_page]} pages"
91
- param[:page] = page_i +1
92
- report_i = send(method, auth, param)[:result]
93
- report += report_i
77
+ if count && count[:total_page]
78
+ count[:total_page].to_i.times.map{ | page_i|
79
+ p "Start downloading #{page_i+1}th page, totally #{count[:total_page]} pages"
80
+ param[:page] = page_i +1
81
+ send(method, auth, param)[:result]
82
+ }.flatten
83
+ else
84
+ response
94
85
  end
95
-
96
- return report
97
86
  end
98
87
 
99
88
  ###################
100
89
  # Helper Function #
101
90
  ###################
102
91
  # incase idlist == nil
103
- private
104
- def self.get_item( params )
105
- return nil if params == nil
106
- return reverse_type( params )
107
- end
108
92
 
109
93
  private
110
94
  def self.make_type( param )
111
- type = {}
112
- # add option
113
- type[:level] = param[:level] || 'account'
114
- type[:page] = param[:page] || 1
115
- # add ids
116
- if param[:ids] != nil
117
- ids = param[:ids]
118
- ids = [ ids ] unless ids.is_a? Array
119
- type[:IdList] = ids.to_json
120
- end
121
- # add date
122
- if param[:startDate]==nil || param[:endDate]==nil
123
- type[:startDate], type[:endDate] = get_date()
124
- else
125
- type[:startDate] = parse_date( param[:startDate] )
126
- type[:endDate] = parse_date( param[:endDate] )
127
- end
128
-
129
- return type
130
- end
131
-
132
- private
133
- def self.get_date()
134
- endDate = Time.now.to_s[0,10]
135
- startDate = (Time.now - 24*3600).to_s[0,10]
136
- return startDate,endDate
137
- end
138
-
139
- private
140
- def self.parse_date( date )
141
- """
142
- Cast string to time:
143
- 'YYYYMMDD' => Time
144
- """
145
- if date
146
- y = date[0..3]
147
- m = date[4..5]
148
- d = date[6..7]
149
- date = Time.new( y, m, d )
150
- else
151
- date = (Time.now - 24*3600)
152
- end
153
- date.to_s[0,10]
95
+ param[:level] ||= 'account'
96
+ param[:page] ||= 1
97
+ param[:IdList] = [param.delete(:ids)].flatten.map(&:to_s)
98
+ param[:startDate] = Date.parse(param[:startDate]).to_s rescue Date.today.to_s
99
+ param[:endDate] = Date.parse(param[:endDate]).to_s rescue Date.today.to_s
100
+ param
154
101
  end
155
102
 
156
103
  end # Report