Skip to content

Commit 6697575

Browse files
committed
refactored away from 'region' toward gateway and subregion identification to mimic battle.net more closely
1 parent 5e57141 commit 6697575

File tree

12 files changed

+119
-131
lines changed

12 files changed

+119
-131
lines changed

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ passing the account information in the options hash. Thus, either of these two
1313

1414
``` ruby
1515
BnetScraper::Starcraft2::ProfileScraper.new(url: 'http://us.battle.net/sc2/en/profile/12345/1/TestAccount/')
16-
BnetScraper::Starcraft2::ProfileScraper.new(bnet_id: '12345', account: 'TestAccount', region: 'na')
16+
BnetScraper::Starcraft2::ProfileScraper.new(bnet_id: '12345', account: 'TestAccount', gateway: 'us')
1717
```
1818

19+
Note that the latter will assume subregion "1", which is North America. Make sure you're also passing the correct subregion along,
20+
if you want to scrape a profile in a different subregion. For a full mapping of regions, see `BnetScraper::Starcraft2::REGIONS`
21+
1922
There are several scrapers that pull various information. They are:
2023

2124
* BnetScraper::Starcraft2::ProfileScraper - collects basic profile information and an array of league URLs
@@ -26,6 +29,14 @@ There are several scrapers that pull various information. They are:
2629
All scrapers have a `#scrape` method that triggers the scraping and storage. By default they will return the result,
2730
but an additional `#output` method exists to retrieve the results subsequent times without re-scraping.
2831

32+
## Terminology
33+
34+
To clarify some of the confusion that might result from changing terminology and no general consensus, BnetScraper now uses naming relative to the battle.net URL scheme to avoid confusion, especially regarding "subregion" and "gateway":
35+
36+
`<gateway>.battle.net/sc2/<locale>/profile/<bnet_id>/<subregion>/<name>`
37+
38+
Note that "region" is not in there - it is the freely named key for a combination of gateway and subregion, it does not appear on battle.net anywhere.
39+
2940
## BnetScraper::Starcraft2::ProfileScraper
3041

3142
This pulls basic profile information for an account, as well as an array of league URLs. This is a good starting

lib/bnet_scraper/starcraft2.rb

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,28 @@ module BnetScraper
1111
# for more details
1212
module Starcraft2
1313
REGIONS = {
14-
'na' => { domain: 'us.battle.net', dir: 'en', label: 'North America' },
15-
'eu' => { domain: 'eu.battle.net', dir: 'en', label: 'Europe' },
16-
'cn' => { domain: 'www.battlenet.com.cn', dir: 'zh', label: 'China' },
17-
'sea' => { domain: 'sea.battle.net', dir: 'en', label: 'South-East Asia' },
18-
'fea' => { domain: 'tw.battle.net', dir: 'zh', label: 'Korea' }
14+
'na' => { gateway: 'us', subregion: 1, locale: 'en', label: 'North America' },
15+
'la' => { gateway: 'us', subregion: 2, locale: 'en', label: 'Latin America' },
16+
'eu' => { gateway: 'eu', subregion: 1, locale: 'en', label: 'Europe' },
17+
'ru' => { gateway: 'eu', subregion: 2, locale: 'en', label: 'Russia' },
18+
'cn' => { gateway: 'cn', subregion: 1, locale: 'zh', label: 'China' },
19+
'sea' => { gateway: 'sea', subregion: 1, locale: 'en', label: 'South-East Asia' },
20+
'tw' => { gateway: 'tw', subregion: 1, locale: 'zh', label: 'Taiwan' },
21+
'kr' => { gateway: 'kr', subregion: 1, locale: 'ko', label: 'Korea' },
22+
# There's a subregion 2 for korea and I honestly don't know what the name of that would be
23+
'kr2' => { gateway: 'kr', subregion: 2, locale: 'ko', label: 'Also Korea' }
1924
}
2025

21-
REGION_DOMAINS = {
22-
'us.battle.net' => 'na',
26+
# Gateway Hostname Mapping
27+
# This exists primarily because china does things differently from everyone else.
28+
HOSTNAMES = {
29+
'us.battle.net' => 'us',
2330
'eu.battle.net' => 'eu',
2431
'www.battlenet.com.cn' => 'cn',
32+
'cn.battle.net' => 'cn',
2533
'sea.battle.net' => 'sea',
26-
'kr.battle.net' => 'fea',
27-
'tw.battle.net' => 'fea'
34+
'kr.battle.net' => 'kr',
35+
'tw.battle.net' => 'tw'
2836
}
2937

3038
# The armory uses spritemaps that are sequentially named and have a fixed
@@ -88,12 +96,12 @@ module Starcraft2
8896
# the parameters being sent to `#full_profile_scrape`.
8997
#
9098
# @param bnet_id - Battle.net Account ID
91-
# @param account - Battle.net Account Name
92-
# @param region - Battle.net Account Region
99+
# @param name - Battle.net Account Name
100+
# @param gateway - Battle.net Account Gateway
93101
# @return profile_data - Hash containing complete profile and league data
94102
# scraped from the website
95-
def self.full_profile_scrape bnet_id, account, region = 'na'
96-
profile_scraper = ProfileScraper.new bnet_id: bnet_id, account: account, region: region
103+
def self.full_profile_scrape bnet_id, name, gateway = 'us'
104+
profile_scraper = ProfileScraper.new bnet_id: bnet_id, name: name, gateway: gateway
97105
profile_output = profile_scraper.scrape
98106

99107
parsed_leagues = []

lib/bnet_scraper/starcraft2/base_scraper.rb

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,54 @@
11
module BnetScraper
22
module Starcraft2
33
# BaseScraper handles the account information extraction. Each scraper can either be passed a profile URL or
4-
# the minimum information needed to access an account. This means passing in account and bnet_id at minimum.
4+
# the minimum information needed to access an account: bnet_id and name. The gateway will default to 'us'
5+
# and region will default to the first region for the given gateway.
6+
#
57
# Both of the following are valid ways to instantiate a scraper for the same account:
68
#
79
# BnetScraper::Starcraft2::BaseScraper.new(url: 'http://us.battle.net/sc2/en/profile/12345/1/TestAccount/')
8-
# BnetScraper::Starcraft2::BaseScraper.new(bnet_id: '12345', account: 'TestAccount')
10+
# BnetScraper::Starcraft2::BaseScraper.new(bnet_id: '12345', name: 'TestAccount')
911
#
1012
# The URL scheme is the following:
11-
#
12-
# http://<REGION_DOMAIN>/sc2/<REGION_LANG>/profile/<BNET_ID>/<BNET_INDEX>/<ACCOUNT>/
13-
#
14-
# Note that by default, the region will be set to 'na' if you opt not to specify the URL or region. The
15-
# scraper uses the short-codes for regions. See `BnetScraper::Starcraft2::REGIONS` for the address
16-
# translations.
13+
# http://<gateway>.battle.net/sc2/<locale>/profile/<bnet_id>/<region>/<name>/
1714
class BaseScraper
18-
attr_reader :bnet_id, :account, :region, :bnet_index, :url
15+
attr_reader :bnet_id, :name, :gateway, :subregion, :region, :url
1916

2017
def initialize options = {}
2118
if options[:url]
2219
extracted_data = options[:url].match(/http:\/\/(.+)\/sc2\/(.+)\/profile\/(.+)\/(\d{1})\/(.[^\/]+)\//)
2320
if extracted_data
24-
@region = REGION_DOMAINS[extracted_data[1]]
21+
@hostname = extracted_data[1]
22+
@gateway = HOSTNAMES[@hostname]
23+
@locale = extracted_data[2]
2524
@bnet_id = extracted_data[3]
26-
@bnet_index = extracted_data[4]
27-
@account = extracted_data[5]
25+
@subregion = extracted_data[4].to_i
26+
@name = extracted_data[5]
2827
@url = options[:url]
2928
else
3029
raise BnetScraper::InvalidProfileError, "URL provided does not match Battle.net format"
3130
end
32-
elsif options[:bnet_id] && options[:account]
31+
elsif options[:bnet_id] && options[:name]
3332
@bnet_id = options[:bnet_id]
34-
@account = options[:account]
35-
@region = options[:region] || 'na'
36-
if options[:bnet_index]
37-
@bnet_index = options[:bnet_index]
38-
else
39-
set_bnet_index
40-
end
41-
end
42-
end
43-
44-
# set_bnet_index
45-
#
46-
# Because profile URLs have to have a specific bnet_index that is seemingly incalculable,
47-
# we must ping both variants to determine the correct bnet_index. We then store that value.
48-
def set_bnet_index
49-
[1,2].each do |idx|
50-
res = Net::HTTP.get_response URI profile_url idx
51-
if res.is_a? Net::HTTPSuccess
52-
@bnet_index = idx
53-
return
54-
end
33+
@name = options[:name]
34+
@gateway = options[:gateway] || 'us'
35+
@subregion= (options[:subregion] || 1).to_i
36+
else
37+
raise BnetScraper::InvalidProfileError, "Required options missing"
5538
end
39+
40+
@region = REGIONS.find{|region, data| data[:gateway] == @gateway && data[:subregion] == @subregion}
41+
raise BnetScraper::InvalidProfileError, "Could not identify region from gateway '#{@gateway}' and subregion '#{@subregion}'" if !@region
42+
@region = @region[0]
5643
end
5744

58-
def profile_url bnet_index = @bnet_index
59-
"http://#{region_info[:domain]}/sc2/#{region_info[:dir]}/profile/#{bnet_id}/#{bnet_index}/#{account}/"
45+
# Returns the profile URL generated from associated data
46+
# Note: while China has it's own hostname/domain, cn.battle.net will
47+
# redirect to it properly.
48+
def profile_url
49+
"http://#{gateway}.battle.net/sc2/#{region_info[:locale]}/profile/#{bnet_id}/#{region_info[:subregion]}/#{name}/"
6050
end
6151

62-
# converts region short-code to region-based URL information
63-
# 'na' => { domain: 'us.battle.net', :dir: 'en' }
6452
def region_info
6553
REGIONS[region]
6654
end

lib/bnet_scraper/starcraft2/league_scraper.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@ module Starcraft2
33
# This pulls information on a specific league for a specific account. It is best used either in conjunction with a
44
# profile scrape that profiles a URL, or if you happen to know the specific league\_id and can pass it as an option.
55
#
6-
# scraper = BnetScraper::Starcraft2::LeagueScraper.new(league_id: '12345', account: 'Demon', bnet_id: '2377239')
6+
# scraper = BnetScraper::Starcraft2::LeagueScraper.new(league_id: '12345', name: 'Demon', bnet_id: '2377239')
77
# scraper.scrape
88
# # => {
99
# season: '6',
10-
# name: 'Aleksander Pepper',
11-
# division: 'Diamond',
10+
# division: 'Aleksander Pepper',
11+
# league: 'Diamond',
1212
# size: '4v4',
1313
# random: false,
1414
# bnet_id: '2377239',
15-
# account: 'Demon'
15+
# name: 'Demon'
1616
# }
1717
class LeagueScraper < BaseScraper
18-
attr_reader :league_id, :season, :size, :random, :name, :division
18+
attr_reader :league_id, :season, :size, :random, :league, :division
1919

2020
# @param [String] url - The league URL on battle.net
2121
# @return [Hash] league_data - Hash of data extracted
@@ -37,7 +37,7 @@ def scrape
3737
header_regex = /Season (\d{1}) - \s+(\dv\d)( Random)? (\w+)\s+Division (.+)/
3838
header_values = value.match(header_regex).to_a
3939
header_values.shift()
40-
@season, @size, @random, @division, @name = header_values
40+
@season, @size, @random, @league, @division = header_values
4141

4242
@random = !@random.nil?
4343
output
@@ -50,11 +50,11 @@ def output
5050
{
5151
season: @season,
5252
size: @size,
53-
name: @name,
5453
division: @division,
54+
league: @league,
5555
random: @random,
5656
bnet_id: @bnet_id,
57-
account: @account
57+
name: @name
5858
}
5959
end
6060
end

lib/bnet_scraper/starcraft2/profile_scraper.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ module Starcraft2
77
# scraper.scrape
88
# # => {
99
# bnet_id: '2377239',
10-
# account: 'Demon',
11-
# bnet_index: 1,
10+
# name: 'Demon',
11+
# subregion: 1,
1212
# race: 'Protoss',
1313
# wins: '684',
1414
# achievement_points: '3630',
@@ -117,8 +117,8 @@ def get_league_list
117117
def output
118118
{
119119
bnet_id: @bnet_id,
120-
account: @account,
121-
bnet_index: @bnet_index,
120+
name: @name,
121+
subregion: @subregion,
122122
race: @race,
123123
current_solo_league: @current_solo_league,
124124
highest_solo_league: @highest_solo_league,

lib/bnet_scraper/starcraft2/status_scraper.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module Starcraft2
55
#
66
# Examples:
77
# BnetScraper::Starcraft2::Status.na => 'Online'
8-
# BnetScraper::Starcraft2::Status.fea => 'Offline'
8+
# BnetScraper::Starcraft2::Status.kr => 'Offline'
99
# BnetScraper::Starcraft2::Status.cn => nil (China is unsupported)
1010
# BnetScraper::Starcraft2::Status.fetch => [
1111
# {:region=>"North America", :status=>"Online"},{:region=>"Europe", :status=>"Online"},

spec/starcraft2/base_scraper_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
describe '#scrape' do
1616
it 'should raise an error calling scrape' do
17-
expect { subject.scrape }.to raise_error NotImplementedError
17+
expect { subject.scrape }.to raise_error BnetScraper::InvalidProfileError
1818
end
1919
end
2020
end

spec/starcraft2/league_scraper_spec.rb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@
2323
end
2424

2525
it 'should set the name' do
26-
subject.name.should be_nil
26+
subject.division.should be_nil
2727
subject.scrape
28-
subject.name.should == 'Aleksander Pepper'
28+
subject.division.should == 'Aleksander Pepper'
2929
end
3030

3131
it 'should set the divison' do
32-
subject.division.should be_nil
32+
subject.league.should be_nil
3333
subject.scrape
34-
subject.division.should == 'Diamond'
34+
subject.league.should == 'Diamond'
3535
end
3636

3737
it 'should set the size' do
@@ -62,12 +62,12 @@
6262
it 'should return a hash of league data' do
6363
expected = {
6464
season: '6',
65-
name: 'Aleksander Pepper',
66-
division: 'Diamond',
65+
division: 'Aleksander Pepper',
66+
league: 'Diamond',
6767
size: '4v4',
6868
random: false,
6969
bnet_id: '2377239',
70-
account: 'Demon'
70+
name: 'Demon'
7171
}
7272

7373
subject.scrape

spec/starcraft2/profile_scraper_spec.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
let(:subject) { scraper_class.new(url: 'http://us.battle.net/sc2/en/profile/2377239/1/Demon/') }
77
end
88

9-
subject { BnetScraper::Starcraft2::ProfileScraper.new(bnet_id: '2377239', account: 'Demon') }
9+
subject { BnetScraper::Starcraft2::ProfileScraper.new(bnet_id: '2377239', name: 'Demon') }
1010

1111
describe '#get_profile_data' do
1212
before do
@@ -69,7 +69,7 @@
6969
expect { scraper.scrape }.to raise_error(BnetScraper::InvalidProfileError)
7070
end
7171

72-
context 'account that has not laddered' do
72+
context 'name that has not laddered' do
7373
let(:scraper) {BnetScraper::Starcraft2::ProfileScraper.new(url: 'http://us.battle.net/sc2/en/profile/3354437/1/ClarkeKent/') }
7474
before do
7575
scraper.scrape
@@ -85,8 +85,8 @@
8585
it 'should extract profile data from the response' do
8686
expected = {
8787
bnet_id: '2377239',
88-
account: 'Demon',
89-
bnet_index: 1,
88+
name: 'Demon',
89+
subregion: 1,
9090
race: 'Protoss',
9191
career_games: '1568',
9292
games_this_season: '0',
@@ -163,8 +163,8 @@
163163

164164
subject.output.should == {
165165
bnet_id: '2377239',
166-
account: 'Demon',
167-
bnet_index: 1,
166+
name: 'Demon',
167+
subregion: 1,
168168
race: nil,
169169
career_games: nil,
170170
games_this_season: nil,

spec/starcraft2/status_scraper_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
BnetScraper::Starcraft2::Status.na.should == 'Online'
77
BnetScraper::Starcraft2::Status.eu.should == 'Online'
88
BnetScraper::Starcraft2::Status.sea.should == 'Online'
9-
BnetScraper::Starcraft2::Status.fea.should == 'Online'
9+
BnetScraper::Starcraft2::Status.kr.should == 'Online'
1010
end
1111
end
1212

0 commit comments

Comments
 (0)