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