File Coverage

blib/lib/Finance/Quote/MarketWatch.pm
Criterion Covered Total %
statement 23 68 33.8
branch 0 8 0.0
condition n/a
subroutine 9 10 90.0
pod 0 3 0.0
total 32 89 35.9


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             # vi: set ts=2 sw=2 noai ic showmode showmatch:
3             #
4             # Copyright (C) 2023, Bruce Schuck <bschuck@asgard-systems.com>
5             #
6             # This program is free software; you can redistribute it and/or modify
7             # it under the terms of the GNU General Public License as published by
8             # the Free Software Foundation; either version 2 of the License, or
9             # (at your option) any later version.
10             #
11             # This program is distributed in the hope that it will be useful,
12             # but WITHOUT ANY WARRANTY; without even the implied warranty of
13             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14             # GNU General Public License for more details.
15             #
16             # You should have received a copy of the GNU General Public License
17             # along with this program; if not, write to the Free Software
18             # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19             # 02110-1301, USA
20             #
21              
22             package Finance::Quote::MarketWatch;
23              
24 5     5   2654 use strict;
  5         25  
  5         161  
25 5     5   42 use warnings;
  5         15  
  5         225  
26              
27 5     5   30 use Encode qw(decode);
  5         14  
  5         248  
28 5     5   33 use HTTP::Request::Common;
  5         21  
  5         348  
29 5     5   46 use HTML::TreeBuilder;
  5         24  
  5         96  
30              
31 5     5   232 use constant DEBUG => $ENV{DEBUG};
  5         26  
  5         359  
32 5     5   35 use if DEBUG, 'Smart::Comments', '###';
  5         21  
  5         31  
33              
34             our $VERSION = '1.58'; # VERSION
35              
36             my $MW_URL = 'https://www.marketwatch.com/investing/stock/';
37              
38             sub methods {
39 5     5 0 30 return (marketwatch => \&marketwatch,
40             nyse => \&marketwatch,
41             nasdaq => \&marketwatch);
42             }
43              
44             our @labels = qw/symbol name last date currency method/;
45              
46             sub labels {
47 5     5 0 19 return (marketwatch => \@labels,
48             nyse => \@labels,
49             nasdaq => \@labels);
50             }
51              
52             sub marketwatch {
53              
54 0     0 0   my $quoter = shift;
55 0           my @stocks = @_;
56 0           my (%info, $tree, $url, $reply);
57 0           my $ua = $quoter->user_agent();
58              
59 0           foreach my $stock (@stocks) {
60              
61 0           $url = $MW_URL . $stock;
62 0           $reply = $ua->get($url);
63              
64 0           my $code = $reply->code;
65 0           my $desc = HTTP::Status::status_message($code);
66 0           my $headers = $reply->headers_as_string;
67 0           my $body = decode('UTF-8', $reply->content);
68              
69             ### Body: $body
70              
71 0           my ($name, $last, $open, $date, $currency, $metatag);
72 0           my (%datehash, @timearray, $timestring);
73              
74 0           $info{ $stock, "symbol" } = $stock;
75              
76 0 0         if ( $code == 200 ) {
77              
78             # Use HTML::TreeBuilder to parse HTML in $body
79 0           $tree = HTML::TreeBuilder->new;
80 0 0         if ($tree->parse($body)) {
81              
82 0           $tree->eof;
83              
84 0 0         if ($metatag = $tree->look_down(_tag => 'meta', name => 'name')) {
85 0           $info{ $stock, 'name' } = $metatag->attr('content');
86             } else {
87 0           $info{ $stock, 'success'} = 0;
88 0           $info{ $stock, 'errormsg' } = 'Error retrieving quote for $stock.';
89 0           next;
90             }
91              
92 0           $metatag = $tree->look_down(_tag => 'meta', name => 'tickerSymbol');
93 0           $info{ $stock, 'symbol' } = $metatag->attr('content');
94              
95 0           $metatag = $tree->look_down(_tag => 'meta', name => 'price');
96 0           ($info{ $stock, 'last' } = $metatag->attr('content')) =~ s/[^0-9.]//g;
97              
98 0           $metatag = $tree->look_down(_tag => 'meta', name => 'priceCurrency');
99 0           $info{ $stock, 'currency' } = $metatag->attr('content');
100              
101 0           $metatag = $tree->look_down(_tag => 'meta', name => 'quoteTime');
102 0           $date = $metatag->attr('content');
103 0           @timearray = split / /, $date;
104 0           $timearray[1] =~ s/[^0-9]//g;
105 0           %datehash = (
106             year => $timearray[2],
107             month => $timearray[0],
108             day => $timearray[1] );
109 0           ($timestring = $timearray[4]) =~ s|\.||g;
110 0           $quoter->store_date(\%info, $stock, \%datehash);
111              
112 0           $info{ $stock, 'success' } = 1;
113              
114 0           $info{ $stock, 'method' } = 'marketwatch';
115              
116             } else {
117 0           $tree->eof;
118 0           $info{ $stock, "success" } = 0;
119 0           $info{ $stock, "errormsg" } =
120             "Error retrieving quote for $stock. Could not parse HTML returned from $url.";
121             }
122              
123             } else { # HTTP Request failed (code != 200)
124 0           $info{ $stock, "success" } = 0;
125 0           $info{ $stock, "errormsg" } =
126             "Error retrieving quote for $stock. Attempt to fetch the URL $url resulted in HTTP response $code ($desc)";
127             }
128              
129             }
130              
131 0 0         return wantarray() ? %info : \%info;
132 0           return \%info;
133              
134             }
135              
136             1;
137              
138             __END__
139              
140             =head1 NAME
141              
142             Finance::Quote::MarketWatch - Obtain quotes from MarketWatch Website
143              
144             =head1 SYNOPSIS
145              
146             use Finance::Quote;
147              
148             $q = Finance::Quote->new;
149              
150             %info = $q->fetch("marketwatch", "aapl"); # Only query marketwatch
151              
152             %info = $q->fetch("nyse", "f"); # Failover to other sources OK.
153              
154             =head1 DESCRIPTION
155              
156             This module fetches information from L<https://www.marketwatch.com/>.
157              
158             This module is loaded by default on a Finance::Quote object. It's also possible
159             to load it explicitly by placing "marketwatch" in the argument list to
160             Finance::Quote->new().
161              
162             This module provides "marketwatch", "nyse", and "nasdaq"
163             fetch methods.
164              
165             =head1 LABELS RETURNED
166              
167             The following labels are returned:
168              
169             =over
170              
171             =item name
172              
173             =item symbol
174              
175             =item last
176              
177             =item date
178              
179             =item currency
180              
181             =back