line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Finance::YahooProfile;
|
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
7440
|
use strict;
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
54
|
|
4
|
1
|
|
|
1
|
|
6
|
use vars qw($VERSION);
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
236
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
$VERSION = '1.12';
|
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
1345
|
use LWP::UserAgent;
|
|
1
|
|
|
|
|
92352
|
|
|
1
|
|
|
|
|
43
|
|
9
|
1
|
|
|
1
|
|
736390
|
use HTTP::Request::Common;
|
|
1
|
|
|
|
|
3493
|
|
|
1
|
|
|
|
|
2239
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
sub new {
|
12
|
0
|
|
|
0
|
1
|
|
my $type = shift;
|
13
|
0
|
|
0
|
|
|
|
my $class = ref $type || $type;
|
14
|
0
|
|
|
|
|
|
my $self = {};
|
15
|
0
|
|
|
|
|
|
bless $self, $class;
|
16
|
0
|
0
|
|
|
|
|
$self->_init(@_) if @_;
|
17
|
0
|
|
|
|
|
|
return $self;
|
18
|
|
|
|
|
|
|
}
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub _init {
|
21
|
0
|
|
|
0
|
|
|
my ($self, %params) = @_;
|
22
|
0
|
|
|
|
|
|
for (keys %params) {
|
23
|
0
|
|
|
|
|
|
$self->{$_} = $params{$_};
|
24
|
0
|
0
|
|
|
|
|
$self->{'dollar_symbol'} = 1 unless defined $params{'dollar_symbol'};
|
25
|
|
|
|
|
|
|
}
|
26
|
|
|
|
|
|
|
}
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub profile {
|
29
|
0
|
|
|
0
|
0
|
|
my ($self, %params) = @_;
|
30
|
|
|
|
|
|
|
|
31
|
0
|
|
|
|
|
|
my (@res, $ua);
|
32
|
|
|
|
|
|
|
|
33
|
0
|
|
|
|
|
|
$ua = LWP::UserAgent->new;
|
34
|
0
|
0
|
|
|
|
|
$ua->timeout($self->{'timeout'}) if defined $self->{'timeout'};
|
35
|
0
|
|
|
|
|
|
$ua->env_proxy();
|
36
|
|
|
|
|
|
|
|
37
|
0
|
0
|
|
|
|
|
if (not ref $params{'s'}) { $params{'s'} = [$params{'s'}]; }
|
|
0
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
|
39
|
0
|
|
|
|
|
|
my ($s, $firstletter, $url, $content, $res);
|
40
|
0
|
|
|
|
|
|
for $s ( @{$params{'s'}} ) {
|
|
0
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
42
|
0
|
|
|
|
|
|
$firstletter = substr($s, 0, 1);
|
43
|
0
|
|
|
|
|
|
$url = "http://biz.yahoo.com/p/$firstletter/$s.html";
|
44
|
0
|
|
|
|
|
|
$content = $ua->request(GET $url)->content();
|
45
|
0
|
|
|
|
|
|
$res = {}; ## to store the results
|
46
|
0
|
|
|
|
|
|
$res->{'requested_symbol'} = $s;
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
{
|
49
|
0
|
|
|
|
|
|
local $/;
|
|
0
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
|
$content =~ s/<[^>]*>//gs;
|
51
|
|
|
|
|
|
|
}
|
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
## Prepare Content for extraction
|
54
|
0
|
|
|
|
|
|
$content =~ s/ / /g; ## insert spaces
|
55
|
0
|
|
|
|
|
|
$content =~ s/.*(Statistics at a Glance -- )//s; ## remove the beginning
|
56
|
0
|
|
|
|
|
|
$content =~ s/(See Profile).*//s; ## remove the end
|
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
## Check for non-existent data
|
59
|
0
|
0
|
|
|
|
|
if ($content =~ /\nNo Such Data/) {
|
60
|
0
|
|
|
|
|
|
$res->{'success'} = 0;
|
61
|
0
|
|
|
|
|
|
push (@res, $res);
|
62
|
0
|
|
|
|
|
|
next;
|
63
|
|
|
|
|
|
|
}
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
## Market
|
66
|
0
|
|
|
|
|
|
$content =~ s/(.+?)://s;
|
67
|
0
|
|
|
|
|
|
$res->{'market'} = $1;
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
## Ticker Symbol
|
70
|
0
|
0
|
|
|
|
|
if ($content =~ s/(.+?)As of //s) {
|
71
|
0
|
|
|
|
|
|
$res->{'symbol'} = $1;
|
72
|
|
|
|
|
|
|
}
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
## Last Updated
|
75
|
0
|
0
|
|
|
|
|
if ($content =~ s/(.+?)Price and Volume//s) {
|
76
|
0
|
|
|
|
|
|
$res->{'last_updated'} = $1;
|
77
|
|
|
|
|
|
|
}
|
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
## 52-Week Prices
|
80
|
0
|
0
|
|
|
|
|
if ($content =~ s/52-Week Lowon (.+?)\$(.+?) Recent Price(.+?) 52-Week Highon (.+?)\$(.+?)( )?Beta/Beta/s) {
|
81
|
0
|
|
|
|
|
|
$res->{'52_week_low_date'} = $1;
|
82
|
0
|
|
|
|
|
|
$res->{'52_week_low'} = $2;
|
83
|
0
|
|
|
|
|
|
$res->{'recent_price'} = $3;
|
84
|
0
|
|
|
|
|
|
$res->{'52_week_high_date'} = $4;
|
85
|
0
|
|
|
|
|
|
$res->{'52_week_high'} = $5;
|
86
|
|
|
|
|
|
|
}
|
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
## Beta, and Volume Data
|
89
|
0
|
0
|
|
|
|
|
if ($content =~ s/Beta(.+?) Daily Volume \(3-month avg\)(.+?)Daily Volume \(10-day avg\)(.+?)Stock/Stock/s) {
|
90
|
0
|
|
|
|
|
|
$res->{'beta'} = $1;
|
91
|
0
|
|
|
|
|
|
$res->{'daily_volume_3ma'} = $2;
|
92
|
0
|
|
|
|
|
|
$res->{'daily_volume_10da'} = $3;
|
93
|
|
|
|
|
|
|
}
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
## 52-Week Price Change
|
96
|
0
|
0
|
|
|
|
|
if ($content =~ s/.+?52-Week Change(.+?)52-Week Changerelative to S&P500(.+?)Share//s) {
|
97
|
0
|
|
|
|
|
|
$res->{'52_week_change'} = $1;
|
98
|
0
|
|
|
|
|
|
$res->{'52_week_change_sp500'} = $2;
|
99
|
|
|
|
|
|
|
}
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
## Share related items
|
102
|
0
|
0
|
|
|
|
|
if ($content =~ s/.+?Market Capitalization(.+?)Shares Outstanding(.+?)Float(.+?)Dividends//s) {
|
103
|
0
|
|
|
|
|
|
$res->{'market_capitalization'} = $1;
|
104
|
0
|
|
|
|
|
|
$res->{'shares_outstanding'} = $2;
|
105
|
0
|
|
|
|
|
|
$res->{'shares_float'} = $3;
|
106
|
|
|
|
|
|
|
}
|
107
|
|
|
|
|
|
|
|
108
|
0
|
0
|
|
|
|
|
if ($content =~ s/.*?Annual Dividend( \(indicated\))?(.+?)( Dividend Yield(.+?))?Last Split(.+?)Per//s) {
|
109
|
0
|
|
|
|
|
|
$res->{'dividend'} = $2;
|
110
|
0
|
|
|
|
|
|
$res->{'dividend_yield'} = $4;
|
111
|
|
|
|
|
|
|
|
112
|
0
|
0
|
|
|
|
|
if ($5 ne 'none') {
|
113
|
0
|
0
|
|
|
|
|
if ($5 =~ m/factor (.+?) on (.+)/) {
|
114
|
0
|
|
|
|
|
|
$res->{'last_split_factor'} = $1;
|
115
|
0
|
|
|
|
|
|
$res->{'last_split_date'} = $2;
|
116
|
|
|
|
|
|
|
}
|
117
|
|
|
|
|
|
|
}
|
118
|
|
|
|
|
|
|
}
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
## Per-Share Data
|
121
|
0
|
0
|
|
|
|
|
if ($content =~ s/.+?Book Value \(mrq\*\)(.+?) Earnings \(ttm\)(.+?) (Earnings \(mrq\)(.+?) )?Sales \(ttm\)(.+?) Cash( \(mrq\*\)?)?(.+?) Valuation//s) {
|
122
|
0
|
|
|
|
|
|
$res->{'book_value'} = $1;
|
123
|
0
|
|
|
|
|
|
$res->{'earnings_ttm'} = $2;
|
124
|
0
|
|
|
|
|
|
$res->{'earnings_mrq'} = $4;
|
125
|
0
|
|
|
|
|
|
$res->{'sales_ttm'} = $5;
|
126
|
0
|
|
|
|
|
|
$res->{'cash'} = $7;
|
127
|
|
|
|
|
|
|
}
|
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
## Valuation Ratios
|
130
|
0
|
0
|
|
|
|
|
if ($content =~ s!.+?Price/Book \(mrq\*\)(.+?) Price/Earnings( \(ttm\))?(.+?) Price/Sales \(ttm\)(.+?) Income!!s) {
|
131
|
0
|
|
|
|
|
|
$res->{'price_book'} = $1;
|
132
|
0
|
|
|
|
|
|
$res->{'price_earnings'} = $3;
|
133
|
0
|
|
|
|
|
|
$res->{'price_sales'} = $4;
|
134
|
|
|
|
|
|
|
}
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
## Income Statements
|
137
|
0
|
0
|
|
|
|
|
if ($content =~ s/.+?Sales \(ttm\)(.+?)EBITDA \(ttm\*\)(.+?)Income available to common \(ttm\)(.+?)Profitability//s) {
|
138
|
0
|
|
|
|
|
|
$res->{'sales'} = $1;
|
139
|
0
|
|
|
|
|
|
$res->{'ebitda'} = $2;
|
140
|
0
|
|
|
|
|
|
$res->{'income'} = $3;
|
141
|
|
|
|
|
|
|
}
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
## Profitability
|
144
|
0
|
0
|
|
|
|
|
if ($content =~ s/.*?Profit Margin \(ttm\)(.+?)Operating Margin \(ttm\)(.+?)Fiscal//s) {
|
145
|
0
|
|
|
|
|
|
$res->{'profit_margin'} = $1;
|
146
|
0
|
|
|
|
|
|
$res->{'operating_margin'} = $2;
|
147
|
|
|
|
|
|
|
}
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
## Fiscal Year
|
150
|
0
|
0
|
|
|
|
|
if ($content =~ s/.*?Fiscal Year Ends(.+?)Most recent quarter(\(fully\nupdated\))?(.+?)(Most recent quarter\(flash earnings\)(.+?))?Management//s) {
|
151
|
0
|
|
|
|
|
|
$res->{'fiscal_year_ends'} = $1;
|
152
|
0
|
|
|
|
|
|
$res->{'most_recent_quarter'} = $3;
|
153
|
0
|
|
|
|
|
|
$res->{'most_recent_quarter_fe'} = $5;
|
154
|
0
|
|
|
|
|
|
$res->{'fiscal_year_ends'} =~ s/\n|\r/ /s;
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
}
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
## Management Effectiveness
|
159
|
0
|
0
|
|
|
|
|
if ($content =~ s/.*?Return on Assets \(ttm\)(.+?)Return on Equity \(ttm\)(.+?)Financial//s) {
|
160
|
0
|
|
|
|
|
|
$res->{'return_on_assets'} = $1;
|
161
|
0
|
|
|
|
|
|
$res->{'return_on_equity'} = $2;
|
162
|
|
|
|
|
|
|
}
|
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
## Financial Strength
|
165
|
0
|
0
|
|
|
|
|
if ($content =~ s/.*?Current Ratio( \(mrq\*?\))?(.+?) Debt\/Equity( \(mrq\*?\))?(.+?) Total Cash( \(mrq\*?\))?(.+?)Short//s) {
|
166
|
0
|
|
|
|
|
|
$res->{'current_ratio'} = $2;
|
167
|
0
|
|
|
|
|
|
$res->{'debt_equity'} = $4;
|
168
|
0
|
|
|
|
|
|
$res->{'total_cash'} = $6;
|
169
|
|
|
|
|
|
|
}
|
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
## Short Interest
|
172
|
0
|
0
|
|
|
|
|
if ($content =~ s/.*?InterestAs\nof (.+?)Shares\nShort(.+?)Percent of Float(.+?)Shares Short\(Prior Month\)(.+?)Short Ratio(.+?) Daily Volume([\d\.KMB]+)//s) {
|
173
|
0
|
|
|
|
|
|
$res->{'short_interest_date'} = $1;
|
174
|
0
|
|
|
|
|
|
$res->{'short_interest'} = $2;
|
175
|
0
|
|
|
|
|
|
$res->{'short_percent'} = $3;
|
176
|
0
|
|
|
|
|
|
$res->{'short_previous_month'} = $4;
|
177
|
0
|
|
|
|
|
|
$res->{'short_ratio'} = $5;
|
178
|
0
|
|
|
|
|
|
$res->{'short_daily_volume'} = $6;
|
179
|
|
|
|
|
|
|
}
|
180
|
|
|
|
|
|
|
|
181
|
0
|
0
|
0
|
|
|
|
$self->_expand($res) if $self->{'expand_numbers'} || $self->{'expand_percent'} || $self->{'expand'};
|
|
|
|
0
|
|
|
|
|
182
|
0
|
|
|
|
|
|
$res->{'success'} = 1;
|
183
|
|
|
|
|
|
|
|
184
|
0
|
|
|
|
|
|
push(@res, $res);
|
185
|
|
|
|
|
|
|
}
|
186
|
|
|
|
|
|
|
|
187
|
0
|
0
|
|
|
|
|
return wantarray ? @res : \@res;
|
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
}
|
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
sub _expand {
|
192
|
0
|
|
|
0
|
|
|
my ($self, $res) = @_;
|
193
|
0
|
|
|
|
|
|
my (%factors, $key, $dollar, $factor, @number_keys, @percent_keys);
|
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
|
%factors = ( 'K' => 1_000,
|
196
|
|
|
|
|
|
|
'M' => 1_000_000,
|
197
|
|
|
|
|
|
|
'B' => 1_000_000_000,
|
198
|
|
|
|
|
|
|
'T' => 1_000_000_000_000 ## for when we have the first trillion dollar company.
|
199
|
|
|
|
|
|
|
);
|
200
|
|
|
|
|
|
|
|
201
|
0
|
|
|
|
|
|
@number_keys = qw(
|
202
|
|
|
|
|
|
|
daily_volume_10da
|
203
|
|
|
|
|
|
|
daily_volume_3ma
|
204
|
|
|
|
|
|
|
ebitda
|
205
|
|
|
|
|
|
|
income
|
206
|
|
|
|
|
|
|
market_capitalization
|
207
|
|
|
|
|
|
|
sales
|
208
|
|
|
|
|
|
|
shares_float
|
209
|
|
|
|
|
|
|
shares_outstanding
|
210
|
|
|
|
|
|
|
short_interest
|
211
|
|
|
|
|
|
|
short_daily_volume
|
212
|
|
|
|
|
|
|
short_previous_month
|
213
|
|
|
|
|
|
|
total_cash
|
214
|
|
|
|
|
|
|
);
|
215
|
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
@percent_keys = qw(
|
217
|
|
|
|
|
|
|
52_week_change
|
218
|
|
|
|
|
|
|
52_week_change_sp500
|
219
|
|
|
|
|
|
|
dividend_yield
|
220
|
|
|
|
|
|
|
operating_margin
|
221
|
|
|
|
|
|
|
profit_margin
|
222
|
|
|
|
|
|
|
return_on_assets
|
223
|
|
|
|
|
|
|
return_on_equity
|
224
|
|
|
|
|
|
|
short_percent
|
225
|
|
|
|
|
|
|
);
|
226
|
|
|
|
|
|
|
|
227
|
0
|
0
|
0
|
|
|
|
if ($self->{'expand_numbers'} || $self->{'expand'}) {
|
228
|
0
|
|
|
|
|
|
for $key (@number_keys) {
|
229
|
0
|
0
|
|
|
|
|
$dollar = (($res->{$key} =~ s/^\$//) ? '$' : ''); ## save dollar sign'
|
230
|
|
|
|
|
|
|
|
231
|
0
|
0
|
|
|
|
|
if ($res->{$key} =~ s/(K|M|B|T)$//) {
|
232
|
0
|
|
|
|
|
|
$res->{$key} *= $factors{$1};
|
233
|
|
|
|
|
|
|
}
|
234
|
|
|
|
|
|
|
|
235
|
0
|
0
|
|
|
|
|
if ($self->{'dollar_symbol'}) {
|
236
|
0
|
|
|
|
|
|
$res->{$key} = $dollar . $res->{$key};
|
237
|
|
|
|
|
|
|
}
|
238
|
|
|
|
|
|
|
}
|
239
|
|
|
|
|
|
|
}
|
240
|
|
|
|
|
|
|
|
241
|
0
|
0
|
0
|
|
|
|
if ($self->{'expand_percent'} || $self->{'expand'}) {
|
242
|
0
|
|
|
|
|
|
for $key (@percent_keys) {
|
243
|
0
|
0
|
|
|
|
|
if ($res->{$key} =~ s/^([\+\-\d\.]+)%$/$1/) {
|
244
|
0
|
|
|
|
|
|
$res->{$key} /= 100;
|
245
|
|
|
|
|
|
|
}
|
246
|
|
|
|
|
|
|
}
|
247
|
|
|
|
|
|
|
}
|
248
|
|
|
|
|
|
|
}
|
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
1;
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
__END__
|