sogou 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +58 -0
- data/Rakefile +1 -0
- data/lib/sogou/auth.rb +5 -0
- data/lib/sogou/ext.rb +46 -0
- data/lib/sogou/response.rb +15 -0
- data/lib/sogou/sem/account.rb +6 -0
- data/lib/sogou/sem/adgroup.rb +6 -0
- data/lib/sogou/sem/base.rb +100 -0
- data/lib/sogou/sem/campaign.rb +6 -0
- data/lib/sogou/sem/creative.rb +6 -0
- data/lib/sogou/sem/enum.rb +70 -0
- data/lib/sogou/sem/keyword.rb +6 -0
- data/lib/sogou/sem/report.rb +6 -0
- data/lib/sogou/sem.rb +8 -0
- data/lib/sogou/version.rb +3 -0
- data/lib/sogou.rb +11 -0
- data/sogou.gemspec +24 -0
- data/spec/sem_account_spec.rb +14 -0
- data/spec/sem_adgroup_spec.rb +120 -0
- data/spec/sem_campaign_spec.rb +94 -0
- data/spec/sem_creative_spec.rb +83 -0
- data/spec/sem_keyword_spec.rb +49 -0
- data/spec/sem_report_spec.rb +56 -0
- data/spec/spec_helper.rb +26 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 34ca740ff610ccc11d870a62c19a27598d665774
|
4
|
+
data.tar.gz: 2c8c3d3e28e7243cfbf26fbbd7098c6ccca0614f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7ce3c4afc5e97a99795a243c41e0719a3bad53b16c97d9334efaed7443e13cf8e3c81ad2f84cef3fba778b86211df8a4a6073bb0ea92e47984880521bf314130
|
7
|
+
data.tar.gz: 307392307a8daaa544c8ef86fbec772db420963058aed0c13383ff6749058b45876bc3bccf730be8100f16adbc72c14b2808e2a6ae6a73836801fcf65801fc96
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 刘明
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# Sogou
|
2
|
+
|
3
|
+
Sogou SEM Services
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'sogou'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install sogou
|
18
|
+
|
19
|
+
## Knowledge
|
20
|
+
camel命名法,用于request数据格式
|
21
|
+
snake命名法,用于response数据格式
|
22
|
+
|
23
|
+
## Rspec
|
24
|
+
先修改spec/spec_helper.rb
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
|
28
|
+
$username = ''
|
29
|
+
$password = ''
|
30
|
+
$token = ''
|
31
|
+
|
32
|
+
```
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
SEM
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
require 'sogou'
|
40
|
+
|
41
|
+
auth = Sogou::Auth.new
|
42
|
+
auth.username = 'username'
|
43
|
+
auth.password = 'password'
|
44
|
+
auth.token = 'token'
|
45
|
+
|
46
|
+
ss = Sogou::SEM::SearchService.new(auth)
|
47
|
+
res = ss.getAccountInfo({})
|
48
|
+
res = ss.getAccountInfo({},true) #debug=true
|
49
|
+
```
|
50
|
+
|
51
|
+
|
52
|
+
## Contributing
|
53
|
+
|
54
|
+
1. Fork it
|
55
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
56
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
57
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
58
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/sogou/auth.rb
ADDED
data/lib/sogou/ext.rb
ADDED
@@ -0,0 +1,46 @@
|
|
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
|
10
|
+
class Savon
|
11
|
+
class Response
|
12
|
+
def header
|
13
|
+
hash[:envelope][:header]
|
14
|
+
end
|
15
|
+
def res_header
|
16
|
+
header[:res_header]
|
17
|
+
end
|
18
|
+
def desc
|
19
|
+
res_header[:desc]
|
20
|
+
end
|
21
|
+
def quota
|
22
|
+
res_header[:quota]
|
23
|
+
end
|
24
|
+
def rquota
|
25
|
+
res_header[:rquota]
|
26
|
+
end
|
27
|
+
def oprs
|
28
|
+
res_header[:oprs]
|
29
|
+
end
|
30
|
+
def oprtime
|
31
|
+
res_header[:oprtime]
|
32
|
+
end
|
33
|
+
def failures
|
34
|
+
res_header[:failures]
|
35
|
+
end
|
36
|
+
def code
|
37
|
+
failures[:code] if failures
|
38
|
+
end
|
39
|
+
def message
|
40
|
+
failures[:message] if failures
|
41
|
+
end
|
42
|
+
def status
|
43
|
+
res_header[:status]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Sogou
|
2
|
+
class Response
|
3
|
+
attr_accessor :header,:body,:rquota,:quota,:status,:desc,:oprs,:oprtime
|
4
|
+
def initialize(response,name_response_sym)
|
5
|
+
@header = response.header[:res_header]
|
6
|
+
@body = response.body[name_response_sym]
|
7
|
+
@rquota = @header[:rquota].to_i
|
8
|
+
@quota = @header[:quota].to_i
|
9
|
+
@status = @header[:status].to_i
|
10
|
+
@desc = @header[:desc]
|
11
|
+
@oprs = @header[:oprs]
|
12
|
+
@oprtime = @header[:oprtime]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Sogou
|
2
|
+
module SEM
|
3
|
+
class Base
|
4
|
+
attr_accessor :username,:password,:token
|
5
|
+
attr_accessor :debug
|
6
|
+
|
7
|
+
def initialize(auth)
|
8
|
+
classname = self.class.name.split('::').last
|
9
|
+
@service_name =
|
10
|
+
case classname
|
11
|
+
when 'CampaignService'
|
12
|
+
'CpcPlanService'
|
13
|
+
when 'AccountService'
|
14
|
+
'AccountService'
|
15
|
+
when 'AdgroupService'
|
16
|
+
'CpcGrpService'
|
17
|
+
when 'KeywordService'
|
18
|
+
'CpcService'
|
19
|
+
when 'CreativeService'
|
20
|
+
'CpcIdeaService'
|
21
|
+
when 'ReportService'
|
22
|
+
'ReportService'
|
23
|
+
when 'DownloadService'
|
24
|
+
'AccountDownloadService'
|
25
|
+
when 'KRService'
|
26
|
+
'KRService'
|
27
|
+
end
|
28
|
+
|
29
|
+
@port_name = @service_name
|
30
|
+
@username = auth.username
|
31
|
+
@password = auth.password
|
32
|
+
@token = auth.token
|
33
|
+
@client = Savon.new("http://api.agent.sogou.com:8080/sem/sms/v1/#{@service_name}?wsdl")
|
34
|
+
|
35
|
+
# Savon.new(@base_uri+service_name+'?wsdl')
|
36
|
+
end
|
37
|
+
def method_missing(name, *args, &block)
|
38
|
+
options,debug = args[0],args[1]
|
39
|
+
options = {} if options.nil?
|
40
|
+
name = name.to_s
|
41
|
+
name_snake = name.snake_case
|
42
|
+
# p name
|
43
|
+
|
44
|
+
|
45
|
+
name_request_sym = (name +'Request').to_sym #if %w(getCampaignByCampaignId getAllCampaign addCampaign updateCampaign deleteCampaign).include?name
|
46
|
+
# puts name_request_sym
|
47
|
+
name_response_sym = (name+'Response').snake_case.to_sym
|
48
|
+
operation = make_operation(name)
|
49
|
+
operation.header = operation_header
|
50
|
+
operation.body = {
|
51
|
+
name_request_sym => options
|
52
|
+
}
|
53
|
+
ap operation.body if debug
|
54
|
+
puts operation.build if debug
|
55
|
+
response = operation.call
|
56
|
+
ap response if debug
|
57
|
+
# ap response.failures if debug
|
58
|
+
if response.failures
|
59
|
+
raise response.failures.to_s
|
60
|
+
else
|
61
|
+
Sogou::Response.new(response,name_response_sym)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
def operations
|
65
|
+
@client.operations(@service_name,@port_name)
|
66
|
+
end
|
67
|
+
|
68
|
+
def make_operation(operation_name)
|
69
|
+
@client.operation(@service_name,@port_name,operation_name)
|
70
|
+
end
|
71
|
+
|
72
|
+
def operation_header
|
73
|
+
{
|
74
|
+
:AuthHeader=>
|
75
|
+
{
|
76
|
+
:username=>@username,
|
77
|
+
:password=>@password,
|
78
|
+
:token=>@token
|
79
|
+
}
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
def example(operation,with_header=false)
|
84
|
+
operation = make_operation(operation)
|
85
|
+
if with_header
|
86
|
+
{
|
87
|
+
:example_header => operation.example_header,
|
88
|
+
:example_body => operation.example_body
|
89
|
+
}
|
90
|
+
else
|
91
|
+
operation.example_body
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# def invalid_options?(options,necessary_options)
|
96
|
+
# return true if necessary_options.any?{|necessary_option|!options.has_key?necessary_option}
|
97
|
+
# end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Sogou
|
2
|
+
module SEM
|
3
|
+
module Format
|
4
|
+
CSV = 2
|
5
|
+
end
|
6
|
+
|
7
|
+
module ReportState
|
8
|
+
PENDING = 1 #等待中
|
9
|
+
DOING = 2 #处理中
|
10
|
+
DONE = 3 #处理成功
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
module PerformanceData
|
15
|
+
COST = 'cost' #消费
|
16
|
+
CPC = 'cpc' #每个点击的消费
|
17
|
+
CLICK = 'click' #点击数
|
18
|
+
IMPRESSION = 'impression' #展示量
|
19
|
+
CTR = 'ctr' #转化率
|
20
|
+
CPM = 'cpm' #?
|
21
|
+
POSITION = 'position' #?
|
22
|
+
CONVERSION = 'conversion' #?
|
23
|
+
end
|
24
|
+
|
25
|
+
module LevelOfDetails
|
26
|
+
PORTFOLIO = 2 #账户粒度
|
27
|
+
CAMPAIGN = 3 #计划粒度
|
28
|
+
ADGROUP = 5 #单元粒度
|
29
|
+
CREATIVE = 7 #创意粒度
|
30
|
+
KEYWORDID = 11 #关键词(keywordid)粒度
|
31
|
+
KEYWORD = 12 #关键词(keywordid)+创意粒度
|
32
|
+
end
|
33
|
+
|
34
|
+
module ReportType
|
35
|
+
PORTFOLIO = 2 #账户
|
36
|
+
CAMPAIGN = 10 #计划
|
37
|
+
ADGROUP = 11 #单元
|
38
|
+
KEYWORDID = 14 #关键词(keywordid)
|
39
|
+
CREATIVE = 12 #创意
|
40
|
+
PAIR = 15 #配对
|
41
|
+
REGION = 3 #地域
|
42
|
+
QUERY = 6 #搜索词
|
43
|
+
WORD = 9 #关键词(wordid)
|
44
|
+
end
|
45
|
+
|
46
|
+
module StatRange #注意:统计范围不能细于当前的统计 粒度,例如统计粒度为计划,则统计 范围不能细到单元
|
47
|
+
PORTFOLIO = 2 #账户范围
|
48
|
+
CAMPAIGN = 3 #计划范围
|
49
|
+
ADGROUP = 5 #单元范围
|
50
|
+
CREATIVE = 7 #创意范围
|
51
|
+
KEYWORDID = 11 #关键词(keywordid)范围
|
52
|
+
WORD = 6 #关键词(wordid)范围
|
53
|
+
end
|
54
|
+
|
55
|
+
module UnitOfTime
|
56
|
+
DAY = 5 #分日
|
57
|
+
WEEK = 4 #分周
|
58
|
+
MONTH = 3 #分月
|
59
|
+
YEAR = 1 #分年
|
60
|
+
HOUR = 7 #分小时
|
61
|
+
TIME = 8 #请求时间段汇总(endDate-StartDate)
|
62
|
+
end
|
63
|
+
|
64
|
+
module Device
|
65
|
+
ALL = 0 #全部搜索推广设备
|
66
|
+
PC = 1 #仅计算机
|
67
|
+
MOBILE = 2 #仅移动 
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/sogou/sem.rb
ADDED
data/lib/sogou.rb
ADDED
data/sogou.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sogou/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sogou"
|
8
|
+
spec.version = Sogou::VERSION
|
9
|
+
spec.authors = ["seoaqua"]
|
10
|
+
spec.email = ["seoaqua@me.com"]
|
11
|
+
spec.description = %q{sogou web services}
|
12
|
+
spec.summary = %q{sogou sem services}
|
13
|
+
spec.homepage = "http://github.com/seoaqua/sogou"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_dependency "savon","~> 3.0"
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sogou::SEM::AccountService do
|
4
|
+
subject{Sogou::SEM::AccountService.new($auth)}
|
5
|
+
let(:options){options = {}}
|
6
|
+
describe "#getAccountInfo" do
|
7
|
+
it "getAccountInfo" do
|
8
|
+
response = subject.getAccountInfo(options)
|
9
|
+
response.status.should == 0
|
10
|
+
response.desc.should == 'success'
|
11
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sogou::SEM::AdgroupService do
|
4
|
+
subject{Sogou::SEM::AdgroupService.new($auth)}
|
5
|
+
describe '#getAllCpcGrpId' do
|
6
|
+
it "should return hash with correct format calling getAllCpcGrpId " do
|
7
|
+
|
8
|
+
response = subject.getAllCpcGrpId
|
9
|
+
response.status.should == 0
|
10
|
+
response.desc.should == 'success'
|
11
|
+
response.quota.should > 0
|
12
|
+
response.rquota.should > 0
|
13
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
14
|
+
# response.class.should == Hash
|
15
|
+
# response.should have_key :campaign_adgroup_ids
|
16
|
+
# response = response[:campaign_adgroup_ids]
|
17
|
+
# response.first.should have_key :campaign_id
|
18
|
+
# response.first.should have_key :adgroup_ids
|
19
|
+
# campaign_id = response.first[:campaign_id]
|
20
|
+
# campaign_id.to_i.to_s.should == campaign_id
|
21
|
+
# response.first[:adgroup_ids].class.should == Array
|
22
|
+
# adgroup_id = response.first[:adgroup_ids].first
|
23
|
+
# adgroup_id.to_i.to_s.should == adgroup_id
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#getCpcGrpByCpcGrpId' do
|
28
|
+
# subject{Sogou::SEM::AdgroupService.new($auth)}
|
29
|
+
it "should return hash with correct format calling getCpcGrpByCpcGrpId" do
|
30
|
+
response = subject.getCpcGrpByCpcGrpId({:cpcGrpIds=>[$adgroup_id]})
|
31
|
+
response.status.should == 0
|
32
|
+
response.desc.should == 'success'
|
33
|
+
response.quota.should > 0
|
34
|
+
response.rquota.should > 0
|
35
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#getCpcGrpIdByCpcPlanId' do
|
40
|
+
# subject{Sogou::SEM::AdgroupService.new($auth)}
|
41
|
+
it "should return hash with correct format calling getCpcGrpIdByCpcPlanId" do
|
42
|
+
response = subject.getCpcGrpIdByCpcPlanId({:cpcPlanIds=>[$campaign_id]})
|
43
|
+
response.status.should == 0
|
44
|
+
response.desc.should == 'success'
|
45
|
+
response.quota.should > 0
|
46
|
+
response.rquota.should > 0
|
47
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
48
|
+
# response.class.should == Hash
|
49
|
+
# response.should have_key :campaign_adgroups
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# describe '#getAdgroupByAdgroupId' do
|
54
|
+
# # subject{Sogou::SEM::AdgroupService.new($auth)}
|
55
|
+
# it "should return hash with correct format calling getAdgroupByAdgroupId" do
|
56
|
+
# pending
|
57
|
+
# response = subject.getAdgroupByAdgroupId({:adgroupIds => $adgroup_ids})
|
58
|
+
# response.status.should == 0
|
59
|
+
# response.desc.should == 'success'
|
60
|
+
# response.quota.should == 2
|
61
|
+
# response.rquota.should > 0
|
62
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
|
66
|
+
describe '#addCpcGrp #updateCpcGrp #getCpcGrpByCpcGrpId #deleteCpcGrp' do
|
67
|
+
# subject {Sogou::SEM::AdgroupService.new($aut)}
|
68
|
+
it "is not ready yet" do
|
69
|
+
#addCpcGrp
|
70
|
+
adgroupType_add = {:cpcPlanId=>$campaign_id,:cpcGrpName=>'adgroupName1',:maxPrice=>2}
|
71
|
+
|
72
|
+
response = subject.addCpcGrp({:cpcGrpTypes => [adgroupType_add]})
|
73
|
+
response.status.should == 0
|
74
|
+
response.desc.should == 'success'
|
75
|
+
response.quota.should > 0
|
76
|
+
response.rquota.should > 0
|
77
|
+
# ap response.body
|
78
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
79
|
+
|
80
|
+
#parse and verify adgroup_id
|
81
|
+
adgroup_id = response.body[:cpc_grp_types][:cpc_grp_id]
|
82
|
+
adgroup_id.to_i.to_s.should == adgroup_id
|
83
|
+
|
84
|
+
#updateCpcGrp
|
85
|
+
adgroupType_update = {:cpcGrpId => adgroup_id, :cpcGrpName => 'adgroupName2'}
|
86
|
+
# ap adgroupType
|
87
|
+
response = subject.updateCpcGrp({:cpcGrpTypes=>[adgroupType_update]})
|
88
|
+
response.status.should == 0
|
89
|
+
response.desc.should == 'success'
|
90
|
+
response.quota.should > 0
|
91
|
+
response.rquota.should > 0
|
92
|
+
# ap response.body
|
93
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
94
|
+
|
95
|
+
#getCpcGrpByCpcGrpId
|
96
|
+
response = subject.getCpcGrpByCpcGrpId({:cpcGrpIds=>[adgroup_id]})
|
97
|
+
response.status.should == 0
|
98
|
+
response.desc.should == 'success'
|
99
|
+
response.quota.should >= 0
|
100
|
+
response.rquota.should > 0
|
101
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
102
|
+
# response.body[:adgroup_types][:adgroup_name].should == 'adgroupName2'
|
103
|
+
|
104
|
+
|
105
|
+
#deleteCpcGrp
|
106
|
+
response = subject.deleteCpcGrp({:cpcGrpIds => [adgroup_id]})
|
107
|
+
response.status.should == 0
|
108
|
+
response.desc.should == 'success'
|
109
|
+
response.quota.should > 0
|
110
|
+
response.rquota.should > 0
|
111
|
+
# ap response.body
|
112
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
113
|
+
# ap response.body
|
114
|
+
# it "is not implemented yet" do
|
115
|
+
# pending("this is pending before we have testing-purpose account")
|
116
|
+
# end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Sogou::SEM::CampaignService do
|
3
|
+
subject{Sogou::SEM::CampaignService.new($auth)}
|
4
|
+
|
5
|
+
describe '#addCampaign #updateCampaign #getCpcPlanByCpcPlanId #deleteCampaign' do
|
6
|
+
pending
|
7
|
+
it "should not raise errors when add, update, and delete a temp campaign" do
|
8
|
+
# ap subject.example('deleteCpcPlan')
|
9
|
+
# pending
|
10
|
+
#addCampaign
|
11
|
+
campaign_type_add = {
|
12
|
+
:cpcPlanName=> 'campaignName18',
|
13
|
+
:budget => '100',
|
14
|
+
:negativeWords => ['7day'],
|
15
|
+
:exactNegativeWords => ['7daysin']
|
16
|
+
}
|
17
|
+
options = {:cpcPlanTypes => [campaign_type_add]}
|
18
|
+
response = subject.addCpcPlan(options)
|
19
|
+
response.status.should == 0
|
20
|
+
response.desc.should == 'success'
|
21
|
+
response.quota.should == 1
|
22
|
+
response.rquota.should > 0
|
23
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
24
|
+
#parse and verify campaign_id
|
25
|
+
campaign_id = response.body[:cpc_plan_types][:cpc_plan_id]
|
26
|
+
campaign_id.to_i.to_s.should == campaign_id
|
27
|
+
|
28
|
+
#updateCpcPlan
|
29
|
+
campaign_type_update =
|
30
|
+
{
|
31
|
+
:cpcPlanId => campaign_id,
|
32
|
+
:cpcPlanName => 'campaignName19',
|
33
|
+
:budget => '101',
|
34
|
+
:negativeWords => ['8day'],
|
35
|
+
:exactNegativeWords => ['8daysin']
|
36
|
+
}
|
37
|
+
sleep 2
|
38
|
+
options = {:cpcPlanTypes => [campaign_type_update]}
|
39
|
+
response = subject.updateCpcPlan(options)
|
40
|
+
response.status.should == 0
|
41
|
+
response.desc.should == 'success'
|
42
|
+
response.quota.should == 1
|
43
|
+
response.rquota.should > 0
|
44
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
45
|
+
#check the result of updateCpcPlan by getCpcPlanByCpcPlanId
|
46
|
+
response = subject.getCpcPlanByCpcPlanId({:cpcPlanIds => [campaign_id]})
|
47
|
+
response.status.should == 0
|
48
|
+
response.desc.should == 'success'
|
49
|
+
response.quota.should == 1
|
50
|
+
response.rquota.should > 0
|
51
|
+
sleep 2
|
52
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
53
|
+
# ap response.body
|
54
|
+
response.body[:cpc_plan_types][:cpc_plan_name].should == 'campaignName19'
|
55
|
+
response.body[:cpc_plan_types][:budget].should == '101.0'
|
56
|
+
response.body[:cpc_plan_types][:negative_words].should == '8day'
|
57
|
+
response.body[:cpc_plan_types][:exact_negative_words].should == "8daysin"
|
58
|
+
|
59
|
+
#deleteCpcPlan
|
60
|
+
response = subject.deleteCpcPlan({:cpcPlanIds=>[campaign_id]})
|
61
|
+
response.status.should == 0
|
62
|
+
response.desc.should == 'success'
|
63
|
+
response.quota.should == 1
|
64
|
+
response.rquota.should > 0
|
65
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# describe '#getCpcPlanByCpcPlanId' do
|
70
|
+
# it "getCpcPlanByCpcPlanId" do
|
71
|
+
# # puts '==============='
|
72
|
+
# # puts subject.example('getAllCampaign')
|
73
|
+
# # {:GetCampaignByCampaignIdRequest=>{:campaignIds=>["long"]}}
|
74
|
+
# # puts '==============='
|
75
|
+
# response = subject.getCpcPlanByCpcPlanId({:campaignIds=>[$campaign_id]})
|
76
|
+
# response.status.should == 0
|
77
|
+
# response.desc.should == 'success'
|
78
|
+
# response.quota.should == 2
|
79
|
+
# response.rquota.should > 0
|
80
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
|
84
|
+
describe '#getAllCpcPlan' do
|
85
|
+
it "getAllCpcPlan" do
|
86
|
+
response = subject.getAllCpcPlan({})
|
87
|
+
response.status.should == 0
|
88
|
+
response.desc.should == 'success'
|
89
|
+
response.quota.should > 0
|
90
|
+
response.rquota.should > 0
|
91
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'uri'
|
3
|
+
describe Sogou::SEM::CreativeService do
|
4
|
+
subject{Sogou::SEM::CreativeService.new($auth)}
|
5
|
+
let(:new_title){'新测试创意标题b'}
|
6
|
+
it '#addCpcIdea #updateCpcIdea #getCpcIdeaByCpcGrpId #deleteCreative' do
|
7
|
+
# ap subject.operations
|
8
|
+
# ap subject.example('deleteCpcIdea')
|
9
|
+
# pending
|
10
|
+
#addCpcIdea
|
11
|
+
creativeType = {
|
12
|
+
:cpcGrpId => $adgroup_id,
|
13
|
+
:title => '测试创意标题d',
|
14
|
+
:description1 => '测试创意首行测试创意首行测试创意首行',
|
15
|
+
:description2 => '测试创意次行测试创意次行测试创意次行',
|
16
|
+
:visitUrl => $pcDestinationUrl,
|
17
|
+
:showUrl=> URI($pcDestinationUrl).host,
|
18
|
+
:mobileVisitUrl => $mobileDestinationUrl,
|
19
|
+
:mobileShowUrl=> URI($mobileDestinationUrl).host
|
20
|
+
}
|
21
|
+
# {:creativeTypes=>[{
|
22
|
+
# :creativeId=>"long",
|
23
|
+
# :adgroupId=>"long",
|
24
|
+
# :title=>"string",
|
25
|
+
# :description1=>"string",
|
26
|
+
# :description2=>"string",
|
27
|
+
# :pcDestinationUrl=>"string",
|
28
|
+
# :pcDisplayUrl=>"string",
|
29
|
+
# :mobileDestinationUrl=>"string",
|
30
|
+
# :mobileDisplayUrl=>"string",
|
31
|
+
# :pause=>"boolean",
|
32
|
+
# :status=>"int"}]
|
33
|
+
# }
|
34
|
+
# }
|
35
|
+
|
36
|
+
# puts subject.example('addCpcIdea')
|
37
|
+
response = subject.addCpcIdea({:cpcIdeaTypes => [creativeType]})
|
38
|
+
response.status.should == 0
|
39
|
+
response.desc.should == 'success'
|
40
|
+
response.quota.should == 1
|
41
|
+
response.rquota.should > 0
|
42
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
43
|
+
creative_id = response.body[:cpc_idea_types][:cpc_idea_id]
|
44
|
+
|
45
|
+
|
46
|
+
# updateCpcIdea
|
47
|
+
sleep 3
|
48
|
+
creativeType = {
|
49
|
+
:cpcIdeaId=>creative_id,
|
50
|
+
:title => new_title,
|
51
|
+
:description1 => '艺龙酒店测试创意首行测试创意首行测试创意首行',
|
52
|
+
:description2 => '艺龙酒店测试创意首行测试创意首行测试创意次行',
|
53
|
+
:visitUrl => 'http://hotel.elong.com/beijing/'
|
54
|
+
}
|
55
|
+
response = subject.updateCpcIdea(:cpcIdeaTypes => [creativeType])
|
56
|
+
response.status.should == 0
|
57
|
+
response.desc.should == 'success'
|
58
|
+
response.quota.should == 1
|
59
|
+
response.rquota.should > 0
|
60
|
+
ap response.body
|
61
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
62
|
+
|
63
|
+
#getCpcIdeaByCpcGrpId
|
64
|
+
sleep 3
|
65
|
+
response = subject.getCpcIdeaByCpcGrpId(:cpcGrpIds => [creative_id])
|
66
|
+
response.status.should == 0
|
67
|
+
response.desc.should == 'success'
|
68
|
+
response.quota.should == 1
|
69
|
+
response.rquota.should > 0
|
70
|
+
ap response.body
|
71
|
+
response.body[:cpc_idea_types][:title].should == new_title
|
72
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
73
|
+
|
74
|
+
#deleteCpcIdea
|
75
|
+
response = subject.deleteCpcIdea({:cpcIdeaIds => [creative_id]})
|
76
|
+
response.status.should == 0
|
77
|
+
response.desc.should == 'success'
|
78
|
+
response.quota.should == 1
|
79
|
+
response.rquota.should > 0
|
80
|
+
# expect{ApiResponse.verify(response.body)}.not_to raise_error
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Sogou::SEM::KeywordService do
|
3
|
+
subject{Sogou::SEM::KeywordService.new($auth)}
|
4
|
+
let(:keyword_sample){'XJK测试关键词o'}
|
5
|
+
it "#addCpc #updateCpc #getCpcByCpcId #deleteCpc " do
|
6
|
+
# ap subject.example('updateCpc')
|
7
|
+
# pending
|
8
|
+
#addCpc
|
9
|
+
# puts $adgroup_id
|
10
|
+
keywordType = {:cpcGrpId => $adgroup_id,:cpc=>keyword_sample,:matchType => 1,:price => 1}
|
11
|
+
response = subject.addCpc({:cpcTypes => [keywordType]})
|
12
|
+
response.status.should == 0
|
13
|
+
response.desc.should == 'success'
|
14
|
+
response.quota.should == 1
|
15
|
+
response.rquota.should > 0
|
16
|
+
keyword_id = response.body[:cpc_types][:cpc_id]
|
17
|
+
|
18
|
+
#updateCpc
|
19
|
+
keywordType = {:cpcId=> keyword_id,:price => 2}
|
20
|
+
response = subject.updateCpc({:cpcTypes=>[keywordType]})
|
21
|
+
response.status.should == 0
|
22
|
+
response.desc.should == 'success'
|
23
|
+
response.quota.should == 1
|
24
|
+
response.rquota.should > 0
|
25
|
+
|
26
|
+
#getCpcByCpcId
|
27
|
+
sleep 3
|
28
|
+
response = subject.getCpcByCpcId({:cpcIds => [keyword_id]})
|
29
|
+
response.status.should == 0
|
30
|
+
response.desc.should == 'success'
|
31
|
+
response.quota.should == 1
|
32
|
+
response.rquota.should > 0
|
33
|
+
keyword = response.body[:cpc_types]
|
34
|
+
(keyword.is_a?Hash).should == true
|
35
|
+
keyword[:cpc_id].should == keyword_id
|
36
|
+
keyword[:cpc_grp_id].should == $adgroup_id
|
37
|
+
keyword[:cpc].should == keyword_sample
|
38
|
+
keyword[:price].should == "2.0"
|
39
|
+
|
40
|
+
#deleteCpc
|
41
|
+
sleep 3
|
42
|
+
response = subject.deleteCpc({:cpcIds => [keyword_id]})
|
43
|
+
response.status.should == 0
|
44
|
+
response.desc.should == 'success'
|
45
|
+
response.quota.should == 1
|
46
|
+
response.rquota.should > 0
|
47
|
+
# response.body[:result].should == '1'
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Sogou::SEM::ReportService do
|
3
|
+
subject{Sogou::SEM::ReportService.new($auth)}
|
4
|
+
it 'should not raise error on #getReportId #getReportState #getReportPath series test' do
|
5
|
+
pending('Report type and report range do not match')
|
6
|
+
#getReportId
|
7
|
+
options = {
|
8
|
+
:performanceData => [Sogou::SEM::PerformanceData::IMPRESSION, Sogou::SEM::PerformanceData::CLICK, Sogou::SEM::PerformanceData::CPC],
|
9
|
+
:startDate => (Time.now - 2*24*3600).utc.iso8601,
|
10
|
+
:endDate => (Time.now - 24*3600).utc.iso8601,
|
11
|
+
:statIds => [$campaign_id],
|
12
|
+
:idOnly => true
|
13
|
+
# :levelOfDetails => Sogou::SEM::LevelOfDetails::CAMPAIGN,
|
14
|
+
# :reportType => Sogou::SEM::ReportType::CAMPAIGN,
|
15
|
+
# :statRange => Sogou::SEM::StatRange::CAMPAIGN
|
16
|
+
}
|
17
|
+
|
18
|
+
response = subject.getReportId({:reportRequestType => options},true)
|
19
|
+
response.status.should == 0
|
20
|
+
response.desc.should == 'success'
|
21
|
+
response.quota.should == 2
|
22
|
+
response.rquota.should > 0
|
23
|
+
|
24
|
+
#parse report_id
|
25
|
+
report_id = response.body[:report_id]
|
26
|
+
|
27
|
+
#getReportState
|
28
|
+
try_count = 0
|
29
|
+
loop do
|
30
|
+
response = subject.getReportState({:reportId => report_id})
|
31
|
+
response.status.should == 0
|
32
|
+
response.desc.should == 'success'
|
33
|
+
response.quota.should == 2
|
34
|
+
response.rquota.should > 0
|
35
|
+
#verify is_generated status
|
36
|
+
is_generated = response.body[:is_generated]
|
37
|
+
break if is_generated == '3' or try_count > 10
|
38
|
+
sleep 1
|
39
|
+
try_count +=1
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
#getReportPath
|
44
|
+
response = subject.getReportPath({:reportId => report_id})
|
45
|
+
response.status.should == 0
|
46
|
+
response.desc.should == 'success'
|
47
|
+
response.quota.should == 2
|
48
|
+
response.rquota.should > 0
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
it "处理过期/无效id,应返回false" do
|
53
|
+
expect{subject.getReportState({:reportId=>'7da8438bc705c9e6e747959fafce91f2'}).body}.to raise_error
|
54
|
+
expect{subject.getReportState({:reportId=>'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'}).body}.to raise_error
|
55
|
+
end
|
56
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'Sogou'
|
2
|
+
require 'time'
|
3
|
+
#请根据自己实际情况填写
|
4
|
+
$username = '' #用户名
|
5
|
+
$password = '' #密码
|
6
|
+
$token = '' #token
|
7
|
+
$auth = Sogou::Auth.new
|
8
|
+
$auth.username = $username
|
9
|
+
$auth.password = $password
|
10
|
+
$auth.token = $token
|
11
|
+
$startDate = (Time.now - 24*3600).utc.iso8601
|
12
|
+
$endDate = Time.now.utc.iso8601
|
13
|
+
$pcDestinationUrl = 'http://www.elong.com/'
|
14
|
+
$mobileDestinationUrl = 'http://www.elong.com/'
|
15
|
+
|
16
|
+
|
17
|
+
cs = Sogou::SEM::CampaignService.new($auth)
|
18
|
+
campaigns = cs.getAllCpcPlan
|
19
|
+
campaign = campaigns.body[:cpc_plan_types].first
|
20
|
+
$campaign_id = campaign[:cpc_plan_id]
|
21
|
+
$campaign_name = campaign[:cpc_plan_name]
|
22
|
+
|
23
|
+
ac = Sogou::SEM::AdgroupService.new($auth)
|
24
|
+
|
25
|
+
adgroups = ac.getCpcGrpByCpcPlanId({:cpcPlanIds=>[$campaign_id]})
|
26
|
+
$adgroup_id = adgroups.body[:cpc_plan_grps][:cpc_grp_types].first[:cpc_grp_id]
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sogou
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- seoaqua
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: savon
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: sogou web services
|
56
|
+
email:
|
57
|
+
- seoaqua@me.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- Gemfile
|
64
|
+
- LICENSE.txt
|
65
|
+
- README.md
|
66
|
+
- Rakefile
|
67
|
+
- lib/sogou.rb
|
68
|
+
- lib/sogou/auth.rb
|
69
|
+
- lib/sogou/ext.rb
|
70
|
+
- lib/sogou/response.rb
|
71
|
+
- lib/sogou/sem.rb
|
72
|
+
- lib/sogou/sem/account.rb
|
73
|
+
- lib/sogou/sem/adgroup.rb
|
74
|
+
- lib/sogou/sem/base.rb
|
75
|
+
- lib/sogou/sem/campaign.rb
|
76
|
+
- lib/sogou/sem/creative.rb
|
77
|
+
- lib/sogou/sem/enum.rb
|
78
|
+
- lib/sogou/sem/keyword.rb
|
79
|
+
- lib/sogou/sem/report.rb
|
80
|
+
- lib/sogou/version.rb
|
81
|
+
- sogou.gemspec
|
82
|
+
- spec/sem_account_spec.rb
|
83
|
+
- spec/sem_adgroup_spec.rb
|
84
|
+
- spec/sem_campaign_spec.rb
|
85
|
+
- spec/sem_creative_spec.rb
|
86
|
+
- spec/sem_keyword_spec.rb
|
87
|
+
- spec/sem_report_spec.rb
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
homepage: http://github.com/seoaqua/sogou
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata: {}
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 2.1.5
|
110
|
+
signing_key:
|
111
|
+
specification_version: 4
|
112
|
+
summary: sogou sem services
|
113
|
+
test_files:
|
114
|
+
- spec/sem_account_spec.rb
|
115
|
+
- spec/sem_adgroup_spec.rb
|
116
|
+
- spec/sem_campaign_spec.rb
|
117
|
+
- spec/sem_creative_spec.rb
|
118
|
+
- spec/sem_keyword_spec.rb
|
119
|
+
- spec/sem_report_spec.rb
|
120
|
+
- spec/spec_helper.rb
|