qticker 1.0.5 → 1.1.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.
- checksums.yaml +4 -4
- data/bin/qticker +3 -4
- data/lib/cli.rb +98 -41
- data/lib/dev_cli.rb +41 -45
- data/lib/main_cli.rb +23 -28
- data/lib/qticker.rb +16 -1
- data/lib/scraper.rb +98 -66
- data/lib/stock.rb +12 -9
- data/lib/stock_attribute.rb +14 -0
- data/lib/stock_description.rb +7 -0
- data/lib/stock_quote.rb +17 -0
- data/lib/stock_related_company.rb +7 -0
- data/lib/table.rb +16 -12
- metadata +41 -12
- data/config/environment.rb +0 -15
- data/lib/desc.rb +0 -8
- data/lib/fixtures/FBIOX.html +0 -1120
- data/lib/fixtures/IBM.html +0 -1269
- data/lib/fixtures/MSFT.html +0 -1268
- data/lib/fixtures/QQQ.html +0 -1059
- data/lib/quote.rb +0 -13
- data/lib/stock_attr.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0745f12aa2f16c3d7ea823422960cfe8ba8890dd
|
4
|
+
data.tar.gz: 8c708da85dab21449ba719530a3b1588ff9cf60a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ac5910a40bd4729b4348a5b1fcb01f73265eaddf64720a61fe9c5377d1d251eb0183fc72493f2f58e7c82f2744a5904c2d6f3d02694804aba8a6454ecc4b56d
|
7
|
+
data.tar.gz: a4693099fd176c612cb0a67185ea8806cc251fd0472595db88d967d10c44fa6f1f873f66bf0daa3a80ace63b9cdd8ad393302dfcbe472cc804c63ccde04933af
|
data/bin/qticker
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require_relative '../
|
3
|
+
require_relative '../lib/qticker.rb'
|
4
4
|
|
5
|
-
cli = MainCli.new
|
6
|
-
|
7
|
-
cli.welcome("Quick Ticker", -> {cli.ticker_symbol_prompt})
|
5
|
+
cli = QuickTicker::MainCli.new
|
6
|
+
cli.welcome("Quick Ticker", -> {cli.ticker_symbol_prompt})
|
data/lib/cli.rb
CHANGED
@@ -1,51 +1,108 @@
|
|
1
|
-
|
1
|
+
module QuickTicker
|
2
2
|
|
3
|
-
|
3
|
+
class Cli
|
4
4
|
|
5
|
-
|
6
|
-
self.scraper = Scraper.new(self)
|
7
|
-
end
|
5
|
+
attr_accessor :stock, :scraper, :last_option_lambda, :exit_message
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
7
|
+
def initialize(cli = nil)
|
8
|
+
self.scraper = QuickTicker::Scraper.new(self)
|
9
|
+
end
|
13
10
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
11
|
+
def welcome(mode_name, mode_lambda)
|
12
|
+
print "\nWelcome to " + mode_name + "!\n"
|
13
|
+
mode_lambda.()
|
14
|
+
end
|
19
15
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
self.stock_option_menu("Redisplay your quote", -> { self.display_quote })
|
24
|
-
end
|
16
|
+
def display_stock_header
|
17
|
+
print "\n#{self.stock.name} (#{self.stock.exchange}:#{self.stock.symbol})\n\n"
|
18
|
+
end
|
25
19
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
20
|
+
def display_stock_quote
|
21
|
+
puts "Current: #{self.stock.quote.price} #{stock.quote.change}(#{stock.quote.change_pct}%)"
|
22
|
+
puts "Open: #{self.stock.quote.open}"
|
23
|
+
puts "Volume: #{self.stock.quote.volume}"
|
24
|
+
puts "Avg Vol: #{self.stock.quote.volume_avg}"
|
25
|
+
puts "Mkt Cap: #{self.stock.quote.mkt_cap}"
|
26
|
+
puts "P/E(ttm): #{self.stock.quote.pe_ttm}"
|
27
|
+
puts "Yield: #{self.stock.quote.div_yld}%"
|
28
|
+
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
30
|
+
def display_stock_description
|
31
|
+
print "#{self.stock.description.sector} : #{self.stock.description.industry}\n\n"
|
32
|
+
puts "#{self.stock.description.summary}".fit
|
33
|
+
end
|
34
|
+
|
35
|
+
def display_stock_related_companies
|
36
|
+
output = "Symbol Price Mkt Cap\n"
|
37
|
+
self.stock.related_companies.each do |stock_related_company|
|
38
|
+
output += (stock_related_company.symbol + ' ' * 8)[0,8]
|
39
|
+
output += (stock_related_company.price + ' ' * 8)[0,8]
|
40
|
+
output += ("#{stock_related_company.change}(#{stock_related_company.change_pct}%)" + ' ' * 16)[0,16]
|
41
|
+
output += stock_related_company.mkt_cap + "\n"
|
42
|
+
end
|
43
|
+
puts output
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_stock_quote
|
47
|
+
self.display_stock_header
|
48
|
+
self.display_stock_quote
|
49
|
+
self.call_stock_option_menu({ option_1_string: "Display a company description", option_2_string: "Display related companies", option_1_lambda: -> { self.fetch_stock_description }, option_2_lambda: -> { self.fetch_stock_related_companies }, last_option_lambda: -> {self.last_option_lambda.()} })
|
50
|
+
end
|
49
51
|
|
52
|
+
def fetch_stock_description
|
53
|
+
self.display_stock_header
|
54
|
+
self.display_stock_description
|
55
|
+
self.call_stock_option_menu({ option_1_string: "Display a quote", option_2_string: "Display related companies", option_1_lambda: -> { self.fetch_stock_quote }, option_2_lambda: -> { self.fetch_stock_related_companies }, last_option_lambda: -> {self.last_option_lambda.()} })
|
56
|
+
end
|
57
|
+
|
58
|
+
def fetch_stock_related_companies
|
59
|
+
self.display_stock_header
|
60
|
+
self.display_stock_related_companies
|
61
|
+
self.call_stock_option_menu({ option_1_string: "Display a quote", option_2_string: "Display a company description", option_1_lambda: -> { self.fetch_stock_quote }, option_2_lambda: -> { self.fetch_stock_description }, last_option_lambda: -> {self.last_option_lambda.()} })
|
62
|
+
end
|
63
|
+
|
64
|
+
def call_stock_option_menu(option_hash)
|
65
|
+
process_stock_option_menu_input(display_stock_option_menu(option_hash[:option_1_string], option_hash[:option_2_string]), option_hash[:option_1_lambda], option_hash[:option_2_lambda], option_hash[:last_option_lambda])
|
66
|
+
end
|
67
|
+
|
68
|
+
def display_stock_option_menu(option_1_string, option_2_string)
|
69
|
+
gets
|
70
|
+
puts "1. #{option_1_string} for #{self.stock.symbol}."
|
71
|
+
puts "2. #{option_2_string} for #{self.stock.symbol}."
|
72
|
+
puts "3. Enter another ticker symbol."
|
73
|
+
puts "Enter any other key to exit."
|
74
|
+
gets.strip.gsub('.', '')
|
75
|
+
end
|
76
|
+
|
77
|
+
def process_stock_option_menu_input(input, option_1_lambda, option_2_lambda, option_3_lambda)
|
78
|
+
if input == "1"
|
79
|
+
option_1_lambda.()
|
80
|
+
elsif input == "2"
|
81
|
+
option_2_lambda.()
|
82
|
+
elsif input == "3"
|
83
|
+
option_3_lambda.()
|
84
|
+
else
|
85
|
+
puts self.exit_message
|
86
|
+
return nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def symbol_validation(symbol, fixture_url = nil)
|
91
|
+
# stock_array[0] is a stock if one was succesfully created and nil otherwise.
|
92
|
+
# stock_array[1] indicates whether the symbol cooresponds to a mutual fund.
|
93
|
+
stock_array = self.scraper.load_gfs(symbol, fixture_url)
|
94
|
+
self.stock = stock_array[0]
|
95
|
+
valid = self.stock.nil? ? false : true
|
96
|
+
puts "Invalid ticker symbol." if !valid
|
97
|
+
puts "Mutual funds are not currently not supported." if stock_array[1]
|
98
|
+
self.fetch_stock_quote if valid
|
99
|
+
# returns an array.
|
100
|
+
# array[0] - whether the entered symbol was valid
|
101
|
+
# array[1] = stock_array[1] - whether the entered
|
102
|
+
# symbol was a mutal fund.
|
103
|
+
[valid, stock_array[1]]
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
50
107
|
|
51
108
|
end
|
data/lib/dev_cli.rb
CHANGED
@@ -1,58 +1,54 @@
|
|
1
|
-
|
1
|
+
module QuickTicker
|
2
2
|
|
3
|
-
|
3
|
+
class DevCli < QuickTicker::Cli
|
4
4
|
|
5
|
-
|
6
|
-
super(main_cli)
|
7
|
-
self.main = main_cli
|
8
|
-
end
|
5
|
+
attr_accessor :main
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
puts "4. Load FBIOX.html"
|
16
|
-
puts "Or enter any other key to return to"
|
17
|
-
puts "your regularly scheduled program."
|
18
|
-
input = gets.strip.gsub('.', '')
|
19
|
-
path = File.expand_path(File.dirname(__FILE__)).chomp('bin') + '/fixtures/'
|
20
|
-
if input == "1"
|
21
|
-
valid = self.symbol_validation("MSFT", false, path + "MSFT.html")
|
22
|
-
elsif input == "2"
|
23
|
-
valid = self.symbol_validation("IBM", false, path + "IBM.html")
|
24
|
-
elsif input == "3"
|
25
|
-
valid = self.symbol_validation("QQQ", false, path + "QQQ.html")
|
26
|
-
elsif input == "4"
|
27
|
-
valid = self.symbol_validation("FBIOX", false, path + "FBIOX.html")
|
28
|
-
else
|
29
|
-
puts "Leaving Developer Mode and resuming program."
|
7
|
+
def initialize(main_cli)
|
8
|
+
super(main_cli)
|
9
|
+
self.main = main_cli
|
10
|
+
self.last_option_lambda = -> { self.call_dev_option_menu }
|
11
|
+
self.exit_message = "Leaving Developer Mode and resuming program."
|
30
12
|
end
|
31
|
-
return nil
|
32
|
-
end
|
33
13
|
|
34
|
-
|
35
|
-
|
36
|
-
if input == "1"
|
37
|
-
opt_1_lambda.()
|
38
|
-
elsif input == "2"
|
39
|
-
self.option_menu
|
40
|
-
else
|
41
|
-
puts "Leaving Developer Mode and resuming program."
|
42
|
-
return nil
|
14
|
+
def call_dev_option_menu
|
15
|
+
process_dev_option_menu_input(display_dev_option_menu)
|
43
16
|
end
|
44
|
-
end
|
45
17
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
puts ""
|
50
|
-
|
18
|
+
def display_dev_option_menu
|
19
|
+
puts "\nPlease select a fixture to load:"
|
20
|
+
puts "1. Load MSFT.html"
|
21
|
+
puts "2. Load IBM.html"
|
22
|
+
puts "3. Load QQQ.html"
|
23
|
+
puts "4. Load FBIOX.html"
|
24
|
+
puts "Or enter any other key to return to"
|
25
|
+
puts "your regularly scheduled program."
|
26
|
+
gets.strip.gsub('.', '')
|
51
27
|
end
|
52
|
-
valid_array[0] # returns whether entered symbol was valid
|
53
|
-
end
|
54
28
|
|
29
|
+
def process_dev_option_menu_input(input)
|
30
|
+
if input == "1"
|
31
|
+
valid = self.symbol_validation("MSFT", "http://lair001.github.io/fixtures/qticker/MSFT.html")
|
32
|
+
elsif input == "2"
|
33
|
+
valid = self.symbol_validation("IBM", "http://lair001.github.io/fixtures/qticker/IBM.html")
|
34
|
+
elsif input == "3"
|
35
|
+
valid = self.symbol_validation("QQQ", "http://lair001.github.io/fixtures/qticker/QQQ.html")
|
36
|
+
elsif input == "4"
|
37
|
+
valid = self.symbol_validation("FBIOX", "http://lair001.github.io/fixtures/qticker/FBIOX.html")
|
38
|
+
else
|
39
|
+
puts self.exit_message
|
40
|
+
end
|
41
|
+
return nil
|
42
|
+
end
|
55
43
|
|
44
|
+
def symbol_validation(symbol, fixture_url = nil)
|
45
|
+
valid_array = super(symbol, fixture_url)
|
46
|
+
if valid_array[1] # whether entered symbol was a mutual fund
|
47
|
+
call_dev_option_menu
|
48
|
+
end
|
49
|
+
valid_array[0] # returns whether entered symbol was valid
|
50
|
+
end
|
56
51
|
|
52
|
+
end
|
57
53
|
|
58
54
|
end
|
data/lib/main_cli.rb
CHANGED
@@ -1,39 +1,34 @@
|
|
1
|
-
|
1
|
+
module QuickTicker
|
2
2
|
|
3
|
-
|
3
|
+
class MainCli < QuickTicker::Cli
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
attr_accessor :dev
|
6
|
+
|
7
|
+
def initialize(cli = nil)
|
8
|
+
super(cli)
|
9
|
+
self.dev = QuickTicker::DevCli.new(self)
|
10
|
+
self.last_option_lambda = -> { self.ticker_symbol_prompt }
|
11
|
+
self.exit_message = "Thank you for using Quick Ticker!"
|
12
|
+
end
|
9
13
|
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
def ticker_symbol_prompt
|
16
|
+
valid = false
|
17
|
+
while !valid do
|
18
|
+
print "\nPlease enter a ticker symbol: "
|
19
|
+
symbol = gets.strip.upcase
|
20
|
+
if symbol == "DEV"
|
21
|
+
self.dev.welcome("Developer Mode", -> {self.dev.call_dev_option_menu}) if symbol == "DEV"
|
22
|
+
else
|
23
|
+
valid = self.symbol_validation(symbol)
|
24
|
+
end
|
20
25
|
end
|
21
26
|
end
|
22
|
-
end
|
23
27
|
|
24
|
-
|
25
|
-
|
26
|
-
if input == "1"
|
27
|
-
opt_1_lambda.()
|
28
|
-
elsif input == "2"
|
29
|
-
self.ticker_symbol_prompt
|
30
|
-
else
|
31
|
-
return nil
|
28
|
+
def symbol_validation(symbol, fixture_url = nil)
|
29
|
+
super(symbol)[0] # returns whether entered symbol was valid
|
32
30
|
end
|
33
|
-
end
|
34
31
|
|
35
|
-
def symbol_validation(symbol, valid, fixture_url = nil)
|
36
|
-
super(symbol, valid)[0] # returns whether entered symbol was valid
|
37
32
|
end
|
38
33
|
|
39
|
-
end
|
34
|
+
end
|
data/lib/qticker.rb
CHANGED
@@ -1 +1,16 @@
|
|
1
|
-
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'word_wrap'
|
3
|
+
require 'word_wrap/core_ext'
|
4
|
+
require 'watir'
|
5
|
+
require 'phantomjs'
|
6
|
+
|
7
|
+
require_relative '../lib/cli.rb'
|
8
|
+
require_relative '../lib/table.rb'
|
9
|
+
require_relative '../lib/stock_attribute.rb'
|
10
|
+
require_relative '../lib/stock_description.rb'
|
11
|
+
require_relative '../lib/dev_cli.rb'
|
12
|
+
require_relative '../lib/main_cli.rb'
|
13
|
+
require_relative '../lib/stock_quote.rb'
|
14
|
+
require_relative '../lib/stock_related_company.rb'
|
15
|
+
require_relative '../lib/scraper.rb'
|
16
|
+
require_relative '../lib/stock.rb'
|
data/lib/scraper.rb
CHANGED
@@ -1,82 +1,114 @@
|
|
1
|
-
|
1
|
+
module QuickTicker
|
2
2
|
|
3
|
-
|
3
|
+
class Scraper
|
4
4
|
|
5
|
-
|
6
|
-
self.cli = cli
|
7
|
-
end
|
5
|
+
attr_accessor :browser, :cli, :gfs_noko_html, :stock
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
def initialize(cli)
|
8
|
+
self.cli = cli
|
9
|
+
self.browser = Watir::Browser.new(:phantomjs)
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
def gfs_url(symbol)
|
13
|
+
"https://www.google.com/finance?q=" + symbol
|
14
|
+
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
return [nil, true] unless self.gfs_noko_html.text.match('\(MUTF:').nil?
|
22
|
-
return [nil, false] if self.gfs_noko_html.css("span.pr").text.strip == "" # checks whether the page lists a price
|
23
|
-
# return [nil, false] if self.gfs_noko_html.css("div.fjfe-content").text.include?("- produced no matches.")
|
24
|
-
[self.create_stock(symbol), false]
|
25
|
-
end
|
16
|
+
def load_gfs_noko_html(url)
|
17
|
+
browser.goto(url)
|
18
|
+
self.gfs_noko_html = Nokogiri::HTML(browser.html)
|
19
|
+
end
|
26
20
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
21
|
+
# Returns an array. Array[0] is a stock if one was succesfully created and nil otherwise.
|
22
|
+
# Array[1] indicates whether the symbol cooresponds to a mutual fund.
|
23
|
+
def load_gfs(symbol, fixture_url = nil)
|
24
|
+
fixture_url.nil? ? load_gfs_noko_html(self.gfs_url(symbol)) : load_gfs_noko_html(fixture_url)
|
25
|
+
return [nil, true] unless self.gfs_noko_html.text.match('\(MUTF:').nil?
|
26
|
+
return [nil, false] if self.gfs_noko_html.css("span.pr").text.strip == "" # checks whether the page lists a price
|
27
|
+
# return [nil, false] if self.gfs_noko_html.css("div.fjfe-content").text.include?("- produced no matches.")
|
28
|
+
[self.create_stock(symbol), false]
|
29
|
+
end
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
begin
|
36
|
-
data[:stock][:name] = self.gfs_noko_html.css("div.g-first a").text.match('(?<=All news for )[\w,.)() ]*(?= »)')[0]
|
37
|
-
rescue NoMethodError
|
38
|
-
data[:stock][:name] = ""
|
31
|
+
def create_stock(symbol)
|
32
|
+
data = package_stock(symbol)
|
33
|
+
QuickTicker::Stock.new(data)
|
39
34
|
end
|
40
|
-
data[:stock][:exchange] = self.gfs_noko_html.css("span.dis-large").text.split("\n")[0]
|
41
|
-
data[:stock] = self.nil_to_empty_str(data[:stock])
|
42
|
-
data[:quote] = self.scrape_quote
|
43
|
-
data[:desc] = self.scrape_desc
|
44
|
-
data
|
45
|
-
end
|
46
35
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
data[:
|
53
|
-
|
54
|
-
data[:change_pct] = ""
|
36
|
+
def package_stock(symbol)
|
37
|
+
data = {}
|
38
|
+
data[:stock] = self.scrape_stock(symbol)
|
39
|
+
data[:quote] = self.scrape_stock_quote
|
40
|
+
data[:description] = self.scrape_stock_description
|
41
|
+
data[:related_companies] = self.scrape_stock_related_companies
|
42
|
+
data
|
55
43
|
end
|
56
|
-
data[:range] = self.gfs_noko_html.css("td[data-snapfield='range']+td").text.strip
|
57
|
-
data[:range_yr] = self.gfs_noko_html.css("td[data-snapfield='range_52week']+td").text.strip
|
58
|
-
data[:open] = self.gfs_noko_html.css("td[data-snapfield='open']+td").text.strip
|
59
|
-
data[:volume] = self.gfs_noko_html.css("td[data-snapfield='vol_and_avg']+td").text.strip.split("/")[0]
|
60
|
-
data[:volume_avg] = self.gfs_noko_html.css("td[data-snapfield='vol_and_avg']+td").text.strip.split("/")[1]
|
61
|
-
data[:mkt_cap] = self.gfs_noko_html.css("td[data-snapfield='market_cap']+td").text.strip
|
62
|
-
data[:pe_ttm] = self.gfs_noko_html.css("td[data-snapfield='pe_ratio']+td").text.strip
|
63
|
-
data[:div_yld] = self.gfs_noko_html.css("td[data-snapfield='latest_dividend-dividend_yield']+td").text.strip.split("/")[1]
|
64
|
-
nil_to_empty_str(data)
|
65
|
-
end
|
66
44
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
45
|
+
def scrape_stock(symbol)
|
46
|
+
data = {}
|
47
|
+
data[:symbol] = symbol
|
48
|
+
begin
|
49
|
+
data[:name] = self.gfs_noko_html.css("div.g-first a").text.match('(?<=All news for )[\w,.)() ]*(?= »)')[0]
|
50
|
+
rescue NoMethodError
|
51
|
+
data[:name] = ""
|
52
|
+
end
|
53
|
+
data[:exchange] = self.gfs_noko_html.css("span.dis-large").text.split("\n")[0]
|
54
|
+
nil_to_empty_str(data)
|
55
|
+
end
|
56
|
+
|
57
|
+
def scrape_stock_quote
|
58
|
+
data = {}
|
59
|
+
data[:price] = self.gfs_noko_html.css("span.pr").text.strip
|
60
|
+
data[:change] = self.gfs_noko_html.css("div.nwp span.bld").text.split("\n")[0]
|
61
|
+
begin
|
62
|
+
data[:change_pct] = self.gfs_noko_html.css("div.nwp span.bld").text.split("\n")[1].gsub(/[)(]/, '').chomp("%")
|
63
|
+
rescue NoMethodError
|
64
|
+
data[:change_pct] = ""
|
65
|
+
end
|
66
|
+
data[:range] = self.gfs_noko_html.css("td[data-snapfield='range']+td").text.strip
|
67
|
+
data[:range_yr] = self.gfs_noko_html.css("td[data-snapfield='range_52week']+td").text.strip
|
68
|
+
data[:open] = self.gfs_noko_html.css("td[data-snapfield='open']+td").text.strip
|
69
|
+
data[:volume] = self.gfs_noko_html.css("td[data-snapfield='vol_and_avg']+td").text.strip.split("/")[0]
|
70
|
+
data[:volume_avg] = self.gfs_noko_html.css("td[data-snapfield='vol_and_avg']+td").text.strip.split("/")[1]
|
71
|
+
data[:mkt_cap] = self.gfs_noko_html.css("td[data-snapfield='market_cap']+td").text.strip
|
72
|
+
data[:pe_ttm] = self.gfs_noko_html.css("td[data-snapfield='pe_ratio']+td").text.strip
|
73
|
+
data[:div_yld] = self.gfs_noko_html.css("td[data-snapfield='latest_dividend-dividend_yield']+td").text.strip.split("/")[1]
|
74
|
+
nil_to_empty_str(data)
|
75
|
+
end
|
74
76
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
77
|
+
def scrape_stock_description
|
78
|
+
data = {}
|
79
|
+
data[:sector] = self.gfs_noko_html.css("a#sector").text
|
80
|
+
data[:industry] = self.gfs_noko_html.css("a#sector+a").text
|
81
|
+
data[:summary] = self.gfs_noko_html.css("div.companySummary").text.gsub("More from Reuters »", "").strip
|
82
|
+
nil_to_empty_str(data)
|
79
83
|
end
|
84
|
+
|
85
|
+
def scrape_stock_related_companies
|
86
|
+
data = []
|
87
|
+
for i in (0..10) do
|
88
|
+
begin
|
89
|
+
data << {
|
90
|
+
symbol: self.gfs_noko_html.css("table#cc-table td.ctsymbol")[i].text,
|
91
|
+
price: self.gfs_noko_html.css("table#cc-table td.ctsymbol+td+td")[i].text,
|
92
|
+
change: self.gfs_noko_html.css("table#cc-table td.ctsymbol+td+td+td")[i].text,
|
93
|
+
change_pct: self.gfs_noko_html.css("table#cc-table td.ctsymbol+td+td+td+td")[i].text.chomp("%"),
|
94
|
+
mkt_cap: self.gfs_noko_html.css("table#cc-table td.ctsymbol+td+td+td+td+td+td")[i].text
|
95
|
+
}
|
96
|
+
rescue NoMethodError
|
97
|
+
i = 11
|
98
|
+
end
|
99
|
+
end
|
100
|
+
data.collect do |related_company_hash|
|
101
|
+
nil_to_empty_str(related_company_hash)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# convert any nil values to empty strings to avoid exceptions
|
106
|
+
def nil_to_empty_str(data_hash)
|
107
|
+
data_hash.each do |key, value|
|
108
|
+
data_hash[key] = "" if data_hash[key].nil?
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
80
112
|
end
|
81
113
|
|
82
114
|
end
|