—#!/usr/bin/perl -W
#
# Copyright (C) 1998, Dj Padzensky <djpadz@padz.net>
# Copyright (C) 1998, 1999 Linas Vepstas <linas@linas.org>
# Copyright (C) 2000, Yannick LE NY <y-le-ny@ifrance.com>
# Copyright (C) 2000, Paul Fenwick <pjf@cpan.org>
# Copyright (C) 2000, Brent Neal <brentn@users.sourceforge.net>
# Copyright (C) 2000, Volker Stuerzl <volker.stuerzl@gmx.de>
# Copyright (C) 2003,2005,2006 Jörg Sommer <joerg@alea.gnuu.de>
# Copyright (C) 2008 Martin Kompf (skaringa at users.sourceforge.net)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA
#
#
# This code derived from Padzensky's work on package Finance::YahooQuote,
# but extends its capabilites to encompas a greater number of data sources.
#
# This code was developed as part of GnuCash <http://www.gnucash.org/>
# =============================================================
package
Finance::Quote::VWD;
require
5.005;
use
strict;
use
LWP::UserAgent;
use
HTML::TreeBuilder;
use
HTML::TableExtract;
our
$VERSION
=
'1.28'
;
# VERSION
sub
methods {
return
(
vwd
=> \
&vwd
); }
sub
labels {
return
(
vwd
=> [
qw/currency date isodate name price last symbol time/
] );
}
# =======================================================================
# The vwd routine gets quotes of funds from the website of
# vwd Vereinigte Wirtschaftsdienste GmbH.
#
# This subroutine was written by Volker Stuerzl <volker.stuerzl@gmx.de>
# and adjusted to match the new vwd interface by Jörg Sommer
# Trim leading and tailing whitespaces (also non-breakable whitespaces)
sub
trim {
$_
=
shift
();
s/^\s*//;
s/\s*$//;
s/
 
;//g;
return
$_
;
}
# Trim leading and tailing whitespaces, leading + and tailing %, leading
# and tailing ± (plus minus) and translate german separators into
# english separators. Also removes the thousands separator in returned
# values.
sub
trimtr {
$_
=
shift
();
s/
 
;//g;
s/
±
;//g;
s/^\s*\+?//;
s/\%?\s*$//;
tr
/,./.,/;
s/,//g;
return
$_
;
}
sub
vwd {
my
$quoter
=
shift
;
my
$ua
=
$quoter
->user_agent();
my
@funds
=
@_
;
return
unless
(
@funds
);
my
%info
;
# LOGGING - set to 1 to enable log file
my
$logging
= 0;
if
(
$logging
) {
open
( LOG,
">>/tmp/vwd.log"
);
}
my
$max_retry
= 30;
foreach
my
$fund
(
@funds
) {
$info
{
$fund
,
"source"
} =
"VWD"
;
$info
{
$fund
,
"success"
} = 0;
$info
{
$fund
,
"errormsg"
} =
"Parse error"
;
my
$request
=
.
"kurse_einzelkurs_uebersicht.htn?s="
.
$fund
;
if
(
$logging
) {
LOG
"Request='$request'\n"
;
}
my
$response
=
$ua
->get(
$request
);
if
(
$response
->is_success ) {
my
$html
=
$response
->decoded_content;
my
$tree
= HTML::TreeBuilder->new;
$tree
->parse(
$html
);
# all other info below <div class=contentContainer>
my
$content
=
$tree
->look_down(
"_tag"
,
"div"
,
"class"
,
"contentContainer"
);
next
if
not
$content
;
my
$wpkurs
=
$content
->look_down(
"_tag"
,
"div"
,
"class"
,
qr/wpKurs/
);
next
if
not
$wpkurs
;
my
$title
=
$wpkurs
->find(
"h1"
);
$title
->find(
"span"
)->delete_content;
$info
{
$fund
,
"name"
} =
$title
->as_trimmed_text;
my
$te
= new HTML::TableExtract(
depth
=> 0,
count
=> 0 );
$te
->parse(
$wpkurs
->as_HTML );
my
$table
=
$te
->first_table_found;
my
$datum
=
$table
->cell( 0, 1 );
if
(
$logging
) {
LOG
"datum: $datum\n"
;
}
if
(
$datum
=~ /([(0123]\d)\.([01]\d)\.(\d\d)/ ) {
# datum contains date
$quoter
->store_date( \
%info
,
$fund
,
{
day
=> $1,
month
=> $2,
year
=> $3 } );
$info
{
$fund
,
"time"
} =
$quoter
->isoTime(
"18:00"
);
}
elsif
(
$datum
=~ /([012]\d:[0-5]\d:[0-5]\d)/ ) {
#datum contains time
$quoter
->store_date( \
%info
,
$fund
);
$info
{
$fund
,
"time"
} =
$quoter
->isoTime($1);
}
my
$kurs
=
$table
->cell( 0, 2 );
next
if
not
$kurs
;
$info
{
$fund
,
"price"
} =
$info
{
$fund
,
"last"
} = trimtr(
$kurs
);
# Currency
my
$portrait
=
$tree
->look_down(
"_tag"
,
"table"
,
"class"
,
"portraitKurse"
);
if
(
$portrait
) {
my
@tds
=
$portrait
->find(
'td'
);
$info
{
$fund
,
"currency"
} =
$tds
[2]->as_trimmed_text();
}
else
{
$info
{
$fund
,
"currency"
} =
"EUR"
;
}
my
$wpinfo
=
$wpkurs
->look_down(
"_tag"
,
"h2"
);
if
(
$wpinfo
) {
if
(
$logging
) {
LOG
"wpinfo: "
.
$wpinfo
->as_trimmed_text .
"\n"
;
}
if
(
$wpinfo
->as_trimmed_text =~ /Symbol:([^ ]*)$/ ) {
$info
{
$fund
,
"symbol"
} = trim($1);
}
}
# fund ok
$info
{
$fund
,
"success"
} = 1;
$info
{
$fund
,
"errormsg"
} =
""
;
# log
if
(
$logging
) {
LOG
join
(
':'
,
$info
{
$fund
,
"name"
},
$info
{
$fund
,
"symbol"
},
$info
{
$fund
,
"date"
},
$info
{
$fund
,
"time"
},
$info
{
$fund
,
"price"
},
$info
{
$fund
,
"currency"
} );
LOG
"\n"
;
}
$tree
->
delete
;
}
else
{
$info
{
$fund
,
"success"
} = 0;
$info
{
$fund
,
"errormsg"
} =
"HTTP error "
.
$response
->status_line;
if
(
$logging
) {
LOG
"ERROR $fund: "
.
$info
{
$fund
,
"errormsg"
} .
"\n"
;
}
if
(
$response
->code == 503 &&
$max_retry
-- > 0 ) {
# The server limits the number of request per time and client
sleep
5;
redo
;
}
}
}
if
(
$logging
) {
close
LOG;
}
return
wantarray
() ?
%info
: \
%info
;
}
1;
=head1 NAME
Finance::Quote::VWD - Obtain quotes from vwd Vereinigte Wirtschaftsdienste GmbH.
=head1 SYNOPSIS
use Finance::Quote;
$q = Finance::Quote->new;
%stockinfo = $q->fetch("vwd","847402");
=head1 DESCRIPTION
This module obtains information from vwd Vereinigte Wirtschaftsdienste GmbH
http://www.vwd.de/. Many european stocks and funds are available, but
at the moment only funds are supported.
Information returned by this module is governed by vwd's terms
and conditions.
=head1 LABELS RETURNED
The following labels may be returned by Finance::Quote::vwd:
currency date isodate name price last symbol time.
=head1 SEE ALSO
vwd Vereinigte Wirtschaftsdienste GmbH, http://www.vwd.de/
=cut