「sub」を含む日記 RSS

はてなキーワード: subとは

2007-09-02

[][][Web::Scraper][API][JSON][JavaScript]Web::Scraperを使ってみたくてニフティクリップJSONを作ってみた

最近perl勉強してて、naoyaのはてなダイアリー - Web::ScraperWeb::Scraperを知り、試しにはてブのAPIを真似してニフティクリップコメントを吐くJSONを作った。

#!/usr/local/bin/perl -T
#
#
use strict;
use warnings;

use URI;
use Web::Scraper;
use JSON::XS;
use CGI;
use Encode;

my $q = new CGI;
print $q->header( -type=>'text/plain', -charset=>'UTF-8');

my $path_info = $q->path_info;
my $path = $path_info =~ m{^/?(nobracket/)?(http\w?)://?(.*)$}xms ? $2.'://'.$3
         :                                                          undef
         ;
exit if ! $path;
my $is_nobracket = 'true' if $1;

if ($q->query_string) {
    my $query_string = $q->query_string;
    $query_string =~ s/;/&/g;
    $path = $path.'?'.$query_string
}

$path =~ s/%23/#/;

$path =~ s/([^\w ])/'%' . unpack('H2', $1)/eg;
$path =~ tr/ /+/;

my $entry_url = "http://clip.nifty.com/entry/?url=" . $path;

my $bookmarks = scraper {
    process 'h4>a', 'user' => 'TEXT';
    process 'li.dateAndTime', 'timestamp' => 'TEXT';
    process 'a.tagtag', 'tags[]' => sub {
        my $text = $_->as_text or return;
        my $left = decode_utf8('??~P');
        my $right = decode_utf8('??~Q');
        return $text =~ /$left (.*?) $right/xms;
    };
    process 'p.comment', 'comment' => 'TEXT';
    result 'user', 'timestamp', 'tags', 'comment';
};

my $niftyclip_entry_info = scraper {
    process 'div.clipTitle>h3>a', 'title' => 'TEXT';
    process 'div.clipTitle>p.url>a', 'url' => '@href';
    process 'div.comments>div.commentsDetails',
        'bookmarks[]' => $bookmarks;
    result 'title','url','bookmarks';
};

my $niftyclip = scraper {
    process 'div#content',
        'niftyclip_entry' => $niftyclip_entry_info;
    result 'niftyclip_entry';
}->scrape(URI->new($entry_url));

exit if ! ($niftyclip->{'url'});

$niftyclip->{'entry_url'} = $entry_url;
$niftyclip->{'count'} = @{$niftyclip->{'bookmarks'}};

my $json = JSON::XS->new->utf8->encode($niftyclip);

$json = '('. $json. ')' if ! $is_nobracket;
print $json;

取得方法は

http://monm.on.coocan.jp/niftyclip/json/entry/<取得したいURL

ってすればいい。「#」は「%23」にエスケープしないとダメ

ニフティクリップのトップならこんな感じ

作りながら「取得したいURLURLエンコードするのは面倒だな」って思い、はてブAPIみたいにpath_infoでアクセスできるようにしたわけだけど、その取得したいURLquery_stringが付いてた場合にどうやってやって良いかわからず結構悩んだ。

結局、path_info+'&'+query_stringってやることで無理やり作ったけど、普通どうやるもんなんだろ?cpanに何か良いモジュールがあったりするのかな。

それと、はてブに合わせて出力の際に()を付けるようにしたけど、これだとYahoo!Pipesで使えなかったから、

http://monm.on.coocan.jp/niftyclip/json/entry/nobracket/<取得したいURL

みたいに「nobracket」付きでアクセスした場合には()を付けないようにした。

コレ使うとニフティクリップとlivedoor クリプのコメント取ってくるAPIみたいなのが作れる。

RSSで取得する場合は

http://pipes.yahoo.com/pipes/pipe.run?_id=zECBJ_VY3BGtBw6B8ivLAg&_render=rss&URL=URLエンコードしたURL

で取得できるし、jsonで取得する場合は

http://pipes.yahoo.com/pipes/pipe.run?_id=zECBJ_VY3BGtBw6B8ivLAg&_render=json&URL=URLエンコードしたURL

ってなる。

こんな感じ

とりあえずサクッと作ってみたけど、わざわざページからJSON作ってるからちょっと重い。

デザインリニューアルされたら使えなくなるし。

その頃にはJSON吐いてくれるようになるんじゃないかなと期待はしてるけど。

参考URL:

http://d.hatena.ne.jp/naoya/20070509/1178686816

http://d.hatena.ne.jp/keyword/%A4%CF%A4%C6%A4%CA%A5%D6%A5%C3%A5%AF%A5%DE%A1%BC%A5%AF%A5%A8%A5%F3%A5%C8%A5%EA%A1%BC%BE%F0%CA%F3%BC%E8%C6%C0API?kid=184075

2007-08-22

http://anond.hatelabo.jp/20070822165701

@data=(a,b,c);print@data
#!/usr/bin/perl
use strict;
my @data = qw(a b c);

my $cx = scalar @data;
my $si = 0;
my $ax;
LOOP:
    $ax = $data[$si];
    print $ax;
    $si++;
not --$cx or goto LOOP;
#!/usr/bin/perl
use strict;
my @data = qw(a b c);

package AtoH;
use base qw(Tie::Handle);
sub TIEHANDLE {
    my $class = shift;
    return bless {data => [@_]}, $class;
}
sub READLINE {
    return shift @{shift->{data}};
}

package main;
tie *ARGV, 'AtoH', @data;
while (<>) {
    print;
}

http://anond.hatelabo.jp/20070822162530

まずは最短コース。(use strict;なんて使っちゃだめよ)

@data = qw(a b c);print(@data);

次にややこしいコース

#!/usr/bin/perl
use strict;
my @data = qw(a b c);
sub nextMember(@) {
    my $datum = shift(@_);
    if($datum){
        print($datum);
        nextMember(@_);
    }
    return;
}
nextMember(@data);

dataは複数形だから、datasなんて認めないぞ僕は。

、、、ここまで書いてから、元増田の「ループして」って条件を忘れていることに気がついたorz

2007-08-21

X-REPROXY-CACHE-CLEAR もあわせて使いたい人向けショート BK

■X-Reproxy-Cache-Clear できる Perlbal プラグインCommentsAdd Star

■[Perl][CPAN][Perlbal] X-REPROXY-CACHE-FORを使いたい人向けショートBK

X-REPROXY-CACHE-FOR ヘッダが Perlbal に(というか Perlbal::Cache に)どのように解釈されるかというと、

Perlbal::Service.pm

1467 sub add_to_reproxy_url_cache {

1468 my Perlbal::Service $self;

1469 my ($reqhd, $reshd);

1470

1471 ($self, $reqhd, $reshd) = @_;

1472

(snip)

1484 my $hostname = $reqhd->header("Host") || '';

1485 my $requri = $reqhd->request_uri || '';

1486 my $key = "$hostname|$requri";

1487

(snip)

1496 $cache->set($key, [$timeout, \@headers, $urls]);

1497 }

こうなってる。ここで、

Perlbal -> mod_perl -> MogileFS

こんな風に、フロントPerlbal, バックエンドに mod_perl ハンドラでも置いて、その裏の MogileFSやりとり(をあんまさせたくないので Perlbal に直にキャッシュさせたい)という構成を考える。

この場合、

つまり、

X-REPROXY-CACHE-CLEAR: /artwork/12345

というヘッダを mod_perl から Perlbal に返す必要がある(host は補われる)

この /artwork/12345 というリクエスト URL は、 mod_perl 側から直に参照できない。

mod_perl ハンドラを例えば以下のような conf であてていたとすると、

<Location /example/artwork>

SetHandler perl-script

PerlHandler Example::Artwork

</Location>

RewriteEngine On

RewriteRule ^/artwork/(.*) http://127.0.0.1:8080/example/artwork/$1 [P,L]

ここで $r->uri をとると /example/artwork/12345 となり、これをそのまま X-REPROXY-CACHE-CLEAR で返しても Perlbal::Cacheキャッシュした key とは違うものなのでキャッシュを破棄できない。自前で $r->uri を split なりして、 /artwork/12345 を、 Rewrite される前の URL を知る必要がある。当然、どんな RewriteRule かに依存するので一般的な実装はあげられない。 Rewrite しなければもう少し話が簡単になる。

要は、

と、それぞれ意味の違った URL (key になるもの)がいくつか存在して、どれがどれやらわからなくなってしまうので、ハマりどころが多い。ありがちな(というか俺がやった)ミスとしては、 CACHE-FOR でキャッシュした状態で MogileFS からファイル実体を消してしまうと (mogile に突っ込むときkey はまた別に digest とかで作ってあったりすると余計に混乱することうけあい) Mogile にはもう存在せず、したがって mod_perl にはどうしたって知りようがない URLPerlbalキャッシュしていて 503 を返しつづける、という状態になってしまう。それから、キャッシュを自発的に消したいときというのはもともとキャッシュしてた URL (Mogile 上でのファイルのありか)が指し示すファイル実体を消したいときなので(実体がないものをいつまでもキャッシュしているのは困る、という理由)当然実体そのものも消すわけだが、

こういう手順でつくらないといけない。この URLACL を厳重にしておかないと、全ての artwork に対応するキャッシュ破棄用(つまりファイル削除用) URL を GET されまくってファイルを消されまくってしまうので非常にまずい。

我ながら乱雑で要領を得ない文章だと思うけど、こんなものでもないよりはあったほうがこれから同じことをやろうとする人にとっては多少の助けになると思うので走り書きのままで公開する。こういう、どっかに一言書いてあれば5秒でぐぐって済むことを何時間もかけてやり直すのは人類にとっての時間的損失でばからしいので、適当に間違ってるところとかを修正しつついろんなブログとかに転載しまくって世に広めてください。

2007-05-11

fizzbuzz.com

http://anond.hatelabo.jp/20070508170219 こいつをアセンブラで書こうとしていたが、

すでに

http://anond.hatelabo.jp/20070510170511 にそれっぽいものが書かれていた。

しかしデクリメントした直後に判定するならフラグですむがそうじゃないときtest命令入れないといけないのでうまくいかんと思った。

とりあえず8086アセンブラで書いてみたが長くなったので実行ファイル(fizzbuzz.com)をBase64で下に書いておくよ。

~) ls -al fizzbuzz.com
-a--rwx       98 May 11 03:28 fizzbuzz.com*

~) base64 < fizzbuzz.com
uwUDuQoJvl0B/s91ErcD/st1BrpSAesOkLpLAesWkP7LdQi6VgGzBesKkLg6OivBiQSL1rQJzSH+
zXXNtQr+yXXHulYBzSG0TM0hRml6eg0KJEZpenpCdXp6DQokVU0NCiQ=

数字の表示の処理で10で割った余りを使っていたのでまずいと思って修正した。ついでに98バイトまで縮めてみた。

こんなことに時間を使っている俺はバカだ。

ソースも載せとこう。8086なんてほとんど初めてに等しいので汚いだろうけど。


CODE	SEGMENT
	ASSUME	CS:CODE,DS:CODE
	ORG 100H
START:
	mov bx, 0305h
	mov cx, 090Ah
	mov si, OFFSET NUM
LOOP:
	dec bh
	jnz skip1
; 3の倍数だった
	mov bh, 3
	dec bl
	jnz skip2
; 3の倍数で5の倍数だった
	mov dx, OFFSET FIZZBUZZ
	jmp loop5
skip2:
; 3の倍数で5の倍数じゃなかった
	mov dx, OFFSET FIZZ
	jmp loopend
skip1:	
; 3の倍数じゃないとき
	dec bl
	jnz skip3
; 3の倍数じゃなくて5の倍数だった
	mov dx, OFFSET BUZZ
loop5:	mov bl, 5
	jmp loopend
skip3:	
; 3の倍数じゃなくて5の倍数でもなかった
; 数字を表示する。2桁でいい
	mov ax, 3A3Ah
	sub ax, cx
	mov [si],ax
	mov dx, si
	
loopend:
	mov ah,9
	int 21h

	dec ch
	jne loop
	mov ch,10
	dec cl
	jne loop

; 最後のBuzzを表示する
	mov dx, OFFSET BUZZ
	int 21h

	mov ax, 4c00H
	int 21h

	
FIZZ:		DB	'Fizz', 0dh, 0ah, '$'
FIZZBUZZ:	DB	'Fizz'
BUZZ:		DB	'Buzz', 0dh, 0ah, '$'
NUM:		DB	'UM', 0dh, 0ah, '$'
CODE	ENDS

	END START

ループ

http://anond.hatelabo.jp/20070510170511

皆素直に繰り返しの構文で1から100まで回してんのね(違うのがあったら面白いかなと思った)。

そうか、せっかくExcelなんだからループいらないじゃん。

てことでhttp://anond.hatelabo.jp/20070509233601を改造。

Public Sub FizzBuzz2()
        Range("A1:A100").Formula = _
        "=IF(INT(ROW()/3)*3=ROW()*1,IF(INT(ROW()/5)*5=ROW()*1,""FizzBuzz"",""Fizz""),IF(INT(ROW()/5)*5=ROW()*1,""Buzz"",ROW()))"
End Sub

まあ内部的にはループしてるんだろうけど、そこはそれ。

剰余不可より100回ループ不可、てほうが制限としては面白いかもね。

2007-05-09

[]無理矢理ExcelVBAで参戦

http://anond.hatelabo.jp/20070508170219

Public Sub FizzBuzz()
    Dim i As Integer
    Dim cc As Range
    For i = 1 To 100
        Set cc = Cells(i, 1)
        cc.FormulaR1C1 = _
        "=IF(INT(ROW()/3)*3=ROW()*1,IF(INT(ROW()/5)*5=ROW()*1,""FizzBuzz"",""Fizz""),IF(INT(ROW()/5)*5=ROW()*1,""Buzz"",ROW()))"
    Next i
    Set cc = Nothing
End Sub

printはワークシート上に。

個人的にはもっと変わり種が見てみたい。冴子先生にFizzBuzzしゃべらせてみるとか。

ログイン ユーザー登録
ようこそ ゲスト さん