line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package WWW::PTV; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
14463
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
27
|
|
4
|
1
|
|
|
1
|
|
4
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
26
|
|
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
829
|
use LWP; |
|
1
|
|
|
|
|
62529
|
|
|
1
|
|
|
|
|
44
|
|
7
|
1
|
|
|
1
|
|
806
|
use WWW::Mechanize; |
|
1
|
|
|
|
|
112120
|
|
|
1
|
|
|
|
|
33
|
|
8
|
1
|
|
|
1
|
|
731
|
use HTML::TreeBuilder; |
|
1
|
|
|
|
|
16611
|
|
|
1
|
|
|
|
|
9
|
|
9
|
1
|
|
|
1
|
|
36
|
use Carp qw(croak); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
58
|
|
10
|
1
|
|
|
1
|
|
467
|
use WWW::PTV::Area; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
21
|
|
11
|
1
|
|
|
1
|
|
318
|
use WWW::PTV::Stop; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
24
|
|
12
|
1
|
|
|
1
|
|
277
|
use WWW::PTV::Route; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1579
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our $VERSION = '0.06'; |
15
|
|
|
|
|
|
|
our $CACHE; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub __request { |
18
|
0
|
|
|
0
|
|
|
my($self,$uri) = @_; |
19
|
0
|
0
|
|
|
|
|
my $res = ( $uri !~ /^http:/ |
20
|
|
|
|
|
|
|
? $self->{ua}->get( $self->{uri} . $uri ) |
21
|
|
|
|
|
|
|
: $self->{ua}->get( $uri ) ); |
22
|
0
|
0
|
|
|
|
|
$res->is_success and return $res->content; |
23
|
0
|
|
|
|
|
|
croak 'Unable to retrieve content: ' . $res->status_line |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub __tl_request { |
27
|
0
|
|
|
0
|
|
|
my ($self, $tag_id)= @_; |
28
|
0
|
|
0
|
|
|
|
my $r = ( $self->{cache} and $CACHE->{timetables}->{master} |
29
|
|
|
|
|
|
|
? $CACHE->{timetables}->{master} |
30
|
|
|
|
|
|
|
: $self->__request( 'http://ptv.vic.gov.au/timetables' ) ); |
31
|
0
|
0
|
|
|
|
|
$CACHE->{timetables}->{master} = $r if $self->{cache}; |
32
|
0
|
|
|
|
|
|
my $t = HTML::TreeBuilder->new_from_content( $r ); |
33
|
0
|
|
|
|
|
|
$t = $t->look_down( _tag => 'select', id => $tag_id ); |
34
|
0
|
|
|
|
|
|
my @routes = $t->look_down( _tag => 'option' ); |
35
|
0
|
|
|
|
|
|
return my %routes = map { $_->attr( 'value' ) => $_->as_text } grep { $_->attr( 'value' ) ne '' } @routes |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub new { |
39
|
0
|
|
|
0
|
1
|
|
my($class,%args)= @_; |
40
|
0
|
|
|
|
|
|
my $self = bless {}, $class; |
41
|
0
|
0
|
|
|
|
|
$self->{uri} = 'http://' . ( defined $args{uri} ? $args{uri} : 'ptv.vic.gov.au' ) . '/'; |
42
|
0
|
|
|
|
|
|
$self->{ua} = LWP::UserAgent->new; |
43
|
0
|
|
|
|
|
|
$self->{tree} = HTML::TreeBuilder->new; |
44
|
0
|
0
|
|
|
|
|
$self->{cache}++ if $args{cache}; |
45
|
0
|
|
|
|
|
|
return $self |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
0
|
|
|
0
|
1
|
|
sub cache { $_[0]->{cache}++ } |
49
|
|
|
|
|
|
|
|
50
|
0
|
|
|
0
|
1
|
|
sub nocache { $_[0]->{cache} = 0 } |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub get_metropolitan_bus_routes { |
53
|
0
|
|
|
0
|
1
|
|
return $_[0]->__tl_request( 'RouteForm1_RouteUrl' ); |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub get_metropolitan_train_routes { |
57
|
0
|
|
|
0
|
1
|
|
return $_[0]->__tl_request( 'RouteForm2_RouteUrl' ) |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub get_metropolitan_tram_routes { |
61
|
0
|
|
|
0
|
1
|
|
return $_[0]->__tl_request( 'RouteForm3_RouteUrl' ); |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub get_vline_bus_routes { |
65
|
0
|
|
|
0
|
1
|
|
return $_[0]->__tl_request( 'RouteForm4_RouteUrl' ) |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub get_vline_train_routes { |
69
|
0
|
|
|
0
|
1
|
|
return $_[0]->__tl_request( 'RouteForm5_RouteUrl' ) |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub get_regional_bus_routes { |
73
|
0
|
|
|
0
|
1
|
|
return $_[0]->__tl_request( 'RouteForm6_RouteUrl' ) |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub get_route_by_id { |
77
|
0
|
|
|
0
|
1
|
|
my( $self, $id )= @_; |
78
|
0
|
0
|
|
|
|
|
$id or return "Mandatory parameter id not given"; |
79
|
|
|
|
|
|
|
|
80
|
0
|
0
|
0
|
|
|
|
return $CACHE->{ROUTE}->{$id} if ( $self->{cache} and $CACHE->{ROUTE}->{$id} ); |
81
|
|
|
|
|
|
|
|
82
|
0
|
|
|
|
|
|
my $r = $self->__request( "/route/view/$id" ); |
83
|
0
|
|
|
|
|
|
my $t = HTML::TreeBuilder->new_from_content( $r ); |
84
|
|
|
|
|
|
|
#my $t = HTML::TreeBuilder->new_from_file( './metro_train_route_1' ); |
85
|
|
|
|
|
|
|
#my $t = HTML::TreeBuilder->new_from_file( './regional_bus_route_geelong_19' ); |
86
|
0
|
|
|
|
|
|
my %route = (id => $id); |
87
|
0
|
|
|
|
|
|
my $r_link = $t->look_down( _tag => 'div', id => 'content' ); |
88
|
0
|
|
|
|
|
|
$route{name} = $t->look_down( _tag => 'h1' )->as_text; |
89
|
0
|
|
|
|
|
|
( $route{direction_in}, $route{direction_out} ) |
90
|
|
|
|
|
|
|
= $r_link->look_down( _tag => 'a' ); |
91
|
|
|
|
|
|
|
|
92
|
0
|
|
|
|
|
|
( $route{direction_in_link}, $route{direction_out_link} ) |
93
|
0
|
|
|
|
|
|
= map { $_->attr( 'href' ) } $r_link->look_down( _tag => 'a' ); |
94
|
|
|
|
|
|
|
|
95
|
0
|
|
|
|
|
|
( $route{direction_in}, $route{direction_out} ) |
96
|
0
|
|
|
|
|
|
= map { $_->as_text } ( $route{direction_in}, $route{direction_out} ); |
97
|
|
|
|
|
|
|
|
98
|
0
|
|
|
|
|
|
( $route{description_in}, $route{description_out} ) |
99
|
0
|
|
|
|
|
|
= map { $_->as_text } $r_link->look_down( _tag => 'p' ); |
100
|
0
|
|
|
|
|
|
my $operator = $t->look_down( _tag => 'div', class => 'operator' )->as_text; |
101
|
0
|
|
|
|
|
|
$operator =~ s/(Contact|Website|:)/,/g; |
102
|
0
|
|
|
|
|
|
$operator =~ s/\s//g; |
103
|
0
|
|
|
|
|
|
( $route{operator} ,$route{operator_ph} ) = ( split /,/, $operator )[0,2]; |
104
|
0
|
|
|
|
|
|
$route{ua} = $self->{ua}; |
105
|
0
|
|
|
|
|
|
$route{uri} = $self->{uri}; |
106
|
0
|
|
|
|
|
|
my $route = WWW::PTV::Route->new( %route ); |
107
|
0
|
0
|
|
|
|
|
$CACHE->{ROUTE}->{$id} = $route if ( $self->{cache} ); |
108
|
0
|
|
|
|
|
|
return $route |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub get_stop_by_id { |
114
|
0
|
|
|
0
|
1
|
|
my( $self, $id )= @_; |
115
|
0
|
0
|
|
|
|
|
$id or return "Mandatory parameter id not given"; |
116
|
0
|
0
|
0
|
|
|
|
return $CACHE->{STOP}->{$id} if ( $self->{cache} and $CACHE->{STOP}->{$id} ); |
117
|
0
|
|
|
|
|
|
my $r = $self->__request( "/stop/view/$id" ); |
118
|
0
|
|
|
|
|
|
my $t = HTML::TreeBuilder->new_from_content( $r ); |
119
|
|
|
|
|
|
|
#my $t = HTML::TreeBuilder->new_from_file( './45470' ); |
120
|
0
|
|
|
|
|
|
my %stop = (id => $id ); |
121
|
0
|
|
|
|
|
|
my $s_type = $t->look_down( _tag => 'img', class => 'stopModeImage' ); |
122
|
0
|
|
|
|
|
|
$stop{address} = $t->look_down( _tag => 'div', id => 'container' ) |
123
|
|
|
|
|
|
|
->look_down( _tag => 'p' ) |
124
|
|
|
|
|
|
|
->as_text; |
125
|
|
|
|
|
|
|
|
126
|
0
|
|
|
|
|
|
$stop{transport_type} = $s_type->attr('src'); |
127
|
0
|
|
|
|
|
|
$stop{transport_type} =~ s|themes/transport-site/images/jp/icons/icon||; |
128
|
0
|
|
|
|
|
|
$stop{transport_type} =~ s|\.png||; |
129
|
0
|
|
|
|
|
|
( $stop{street}, $stop{locality} ) = ( split /,/, $stop{address} ); |
130
|
0
|
|
|
|
|
|
( $stop{postcode} ) = $stop{locality} =~ /\b(\d{4})\b/; |
131
|
0
|
|
|
|
|
|
$stop{municipiality} = $t->look_down( _tag => 'table', class => 'stationSummary' ) |
132
|
|
|
|
|
|
|
->look_down( _tag => 'a' ) |
133
|
|
|
|
|
|
|
->as_text; |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
( $stop{municipiality_id} ) = $t->look_down( _tag => 'table', class => 'stationSummary' ) |
136
|
|
|
|
|
|
|
->look_down( _tag => 'a' ) |
137
|
|
|
|
|
|
|
->attr( 'href' ); |
138
|
0
|
|
|
|
|
|
( $stop{municipiality_id} ) = $stop{municipiality_id} =~ /\/(\d.*)$/; |
139
|
|
|
|
|
|
|
|
140
|
0
|
|
|
|
|
|
$stop{zone} = ( $t->look_down( _tag => 'table', class => 'stationSummary' ) |
141
|
|
|
|
|
|
|
->look_down( _tag => 'td' ) |
142
|
|
|
|
|
|
|
)[2]->as_text; |
143
|
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
|
$stop{map_ref} = $t->look_down( _tag => 'div', class => 'aside' ) |
145
|
|
|
|
|
|
|
->look_down( _tag => 'a' ) |
146
|
|
|
|
|
|
|
->attr( 'href' ); |
147
|
|
|
|
|
|
|
|
148
|
0
|
|
|
|
|
|
( $stop{latitude} ) = $stop{map_ref} =~ /=(-?\d.*),/; |
149
|
|
|
|
|
|
|
|
150
|
0
|
|
|
|
|
|
( $stop{longitude} ) = $stop{map_ref} =~ /,(-?\d.*)$/; |
151
|
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
|
( $stop{phone_feedback}, $stop{phone_station} ) |
153
|
0
|
|
|
|
|
|
= map { $_->as_text } $t->look_down( _tag => 'div', class => 'expander phone-numbers' ) |
154
|
|
|
|
|
|
|
->look_down( _tag => 'dd' ); |
155
|
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
|
$stop{staff_hours} = $t->look_down( _tag => 'div', 'data-cookie' => 'stop-staff' ) |
157
|
|
|
|
|
|
|
->look_down( _tag => 'dd' )->as_text; |
158
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
( $stop{myki_machines}, $stop{myki_checks}, $stop{vline_bookings} ) |
160
|
0
|
|
|
|
|
|
= map { $_->as_text } $t->look_down( _tag => 'div', 'data-cookie' => 'stop-ticketing' ) |
161
|
|
|
|
|
|
|
->look_down( _tag => 'dd' ); |
162
|
|
|
|
|
|
|
|
163
|
0
|
|
|
|
|
|
( $stop{car_parking}, $stop{_bicycles}, $stop{taxi_rank} ) |
164
|
0
|
|
|
|
|
|
= map { $_->as_text } $t->look_down( _tag => 'div', 'data-cookie' => 'stop-other-transport-links' ) |
165
|
|
|
|
|
|
|
->look_down( _tag => 'dd' ); |
166
|
|
|
|
|
|
|
|
167
|
0
|
|
|
|
|
|
( $stop{bicycle_racks}, $stop{bicycle_lockers}, $stop{bicycle_cage} ) |
168
|
0
|
|
|
|
|
|
= map { s/.*://; $_ } split /,/, $stop{_bicycles}; |
|
0
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
|
170
|
0
|
|
|
|
|
|
( $stop{wheelchair_accessible}, $stop{stairs}, $stop{escalator}, $stop{lift}, $stop{tactile_paths}, $stop{hearing_loop} ) |
171
|
0
|
|
|
|
|
|
= map { $_->as_text } $t->look_down( _tag => 'div', 'data-cookie' => 'stop-accessibility' ) |
172
|
|
|
|
|
|
|
->look_down( _tag => 'dd' ); |
173
|
|
|
|
|
|
|
|
174
|
0
|
|
|
|
|
|
( $stop{seating}, $stop{lighting}, $stop{lockers}, $stop{public_phone}, $stop{public_toilet}, $stop{_waiting_area} ) |
175
|
0
|
|
|
|
|
|
= map { $_->as_text } $t->look_down( _tag => 'div', 'data-cookie' => 'stop-general-facilities' ) |
176
|
|
|
|
|
|
|
->look_down( _tag => 'dd' ); |
177
|
|
|
|
|
|
|
|
178
|
0
|
|
|
|
|
|
( $stop{waiting_area_indoor}, $stop{waiting_area_sheltered} ) |
179
|
0
|
|
|
|
|
|
= map { s/.*://; $_ } split /,/, $stop{_waiting_area}; |
|
0
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
|
181
|
0
|
|
|
|
|
|
foreach my $line ( $t->look_down( _tag => 'div', 'data-cookie' => 'stop-line-timetables' ) |
182
|
|
|
|
|
|
|
->look_down( _tag => 'div', class => 'timetable-row' ) ) { |
183
|
0
|
|
|
|
|
|
my $ref = { id => $line->look_down( _tag => 'a' )->attr( 'href' ) =~ /^.*\/(.*)/ }; |
184
|
0
|
|
|
|
|
|
$ref->{ name } = $line->look_down( _tag => 'a' )->as_text; |
185
|
0
|
|
|
|
|
|
$ref->{ type } = _get_line_type( $line->look_down( _tag => 'img' )->attr( 'src' ) ); |
186
|
0
|
|
|
|
|
|
push @{ $stop{routes} }, $ref |
|
0
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
0
|
|
|
|
|
|
$stop{ua} = $self->{ua}; |
190
|
|
|
|
|
|
|
|
191
|
0
|
|
|
|
|
|
my $stop = WWW::PTV::Stop->new( %stop ); |
192
|
0
|
0
|
|
|
|
|
$CACHE->{STOP}->{$id} = $stop if ( $self->{cache} ); |
193
|
|
|
|
|
|
|
|
194
|
0
|
|
|
|
|
|
return $stop |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
sub get_area_by_id { |
198
|
0
|
|
|
0
|
1
|
|
my( $self, $id )= @_; |
199
|
0
|
0
|
|
|
|
|
$id or return "Mandatory parameter id not given"; |
200
|
0
|
0
|
0
|
|
|
|
return $CACHE->{AREA}->{$id} if ( $self->{cache} and $CACHE->{AREA}->{$id} ); |
201
|
0
|
|
|
|
|
|
my $r = $self->__request( "/location/view/$id" ); |
202
|
0
|
|
|
|
|
|
my $t = HTML::TreeBuilder->new_from_content( $r ); |
203
|
|
|
|
|
|
|
#my $t = HTML::TreeBuilder->new_from_file( './local_area_19' ); |
204
|
|
|
|
|
|
|
#my $t = HTML::TreeBuilder->new_from_file( './area_30' ); |
205
|
0
|
|
|
|
|
|
my %area = ( id => $id ); |
206
|
0
|
|
|
|
|
|
$area{name} = $t->look_down( _tag => 'h1' )->as_text; |
207
|
0
|
|
|
|
|
|
@{ $area{suburbs}} = split /, /, $t->look_down( _tag => 'p' )->as_text; |
|
0
|
|
|
|
|
|
|
208
|
0
|
|
|
|
|
|
my $t_type; |
209
|
|
|
|
|
|
|
|
210
|
0
|
|
|
|
|
|
foreach my $service ( $t->look_down( _tag => 'div', id => 'content' )->look_down( _tag => 'div' ) ) { |
211
|
0
|
|
|
|
|
|
my $type = $service->look_down( _tag => 'h3' ); |
212
|
|
|
|
|
|
|
|
213
|
0
|
0
|
|
|
|
|
if ( $type->as_text ne '' ) { $t_type = $type->as_text } |
|
0
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
|
215
|
0
|
|
|
|
|
|
@{ $area{service}{names}{$t_type} } |
|
0
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
= map { $_->as_text } $service->look_down( _tag => 'li' ); |
217
|
|
|
|
|
|
|
|
218
|
0
|
|
|
|
|
|
@{ $area{service}{links}{$t_type} } |
|
0
|
|
|
|
|
|
|
219
|
0
|
|
|
|
|
|
= map { $_->attr( 'href' ) } $service->look_down( _tag => 'a' ); |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
0
|
|
|
|
|
|
my $area = WWW::PTV::Area->new( %area ); |
223
|
0
|
0
|
|
|
|
|
$CACHE->{AREA}->{$id} = $area if ( $self->{cache} ); |
224
|
|
|
|
|
|
|
|
225
|
0
|
|
|
|
|
|
return $area |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub get_local_areas { |
229
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
230
|
0
|
|
|
|
|
|
my $r = $self->__request( '/getting-around/local-areas/' ); |
231
|
0
|
|
|
|
|
|
my $t = HTML::TreeBuilder->new_from_content( $r ); |
232
|
|
|
|
|
|
|
#my $t = HTML::TreeBuilder->new_from_file( './local_areas_list' ); |
233
|
0
|
|
|
|
|
|
$t = $t->look_down( _tag => 'div', id => 'content' ); |
234
|
|
|
|
|
|
|
|
235
|
0
|
|
|
|
|
|
@{ $self->{local_areas}{names} } |
|
0
|
|
|
|
|
|
|
236
|
0
|
|
|
|
|
|
= map { $_->as_text } $t->look_down( _tag => 'li' ); |
237
|
|
|
|
|
|
|
|
238
|
0
|
|
|
|
|
|
@{ $self->{local_areas}{links} } |
|
0
|
|
|
|
|
|
|
239
|
0
|
|
|
|
|
|
= map { $_->attr( 'href' ) } $t->look_down( _tag => 'a' ); |
240
|
|
|
|
|
|
|
|
241
|
0
|
|
|
|
|
|
my %res; |
242
|
0
|
|
|
|
|
|
@res{ @{ $self->{local_areas}{names} } } = @{ $self->{local_areas}{links} }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
|
return %res |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub _get_line_type { |
247
|
0
|
|
|
0
|
|
|
my $obj = shift; |
248
|
0
|
|
|
|
|
|
$obj =~ s/^.*\/icon//; |
249
|
0
|
|
|
|
|
|
$obj =~ s/\..*$//; |
250
|
0
|
|
|
|
|
|
return lc $obj |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
1; |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
__END__ |