ppc 1.3.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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