Skip to content

Instantly share code, notes, and snippets.

@punytan
Last active April 1, 2016 10:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save punytan/4017e8aff64126ffe7ac to your computer and use it in GitHub Desktop.
Save punytan/4017e8aff64126ffe7ac to your computer and use it in GitHub Desktop.
use strict;
use warnings;
use utf8;
package Weather;
use DateTime;
use Web::Scraper;
use URI;
our $AREA = {
千代田区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13101.html',
中央区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13102.html',
港区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13103.html',
新宿区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13104.html',
文京区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13105.html',
台東区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13106.html',
墨田区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13107.html',
江戸川区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13108.html',
品川区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13109.html',
目黒区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13110.html',
大田区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13111.html',
世田谷区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13112.html',
渋谷区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13113.html',
中野区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13114.html',
杉並区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13115.html',
豊島区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13116.html',
北区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13117.html',
荒川区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13118.html',
板橋区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13119.html',
練馬区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13120.html',
足立区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13121.html',
葛飾区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13122.html',
江戸川区 => 'http://weather.yahoo.co.jp/weather/jp/13/4410/13123.html',
};
sub get_yahoo_weather {
my $area = shift;
my $scraper = scraper {
process "div#yjw_pinpoint_today", today => scraper {
process h3 => "date" => "TEXT";
process "table", "rows[]" => scraper {
process "tr:nth-child(1) td" => "time[]" => "TEXT";
process "tr:nth-child(2) td" => "weather[]" => scraper {
process "img" => img => '@src';
process "small" => text => 'TEXT';
};
process "tr:nth-child(3) td" => "temperature[]" => "TEXT";
process "tr:nth-child(4) td" => "humidity[]" => "TEXT";
process "tr:nth-child(5) td" => "rainfall_precipitation[]" => "TEXT";
process "tr:nth-child(6) td" => "wind_direction[]" => "TEXT";
};
};
process "div#yjw_pinpoint_tomorrow", tomorrow => scraper {
process h3 => "date" => "TEXT";
process "table", "rows[]" => scraper {
process "tr:nth-child(1) td" => "time[]" => "TEXT";
process "tr:nth-child(2) td" => "weather[]" => scraper {
process "img" => img => '@src';
process "small" => text => 'TEXT';
};
process "tr:nth-child(3) td" => "temperature[]" => "TEXT";
process "tr:nth-child(4) td" => "humidity[]" => "TEXT";
process "tr:nth-child(5) td" => "rainfall_precipitation[]" => "TEXT";
process "tr:nth-child(6) td" => "wind_direction[]" => "TEXT";
};
};
process "div#yjw_week", week => scraper {
process h2 => "date" => "TEXT";
process "table.yjw_table", "rows[]" => scraper {
process "tr:nth-child(1) td" => "dates[]" => "TEXT";
process "tr:nth-child(2) td" => "weather[]" => scraper {
process "img" => img => '@src';
process "small" => text => 'TEXT';
};
process "tr:nth-child(3) td" => "temperature[]" => scraper {
process "small" => label => "TEXT";
process "font" => "highlow[]" => "TEXT";
process "font:nth-child(2)" => low => "TEXT";
};
process "tr:nth-child(4) td" => "rainfall_ratio[]" => "TEXT";
};
process "table.yjw_table tr:nth-child(2)", "weather[]" => scraper {
process td => "columns[]" => "TEXT"
};
};
};
$scraper->scrape(URI->new($AREA->{$area}));
}
sub get_amesh_time {
my $now = DateTime->now(time_zone => "Asia/Tokyo");
my $current = join "",
$now->ymd(""),
map { sprintf "%02d", $_ } $now->hour, $now->minute;
$current - ($now->minute % 5)
}
package main;
use Plack::Request;
use Text::Xslate;
use Data::Section::Simple 'get_data_section';
use Encode;
my $xslate = Text::Xslate->new;
sub {
my $req = Plack::Request->new(shift);
my $area = decode_utf8([split /\//, $req->path_info]->[-1] // '');
if ($AREA->{$area}) {
my $body = $xslate->render_string(get_data_section('template.tt'), {
amesh_time => Weather::get_amesh_time,
yahoo_weather => Weather::get_yahoo_weather($area || '千代田区'),
});
return do {
my $res = $req->new_response(200);
$res->body(encode_utf8 $body);
$res->finalize;
};
} else {
my $body = $xslate->render_string(get_data_section('list.tt'), { areas => [ keys %$AREA ] });
return do {
my $res = $req->new_response(404);
$res->body(encode_utf8 $body);
$res->finalize;
};
}
}
__DATA__
@@ list.tt
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="300">
<style>
body { width: 100%; margin-top: 0; margin-bottom: 0; line-height: 1em; }
</style>
</head>
<body>
<ul>
: for $areas -> $key {
<li><a href="/<:$key:>"><: $key :></a>
: }
</ul>
</body>
</html>
@@ template.tt
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="300">
<style>
body { width: 100%; margin-top: 0; margin-bottom: 0; line-height: 1em; }
</style>
<style>
div#yahoo-weather { width: 770px; margin:0 auto; }
div#yahoo-weather table { width: 100%; }
div#yahoo-weather table td { text-align: center; font-size: small; vertical-align: middle; }
div#yahoo-weather table td.foo { background-color: #efefef; }
</style>
<style>
div#amesh { width: 770px; height: 480px; margin: 0 auto; }
div#amesh img { width: 770px; height: 480px; display: block; }
div#amesh img#background-map { position: absolute; }
div#amesh img#rainfall-mesh { position: absolute; }
div#amesh img#foreground-map { position: absolute; }
</style>
</head>
<body>
<div id="yahoo-weather">
<table>
<tr>
<td colspan="9" class="foo"><: $yahoo_weather.today.date :></td>
</tr>
: for $yahoo_weather.today.rows -> $row {
<tr>
: for $row.time -> $col {
<td><: $col :></td>
: }
</tr>
<tr>
: for $row.weather -> $col {
<td><: if $col.img { :><img src="<: $col.img :>"><br><: } else { :>
<: $col.text :>
: }
</td>
: }
</tr>
<tr>
: for $row.temperature -> $col {
<td><: $col :></td>
: }
</tr>
<tr>
: for $row.humidity -> $col {
<td><: $col :></td>
: }
</tr>
<tr>
: for $row.rainfall_precipitation -> $col {
<td><: $col :></td>
: }
</tr>
<tr>
: for $row.wind_direction -> $col {
<td><: $col :></td>
: }
</tr>
: }
<tr>
<td colspan="9" class="foo"><: $yahoo_weather.tomorrow.date :></td>
</tr>
: for $yahoo_weather.tomorrow.rows -> $row {
<tr>
: for $row.time -> $col {
<td><: $col :></td>
: }
</tr>
<tr>
: for $row.weather -> $col {
<td><: if $col.img { :><img src="<: $col.img :>"><br><: } else { :>
<: $col.text :>
: }
</td>
: }
</tr>
<tr>
: for $row.temperature -> $col {
<td><: $col :></td>
: }
</tr>
<tr>
: for $row.humidity -> $col {
<td><: $col :></td>
: }
</tr>
<tr>
: for $row.rainfall_precipitation -> $col {
<td><: $col :></td>
: }
</tr>
<tr>
: for $row.wind_direction -> $col {
<td><: $col :></td>
: }
</tr>
: }
</table>
<table>
<tr>
<td colspan="7" class="foo"><: $yahoo_weather.week.date :></td>
</tr>
: for $yahoo_weather.week.rows -> $row {
<tr>
: for $row.dates -> $col {
<td><: $col :></td>
: }
</tr>
<tr>
: for $row.weather -> $col {
<td><: if $col.img { :><img src="<: $col.img :>"><: } else { :>
<: $col.text :>
: }
</td>
: }
</tr>
<tr>
: for $row.temperature -> $col {
: if $col.highlow {
<td><: $col.highlow[0] :> / <: $col.highlow[1] :></td>
: } else {
<td>
<div><: $col.label :><div>
</td>
: }
: }
</tr>
: for [ "rainfall_ratio"] -> $key {
<tr>
: for $row[$key] -> $col {
<td><: $col :></td>
: }
</tr>
: }
: }
</table>
</div>
<div id="amesh">
<img id="background-map" src="http://tokyo-ame.jwa.or.jp/map/map000.jpg">
<img id="rainfall-mesh" src="http://tokyo-ame.jwa.or.jp/mesh/000/<: $amesh_time :>.gif" >
<img id="foreground-map" src="http://tokyo-ame.jwa.or.jp/map/msk000.png">
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment