weatherscout 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8b0d63da54f05eea838d5a10bed697dcd1d735eb
4
- data.tar.gz: db40952ef17dee2abf0ebe33df5ec1a0fd8d3dc2
3
+ metadata.gz: 2af3cc5c390cc4e5a9817b474ab059230a767041
4
+ data.tar.gz: 99b4a96130932e19941e0541eddd1c93d80a7413
5
5
  SHA512:
6
- metadata.gz: 4587da3cc3e1945bfb4285c792f5032d07c11925112e4de641ba7aa08761e5ed0a3b7e7af6a99bd78e19bd23a0d5aa7e2c7ba909f25f698e633b1233ffd9c793
7
- data.tar.gz: 86e041ebf87ee31d42b40714a3386911661064fa0550cd798d46e8a4ee9cb1da13c236d4eb4c7ae74e358142bba4bb3c421bf6b2abb5cd7f3ff62049b003f97e
6
+ metadata.gz: 0c375ce7327f53c051819d3f02092527cbbfad7ea5977ac7f14d43e5ba09eb83d689cde40c1374028ab499d755ace21c51f9c4b4ccbe1be8755f2e72cf13e394
7
+ data.tar.gz: c65150ec72d3c362dc693cbcfd28486fb57a095003b0fb7484c563f358339bd56b14f409eeca9664da0525a1e928faf5f52b4d22e89cf3be18870006dd46a837
data/Gemfile CHANGED
@@ -3,6 +3,8 @@ source 'https://rubygems.org'
3
3
  gem 'oga'
4
4
  gem 'minitest'
5
5
  gem 'thor'
6
+ gem 'vcr'
7
+ gem 'webmock'
6
8
 
7
9
  group :test do
8
10
  gem 'rake'
data/README.md CHANGED
@@ -15,34 +15,144 @@ $ gem install weatherscout
15
15
  To see the weather today
16
16
  ```sh
17
17
  $ weatherscout today 新竹
18
- 新竹(01/01)天氣狀況:
19
- 白天氣象:多雲,氣溫 15 ~ 16 度
20
- 晚上氣象:多雲,氣溫 15 ~ 23
21
- 降雨機率:0 %
18
+ 新竹(HsinchuCity)的天氣預測:
19
+ 今晚至明晨 01/21 00:00~01/21 06:00
20
+ -氣溫:15 ~ 16
21
+ -降雨機率:70 %
22
+ -天氣狀況:多雲短暫雨
23
+ 明日白天 01/21 06:00~01/21 18:00
24
+ -氣溫:15 ~ 18 度
25
+ -降雨機率:60 %
26
+ -天氣狀況:多雲短暫雨
27
+ 明日晚上 01/21 18:00~01/22 06:00
28
+ -氣溫:15 ~ 17 度
29
+ -降雨機率:70 %
30
+ -天氣狀況:多雲時陰陣雨
22
31
  溫馨叮嚀:
23
- 清晨東北季風影響,早晚氣溫低
24
- (31)日,新竹市地區仍受東北季風影響,為多雲的天氣,空曠地區易有8至9級強陣風,香山區白天溫度在15-19度左右;外出請注意保暖及注意安全。
25
- 明(1)日,新竹市地區清晨東北季風影響,早晚氣溫低,為多雲的天氣,預報溫度在1618度之間;外出請注意保暖及注意安全。
26
- 明(1)日,新竹沿海地區風力7至8陣風10級下午轉5至6陣風8級,作業船隻及海邊活動仍請注意安全。
32
+ 東北季風及華南雲雨區影響,多雲短暫雨
33
+ (20)日,持續受大陸冷氣團影響,氣溫較低,水氣增加,為多雲時陰有短暫雨的天氣,清晨起,局部地區已有短暫陣雨發生。
34
+ (21)日,受東北季風及華南雲雨區影響,氣溫略回升,為多雲短暫雨的天氣。預估氣溫16-18度,空曠地區有6至8級強陣風;清晨部分地區有短暫陣雨,外出請注意保暖和強風及攜帶雨具備用。
27
35
  ```
28
36
 
29
- The weather in the future week and other feature will be coming soon! :grinning:
37
+ To see the weather in the future week
38
+ ```sh
39
+ ➜ weather-scout-scraper git:(weekly-weather) ✗ ./bin/weatherscout week 新竹
40
+ 新竹(HsinchuCity)的未來一週預測:
41
+ 01/23星期六
42
+ -白天溫度:8 ~ 12 度
43
+ -白天天氣狀況:陰時多雲陣雨
44
+ -晚上溫度:6 ~ 8 度
45
+ -晚上天氣狀況:陰時多雲短暫雨
46
+ 01/24星期日
47
+ -白天溫度:5 ~ 7 度
48
+ -白天天氣狀況:多雲短暫雨
49
+ -晚上溫度:4 ~ 5 度
50
+ -晚上天氣狀況:多雲
51
+ 01/25星期一
52
+ -白天溫度:4 ~ 10 度
53
+ -白天天氣狀況:多雲時晴
54
+ -晚上溫度:8 ~ 9 度
55
+ -晚上天氣狀況:晴時多雲
56
+ 01/26星期二
57
+ -白天溫度:8 ~ 18 度
58
+ -白天天氣狀況:多雲時晴
59
+ -晚上溫度:13 ~ 15 度
60
+ -晚上天氣狀況:晴時多雲
61
+ 01/27星期三
62
+ -白天溫度:12 ~ 19 度
63
+ -白天天氣狀況:多雲時陰
64
+ -晚上溫度:15 ~ 16 度
65
+ -晚上天氣狀況:陰時多雲短暫陣雨
66
+ 01/28星期四
67
+ -白天溫度:15 ~ 18 度
68
+ -白天天氣狀況:多雲時陰短暫陣雨
69
+ -晚上溫度:15 ~ 16 度
70
+ -晚上天氣狀況:陰短暫陣雨
71
+ 01/29星期五
72
+ -白天溫度:15 ~ 18 度
73
+ -白天天氣狀況:陰短暫陣雨
74
+ -晚上溫度:15 ~ 16 度
75
+ -晚上天氣狀況:陰天
76
+ ```
30
77
 
31
78
  ## Development
32
79
  Use it from your Ruby code:
80
+ #### DailyWeather
33
81
  ````ruby
34
82
  require 'weatherscout'
35
83
  CITY = "新竹"
36
- weather = DailyWeatherScraper::DailyWeather.new(CITY)
84
+ daily_weather = DailyWeatherScraper::DailyWeather.new(CITY)
85
+
86
+ city = daily_weather.city
87
+ # ""HsinchuCity""
37
88
 
38
- temp = weather.temperature_day
39
- puts "今天白天氣溫:#{temp}"
89
+ weathers = daily_weather.weathers
90
+ # {"今晚至明晨 01/21 00:00~01/21 06:00"=>
91
+ # {"temperature"=>"15 ~ 16",
92
+ # "rain_probability"=>"70 %",
93
+ # "condition"=>"多雲短暫雨"},
94
+ # "明日白天 01/21 06:00~01/21 18:00"=>
95
+ # {"temperature"=>"15 ~ 18",
96
+ # "rain_probability"=>"60 %",
97
+ # "condition"=>"多雲短暫雨"},
98
+ # "明日晚上 01/21 18:00~01/22 06:00"=>
99
+ # {"temperature"=>"15 ~ 17",
100
+ # "rain_probability"=>"70 %",
101
+ # "condition"=>"多雲時陰陣雨"}}
40
102
 
41
- tips = weather.tips
42
- puts "溫馨提示:\n#{tips}"
103
+ tips = daily_weather.tips
104
+ # "東北季風及華南雲雨區影響,多雲短暫雨\n昨 (20)日,持續受大陸冷氣團影響,氣溫較低,水氣增加,為多雲時陰有短暫雨的天氣,清晨起,局部地區已有短暫陣雨發生。\n明 (21)日,受東北季風及華南雲雨區影響,氣溫略回升,為多雲短暫雨的天氣。預估氣溫16-18度,空曠地區有6至8級強陣風;清晨部分地區有短暫陣雨,外出請注意保暖和強風及攜帶雨具備用。\n"
43
105
 
44
106
  ````
45
107
 
108
+ ####WeeklyWeather
109
+ ```ruby
110
+ require 'weatherscout'
111
+ CITY = "新竹"
112
+ weekly_weather = WeatherScraper::WeeklyWeather.new(CITY)
113
+
114
+ city = daily_weather.city
115
+ # ""HsinchuCity""
116
+
117
+ weathers = daily_weather.weathers
118
+ # {"01/23星期六"=>{
119
+ # "day_temperature"=>"8 ~ 12",
120
+ # "day_condition"=>"陰時多雲陣雨",
121
+ # "night_temperature"=>"6 ~ 8",
122
+ # "night_condition"=>"陰時多雲短暫雨"},
123
+ # "01/24星期日"=>{
124
+ # "day_temperature"=>"5 ~ 7",
125
+ # "day_condition"=>"多雲短暫雨",
126
+ # "night_temperature"=>"4 ~ 5",
127
+ # "night_condition"=>"多雲"},
128
+ # "01/25星期一"=>{
129
+ # "day_temperature"=>"4 ~ 10",
130
+ # "day_condition"=>"多雲時晴",
131
+ # "night_temperature"=>"8 ~ 9",
132
+ # "night_condition"=>"晴時多雲"},
133
+ # "01/26星期二"=>{
134
+ # "day_temperature"=>"8 ~ 18",
135
+ # "day_condition"=>"多雲時晴",
136
+ # "night_temperature"=>"13 ~ 15",
137
+ # "night_condition"=>"晴時多雲"},
138
+ # "01/27星期三"=>{
139
+ # "day_temperature"=>"12 ~ 19",
140
+ # "day_condition"=>"多雲時陰",
141
+ # "night_temperature"=>"15 ~ 16",
142
+ # "night_condition"=>"陰時多雲短暫陣雨"},
143
+ # "01/28星期四"=>{
144
+ # "day_temperature"=>"15 ~ 18",
145
+ # "day_condition"=>"多雲時陰短暫陣雨",
146
+ # "night_temperature"=>"15 ~ 16",
147
+ # "night_condition"=>"陰短暫陣雨"},
148
+ # "01/29星期五"=>{
149
+ # "day_temperature"=>"15 ~ 18",
150
+ # "day_condition"=>"陰短暫陣雨",
151
+ # "night_temperature"=>"15 ~ 16",
152
+ # "night_condition"=>"陰天"}}
153
+
154
+ ```
155
+
46
156
  ## Test
47
157
  Using [rake](http://docs.seattlerb.org/rake/) to run tests. If you don't have rake using `gem install rake` to install it.
48
158
 
data/bin/weatherscout CHANGED
@@ -1,12 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'thor'
3
3
  require 'weatherscout' # for production
4
- # require './lib/weatherdesc/daily_weather.rb' # for cmd line testing purposes
4
+ # require './lib/weathers/weather_scraper/daily_weather.rb' # for cmd line testing purposes
5
+ # require './lib/weathers/weather_scraper/weekly_weather.rb' # for cmd line testing purposes
6
+
5
7
 
6
8
  class WeatherCLI < Thor
7
9
  desc 'today CITY', 'see the weather of the city today'
8
10
  def today(city)
9
- weather = DailyWeatherScraper::DailyWeather.new(city)
11
+ weather = WeatherScraper::DailyWeather.new(city)
10
12
  city_eng = weather.city
11
13
  weathers = weather.weathers
12
14
  tips = weather.tips
@@ -21,6 +23,26 @@ class WeatherCLI < Thor
21
23
  puts "溫馨叮嚀:"
22
24
  puts "#{tips}"
23
25
  end
26
+
27
+ desc 'week CITY', 'see the weather of the city this week'
28
+ def week(city)
29
+ weather = WeatherScraper::WeeklyWeather.new(city)
30
+ city_eng = weather.city
31
+ weathers = weather.weathers
32
+
33
+ day_temp = weathers.values.map {|e| e['day_temperature']}
34
+ day_cond = weathers.values.map {|e| e['day_condition']}
35
+ night_temp = weathers.values.map {|e| e['night_temperature']}
36
+ night_cond = weathers.values.map {|e| e['night_condition']}
37
+ puts "#{city}(#{city_eng})的未來一週預測:"
38
+ weathers.keys.each_index do |i|
39
+ puts "#{weathers.keys[i]}"
40
+ puts " -白天溫度:#{day_temp[i]} 度"
41
+ puts " -白天天氣狀況:#{day_cond[i]}"
42
+ puts " -晚上溫度:#{night_temp[i]} 度"
43
+ puts " -晚上天氣狀況:#{night_cond[i]}"
44
+ end
45
+ end
24
46
  end
25
47
 
26
48
  WeatherCLI.start(ARGV)
@@ -0,0 +1,5 @@
1
+ # Versioning
2
+ module WeatherDesc
3
+ VERSION = '0.3.1'
4
+ DATE = '2016-01-23'
5
+ end
@@ -0,0 +1,6 @@
1
+ require_relative './weather_scraper/weekly_weather.rb'
2
+ require_relative './weather_scraper/daily_weather.rb'
3
+ require_relative './weather_scraper/name_mapping.rb'
4
+
5
+ module WeatherScraper
6
+ end
@@ -0,0 +1,69 @@
1
+ require 'oga'
2
+ require 'open-uri'
3
+ require_relative 'name_mapping'
4
+
5
+ module WeatherScraper
6
+ # parse daily weather description from cwb website
7
+ class DailyWeather
8
+ include NameMapping
9
+ CWB_URL = "http://www.cwb.gov.tw"
10
+ CITY_WEATHER_URL = "#{CWB_URL}/V7/forecast/taiwan/"
11
+
12
+ def initialize(city)
13
+ @city = city_mapping(city).delete("_")
14
+ parse_html(city_mapping(city))
15
+ end
16
+
17
+ def city
18
+ @city
19
+ end
20
+
21
+ def weathers
22
+ @weathers ||= parse_weathers
23
+ end
24
+
25
+ def tips
26
+ @tips ||= parse_tips
27
+ end
28
+
29
+ private
30
+
31
+ def parse_html(city)
32
+ url = "#{CITY_WEATHER_URL}/#{city}.htm"
33
+ @document = Oga.parse_html(open(url))
34
+ end
35
+
36
+ def parse_weathers
37
+ data = @document.xpath("//table[@class='FcstBoxTable01']")
38
+ data[2].children[3].children.map do |weathers|
39
+ timestamp= weathers.children[1].children.text.force_encoding('UTF-8')
40
+ temperature = weathers.children[3].children.text
41
+ rain_probability = weathers.children[9].children.text
42
+ condition = weathers.children[5].children[1].attributes[1].value.force_encoding('UTF-8')
43
+ [timestamp,
44
+ {"temperature" => temperature,
45
+ "rain_probability" => rain_probability,
46
+ "condition" => condition}]
47
+ end.to_h
48
+ end
49
+
50
+ def parse_tips
51
+ data = @document.xpath("//div[@id='box8']")
52
+ tips_api = data[0].children[13].children[0].text.split("'")[1]
53
+ tips_url = "#{CWB_URL}/#{tips_api}"
54
+ tips_doc = Oga.parse_html(open(tips_url))
55
+ result = ""
56
+ tips_doc.children.each do |element|
57
+ if element.text.empty?
58
+ result << "\n"
59
+ elsif element.text.split(":")[0].force_encoding('UTF-8') == "更新時間"
60
+ break
61
+ else
62
+ result << element.text
63
+ end
64
+ end
65
+ result = result.gsub("\n\n","\n")
66
+ result.force_encoding('UTF-8')
67
+ end
68
+ end
69
+ end
@@ -1,70 +1,7 @@
1
- require 'oga'
2
- require 'open-uri'
3
-
4
- module DailyWeatherScraper
5
- # parse course description from sharecourse web
6
- class DailyWeather
7
- CWB_URL = "http://www.cwb.gov.tw"
8
- CITY_WEATHER_URL = "#{CWB_URL}/V7/forecast/taiwan/"
9
-
10
- def initialize(city)
11
- @city = name_mapping(city).delete("_")
12
- parse_html(name_mapping(city))
13
- end
14
-
15
- def city
16
- @city
17
- end
18
-
19
- def weathers
20
- @weathers ||= parse_weathers
21
- end
22
-
23
- def tips
24
- @tips ||= parse_tips
25
- end
26
-
27
- private
28
-
29
- def parse_html(city)
30
- url = "#{CITY_WEATHER_URL}/#{city}.htm"
31
- @document = Oga.parse_html(open(url))
32
- end
33
-
34
- def parse_weathers
35
- data = @document.xpath("//table[@class='FcstBoxTable01']")
36
- data[2].children[3].children.map do |weathers|
37
- timestamp= weathers.children[1].children.text.force_encoding('UTF-8')
38
- temperature = weathers.children[3].children.text
39
- rain_probability = weathers.children[9].children.text
40
- condition = weathers.children[5].children[1].attributes[1].value.force_encoding('UTF-8')
41
- [timestamp,
42
- {"temperature" => temperature,
43
- "rain_probability" => rain_probability,
44
- "condition" => condition}]
45
- end.to_h
46
- end
47
-
48
- def parse_tips
49
- data = @document.xpath("//div[@id='box8']")
50
- tips_api = data[0].children[13].children[0].text.split("'")[1]
51
- tips_url = "#{CWB_URL}/#{tips_api}"
52
- tips_doc = Oga.parse_html(open(tips_url))
53
- result = ""
54
- tips_doc.children.each do |element|
55
- if element.text.empty?
56
- result << "\n"
57
- elsif element.text.split(":")[0].force_encoding('UTF-8') == "更新時間"
58
- break
59
- else
60
- result << element.text
61
- end
62
- end
63
- result = result.gsub("\n\n","\n")
64
- result.force_encoding('UTF-8')
65
- end
66
-
67
- def name_mapping(city)
1
+ module WeatherScraper
2
+ # provide city name mapping
3
+ module NameMapping
4
+ def city_mapping(city)
68
5
  case city
69
6
  when "臺北", "台北", "臺北市", "台北市", "Taipei", "TaipeiCity"
70
7
  result = "Taipei_City"
@@ -0,0 +1,53 @@
1
+ require 'oga'
2
+ require 'open-uri'
3
+ require_relative 'name_mapping'
4
+
5
+ module WeatherScraper
6
+ # parse weekly weather description from cwb website
7
+ class WeeklyWeather
8
+ include NameMapping
9
+ CWB_URL = "http://www.cwb.gov.tw"
10
+ CITY_WEATHER_URL = "#{CWB_URL}/V7/forecast/taiwan/inc/city"
11
+
12
+ def initialize(city)
13
+ @city = city_mapping(city).delete("_")
14
+ parse_html(city_mapping(city))
15
+ end
16
+
17
+ def city
18
+ @city
19
+ end
20
+
21
+ def weathers
22
+ @weathers ||= parse_weathers
23
+ end
24
+
25
+ private
26
+
27
+ def parse_html(city)
28
+ url = "#{CITY_WEATHER_URL}/#{city}.htm"
29
+ @document = Oga.parse_html(open(url))
30
+ end
31
+
32
+ def parse_weathers
33
+ timestamp = @document.xpath("//th[@width='11%']")
34
+ timestamp = timestamp.map {|e| e.text.force_encoding('UTF-8')}
35
+
36
+ data = @document.xpath("//td")
37
+ temperature = data.map { |e| e.text.split(" ")[2]}
38
+ condition = data.map{ |e| e.children[1].attributes[1].value.force_encoding('UTF-8')}
39
+
40
+ result = []
41
+ timestamp.each_index do |i|
42
+ result << [timestamp[i],
43
+ {"day_temperature" => temperature[i+7],
44
+ "day_condition" => condition[i+7],
45
+ "night_temperature" => temperature[i],
46
+ "night_condition" => condition[i]
47
+ }
48
+ ]
49
+ end
50
+ result.to_h
51
+ end
52
+ end
53
+ end
data/lib/weatherscout.rb CHANGED
@@ -1 +1 @@
1
- require 'weatherdesc/daily_weather.rb'
1
+ require 'weathers/weather_scraper.rb'
@@ -1,54 +1,63 @@
1
+ require 'vcr'
2
+ require 'webmock'
1
3
  require 'minitest/autorun'
2
4
  require './lib/weatherscout.rb'
3
5
 
4
- CITY = "新竹"
5
- daily_weather = DailyWeatherScraper::DailyWeather.new(CITY)
6
+ DAILY_CITY = "新竹"
6
7
 
7
- describe 'Daily weather desc scrap' do
8
+ VCR.configure do |config|
9
+ config.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
10
+ config.hook_into :webmock
11
+ end
8
12
 
9
- it 'should return city name' do
10
- city = daily_weather.city
11
- city.must_be_instance_of String
12
- end
13
+ VCR.use_cassette('dailytweather') do
14
+ daily_weather = WeatherScraper::DailyWeather.new(DAILY_CITY)
15
+ describe 'Daily weather desc scrap' do
13
16
 
14
- it 'has the right number of period weathers' do
15
- weathers = daily_weather.weathers
16
- weathers.size.must_equal 3
17
- end
17
+ it 'should return city name' do
18
+ city = daily_weather.city
19
+ city.must_be_instance_of String
20
+ end
18
21
 
19
- it 'should return the timestamp in correct format' do
20
- timestamps = daily_weather.weathers.keys
21
- timestamps.each do |timestamp|
22
- timestamp.must_match /\A.{4,5}\s\d\d\/\d\d\s\d\d:\d\d~\d\d\/\d\d\s\d\d:\d\d/
22
+ it 'has the right number of period weathers' do
23
+ weathers = daily_weather.weathers
24
+ weathers.size.must_equal 3
23
25
  end
24
- end
25
26
 
26
- it 'should return temperature' do
27
- weathers = daily_weather.weathers.values
28
- weathers.each do |weather|
29
- temperature = weather["temperature"]
30
- temperature.must_match /(-|\d)\d+\s~\s(-|\d)\d+/
27
+ it 'should return the timestamp in correct format' do
28
+ timestamps = daily_weather.weathers.keys
29
+ timestamps.each do |timestamp|
30
+ timestamp.must_match /\A.{4,5}\s\d\d\/\d\d\s\d\d:\d\d~\d\d\/\d\d\s\d\d:\d\d/
31
+ end
31
32
  end
32
- end
33
33
 
34
- it 'should return weather condition' do
35
- weathers = daily_weather.weathers.values
36
- weathers.each do |weather|
37
- condition = weather["condition"]
38
- condition.must_be_instance_of String
34
+ it 'should return temperature' do
35
+ weathers = daily_weather.weathers.values
36
+ weathers.each do |weather|
37
+ temperature = weather["temperature"]
38
+ temperature.must_match /(-|\d)\d*\s~\s(-|\d)\d*/
39
+ end
39
40
  end
40
- end
41
41
 
42
- it 'should return rain probaliity' do
43
- weathers = daily_weather.weathers.values
44
- weathers.each do |weather|
45
- probaliity = weather["rain_probability"]
46
- probaliity.must_match /\d+\s%/
42
+ it 'should return weather condition' do
43
+ weathers = daily_weather.weathers.values
44
+ weathers.each do |weather|
45
+ condition = weather["condition"]
46
+ condition.must_be_instance_of String
47
+ end
48
+ end
49
+
50
+ it 'should return rain probaliity' do
51
+ weathers = daily_weather.weathers.values
52
+ weathers.each do |weather|
53
+ probaliity = weather["rain_probability"]
54
+ probaliity.must_match /\d+\s%/
55
+ end
47
56
  end
48
- end
49
57
 
50
- it 'should return weather tips' do
51
- tips = daily_weather.tips
52
- tips.must_be_instance_of String
58
+ # it 'should return weather tips' do
59
+ # tips = daily_weather.tips
60
+ # tips.must_be_instance_of String
61
+ # end
53
62
  end
54
63
  end