Markdown-Pod
view release on metacpan or search on metacpan
t/mkd/2011-12-12.mkd view on Meta::CPAN
ë¤ìì `manaba.yml` ì¤ì íì¼ìì ê´ë¦¬íë `webtoon` í목ì ë´ì© ì¤ ì¼ë¶ì
ëë¤.
#!yaml
webtoon:
dieter:
name: ë¤ì´ì´í°
site: daum
code: 10362
image: http://i1.cartoon.daumcdn.net/svc/image/U03/cartoon/U620854C4D5B251707
noblesse:
name: ë
¸ë¸ë ì¤
site: naver
code: 25455
image: http://imgcomic.naver.com/webtoon/25455/thumbnail/title_thumbnail_20100614120245_t125x101.jpg
kudu:
name: 구ë
site: nate
code: 31337
image: http://crayondata.cyworld.com/upload/series/31337_m.gif
ì´ì ë¤ìê³¼ ë¤ì´ë², ë¤ì´í¸ ì¹í°ì´ë¼ë©´ ì¼ë§ë ì§ ê´ë¦¬íê³ (ë³´ê³ ?)
ì¶ì ë§í¼ ì¤ì íì¼ì ì¶ê°íë©´ ë©ëë¤.
ê°ê°ì ë§íë ìì ë§ì ê³ ì ID íë¶ì `name`, `site`, `code`, `image` í목ì ê°ì§ëë¤.
`site`ì `code` ë¶ë¶ì ì ííê² ê¸°ì
í´ì¼ì§ë§ Manabaê° ì ëë¡
ì²ë¦¬ë¥¼ í´ì¤ ì ììµëë¤. `name`ê³¼ `image`ë íë©´ì ë³´ì´ê¸° ìí
ë¶ë¶ì¼ë¡ ì못 ì
ë ¥íë¤ê³ í´ë ì¤íì 문ì ë ìì§ë§ ì¹í° ì´ë¦ì´
ì ëë¡ ë³´ì´ì§ ìëë¤ëê° ëë ì¹í° ëí ì´ë¯¸ì§ê° ì ëë¡ ë³´ì´ì§ ìë
문ì ê° ìì ì ììµëë¤.
ì¤ì íì¼ ìì²´ê° ê°ê²°í ë§í¼ í¹ë³í ì¤ëª
ì´ ë íìí ê² ê°ì§ë ììµëë¤.
ìì±í `manaba.yml` ì¤ì íì¼ì ì½ì´ ë¤ì´ë ¤ë©´
[CPANì YAML::Tiny 모ë][cpan-yaml-tiny]ì ì¬ì©í©ëë¤.
#!perl
sub load_manaba {
my $yaml = YAML::Tiny->read( config->{manaba} );
$CONFIG = $yaml->[0];
}
ë§êµ¬ ê¸ì´ì¤ê¸°!
---------------
ì¹ íì´ì§ì ì 보를 ê¸ì´ì¬ ì ìë ë¼ì´ë¸ë¬ë¦¬ë Perl 모ëì ë¬´ì² ë§ìµëë¤.
íì§ë§ ì¹ í¬íì ê²½ì° ëìì¸ê³¼ HTML êµ¬ì¡°ê° ììë¡ ë³í기 ë문ì
ê°ë¥íë©´ ìì½ê² ìíë HTML ììì ê°ì ì¶ì¶í ì ìë ë°©ë²ì ì¬ì©íë ê²ì´ ì 리í©ëë¤.
[CPANì Web::Scraper 모ë][cpan-web-scraper]ì ì´ì©íë©´ CSS ì
ë í° ë°©ìì´ë
XPath ë°©ìì ì´ì©í´ì HTML í¹ì ìì를 ì½ê² ì°¾ì ì ììµëë¤.
ì ê· ííìì ì´ì©íë ê²ë³´ë¤ë ìëì ì¼ë¡ ë§ì´ ë리ì§ë§
ì¬ì´í¸ì ë³íì ë°ë¼ ë°ë¹ ë¥´ê² ëìí ì ìë¤ë ê²ì´ ë§¤ë ¥ì
ëë¤.
ëí ì¹ì ê¸ì´ì¬ ë ì¼ë¶ë¬ í´ë¹ ì¬ì´í¸ì ê³¼ë¶í를 ì£¼ì§ ì기 ìí´
ì§ì° ìê°ì 주기ë(`sleep $time`) íëë° `Web::Scraper`ì ìë ìì²´ê°
ë리기 ë문ì ì무ëë ê¸ë ì
ì¥ììë ì½ê°ì ì§ì°ì´ ë°ìíë¯ë¡
ì¡°ê¸ ìì¬ëë ë©´ë ììµëë¤.
ê°ê°ì í¬í ì¬ì´í¸ ë³ë¡ `Web::Scraper` 모ëì ì´ì©í´ì íì´ì§ë¥¼ ê¸ì í
íì°¨ ê´ë ¨ ì 보를 ì¶ì¶íëë¡ í©ëë¤.
ë¤ì´í¸ ì¹í°ì ëí´ ì²ë¦¬íë ì½ëë ë¤ìê³¼ ê°ìµëë¤.
#!perl
sub update_nate_link {
my ( $id, @links ) = @_;
...
my @chapters = sort {
my $page_no_a = 0;
my $page_no_b = 0;
$page_no_a = $1 if $a =~ m/^(\d+)$/;
$page_no_b = $1 if $b =~ m/^(\d+)$/;
$page_no_a <=> $page_no_b;
} map {
m{viewer/(\d+)$};
} @links;
...
}
ë¤ì´ë² ì¹í°ê³¼ ë¤ì ì¹í°ë 기본ì ì¸ íìì ë¹ì·íì§ë§,
`map`ì ì´ì©í´ì ë§í¬ 주ììì íì°¨ ì 보를 ê¸ì´ì¤ë
ì ê·ííì ë¶ë¶ë§ ì¡°ê¸ì© ë¤ë¦
ëë¤.
Let's Dance!
-------------
ìíë ì¹í°ì 첫 주ìë, ìµì 주ìë ììê³
ì´ì ë¨ì ê²ì íë©´ì ë¿ë ¤ì£¼ê¸°ë§ íë©´ ë©ëë¤.
ì무ëë ê°ë¨íê² ë§ë¤ ëë ì¹ ì´í리ì¼ì´ì
ì¼ë¡ ë§ëë ê²ì´
UI를 ìì íë¤ê±°ë Perlê³¼ ì°ëí기ë ì¢ì ê² ê°ìµëë¤.
ê·¸ë ë¤ë©´ Perlì ë§ì´í¬ë¡ ì¹ íë ììí¬ì¸
[Dancer][dancer-home]를 ì¬ì©í´ì UI 구íì ë§ë¬´ë¦¬íì£ .
컨í¸ë¡¤ë¬ë ë¨ ë ê°ë§ ë§ë¤ê² ìµëë¤.
기본 íì´ì§ë¥¼ ì미íë `/`, ì¦ ì¸ë±ì¤ì© 컨í¸ë¡¤ë¬ íëì
ê°ì ë¡ ì¬ì©ìê° ë±ë¡í ì¹í°ì ì 보를 ê°±ì (`Web::Scraper`를 ì´ì©í´ì)íë
`update` 컨í¸ë¡¤ë¬ë¥¼ ìì±í©ëë¤.
- /
- /update/:id?
`/` 컨í¸ë¡¤ë¬ë ë·° ë¨ì ë겨주기 ìí ë°ì´í°ë¥¼ ìì±í기 ìí ì²ë¦¬ë¥¼ ìíí©ëë¤.
#!perl
get '/' => sub {
my $webtoon = $CONFIG->{webtoon};
my @items = map {
my $item = $webtoon->{$_};
$item->{id} = $_;
$item->{first} = q{} unless $item->{first};
$item->{last} = q{} unless $item->{last};
$item;
} sort keys %$webtoon;
my $ptr = 0;
my @rows;
while ( $items[$ptr] ) {
my @cols;
for my $i ( 0 .. 9 ) {
last unless $items[$ptr];
push @cols, $items[$ptr];
++$ptr;
}
push @rows, \@cols;
}
template 'index' => {
rows => \@rows,
};
};
`update` 컨í¸ë¡¤ë¬ë `id`를 ë°ìì í¹ì íì°¨ë§ ê°±ì í ìë ìê³
`id`를 ëê²¨ì£¼ì§ ìë ê²½ì° ëª¨ë ì¹í°ì íì°¨ ì 보를 ê°±ì í©ëë¤.
#!perl
get '/update/:id?' => sub {
my $id = param('id');
if ($id) {
update($id);
}
else {
update_all();
}
redirect '/';
};
ì¹í°ì ì 보를 ê¸ì´ì¤ë í¨ìë `update_all()`ê³¼ `update()` í¨ìì
ëë¤.
`update_all()` í¨ìë ë´ë¶ì ì¼ë¡ `update()` í¨ì를 í¸ì¶íë¯ë¡
`update()` í¨ì를 ê°ëµíê² ì´í´ë³´ì£ .
#!perl
sub update {
my $id = shift;
return unless $id;
my $webtoon = $CONFIG->{webtoon};
return unless $webtoon;
my $site_name = $webtoon->{$id}{site};
return unless $site_name;
my $scraper = $SCRAPERS->{ $site_name };
return unless $scraper;
my $site = $CONFIG->{site};
return unless $site;
my $start_url = sprintf(
$site->{ $site_name }{ 'start_url' },
$webtoon->{$id}{ 'code' },
);
my $items = $scraper->scrape( URI->new( $start_url ) )->{items};
my @links = map { $_->{link} } @$items;
given ( $site_name ) {
update_daum_link($id, @links) when 'daum';
update_naver_link($id, @links) when 'naver';
update_nate_link($id, @links) when 'nate';
}
}
`update()` í¨ìë ë¤ì ê°ê°ì ì¬ì´í¸ ë³ë¡ ì¹í°ì ì²ë¦¬í기 ìí í¨ìë¡ ì´ëí©ëë¤.
ê°ê°ì í¨ìììë ììì ë³´ìë `Web::Scraper` 모ëì ì´ì©í´ì
ìíë ì¹í° íì°¨ ì 보를 ì¶ì¶í©ëë¤.
`Web::Scraper`를 ì¬ì©í기 ë문ì ì ì íê² ì§ì° ìê°ì ì£¼ì§ ìì¼ë©´
í¬í ì¬ì´í¸ë¡ë¶í° ì¬ì©íë ìì´í¼ê° ë¸ë¡ ë¹í ì ìì¼ë¯ë¡ 주ìíëë¡ í©ëë¤.
íìíë¤ë©´ `update_all()` ëë `update()` í¨ìì
`sleep $time` ì²ë¼ ì§ì° ìê°ì ì ì íê² ì£¼ëë¡ í©ëë¤.
íì¬ êµ¬íì Manabaê° ìµì´ì Dancer ì¹ ì´í리ì¼ì´ì
ì¼ë¡ ì¤íë ë
모ë ì¹í°ì ì 보를 ê¸ì´ìµëë¤.
ì¹í°ì ìì´ ë§ì¼ë©´ ë§ììë¡ ì 보를 ê¸ì´ì¤ëë° ëë ë¹ì©ì´ 커ì§ë¯ë¡
íì´ì§ê° ê°±ì ë ëë§ë¤ ì 보를 ê°±ì í기 ë³´ë¤ë ê°ê°ì ì¹í° ë³ë¡
ê°±ì í ì ìëë¡ `/update` 컨í¸ë¡¤ë¬ìì `id`를 ì¸ìë¡ ë°ê³ ììì ì ìí´ì£¼ì¸ì.
ë¤ì´ë²ë ê´´ë¡ì...
-------------------
ê±°ì ë¤ ìì
ì´ ëëê° ë¬´ë µ ë¤ì´ë²ì ì¹í° ëí ì´ë¯¸ì§ê° ë³´ì´ì§ ì기 ììíìµëë¤.
(ì´ë°! ìê¹ê¹ì§ë§ í´ë ì ë³´ìëë°!!)
ì¬ë¬ë²ì ê²ì ë° í
ì¤í¸ ê²°ê³¼ ë¤ì´ë²ê° ì ì±
ì ì¼ë¡ ì¸ë¶ 주ììì
ìì ì ì´ë¯¸ì§ë¥¼ ì´ëíë ê²ì ë§ì ëìë¤ë ì¬ì¦ì êµ³íê² ë©ëë¤.
ìë§ë í¸ëí½ì íì¦ì ë§ê¸° ìí ë°©ìì¼ë¡ ìê°ëëë°
êµë´ 1ì ëí í¬íìì ê°ìí ë ìê°ë³´ë¤ *쪼ì§..* ... í ê² ê°ìµëë¤.
IP ë¸ë ë¹íì§ ìì ê²ì´ ë¤íì´êµ°ì...;;;
ê·¸ëì íë¡ê·¸ë¨ ììì ì´ë¯¸ì§ë¥¼ ë°ë¡ ë³´ì¬ì£¼ë ê²ì´ ìëë¼
ë¤ì´ë¡ë ë°ìì ë¡ì»¬ íë ëì¤í¬ì ì ì¥í´ì ë³´ì¬ì£¼ê¸°ë¡ ì ì±
ì ì íí©ëë¤.
( run in 3.222 seconds using v1.01-cache-2.11-cpan-d8267643d1d )