EntryFullTextでCSSセレクターを使う

エントリー書くか、という時になってPlaggerCookbookのレシピに

  • Use XPath and CSS Selector to extract fulltext content
無料でメル友を作る為のサイトplagger

なんて書いてあるのをみつけた。既にあるのかな?だいぶ前に

CSS selector で抽出かけるのは Plagger にもほしいかも

CSS selector to XPath - Bulknews::Subtech - subtech

って書いてあるし、HTML::Selector::XPathmiyagawaさん作なのでありそうだけど、とりあえず習作ということで書いたやつを貼ってみる。

assets/plugins/Filter-EntryFullText/*.yamlxpathなら

extract_xpath:
  title: //h2[@id="title"]
  body: //div[@class="section"]

とか書くところを

extract_selector:
  title: h2#title
  body: div.section

なんていう風に書ける。

Index: EntryFullText.pm
===================================================================
--- EntryFullText.pm	(リビジョン 1947)
+++ EntryFullText.pm	(作業コピー)
@@ -258,7 +258,7 @@
     my($self, $args) = @_;
     my $data;
 
-    unless ($self->{extract} || $self->{extract_xpath}) {
+    unless ($self->{extract} || $self->{extract_xpath} || $self->{extract_selector}) {
         Plagger->context->log(error => "YAML doesn't have either 'extract' nor 'extract_xpath'");
         return;
     }
@@ -271,19 +271,35 @@
 	}
     }
 
-    if ($self->{extract_xpath}) {
+    if ($self->{extract_xpath} || $self->{extract_selector}) {
         eval { require HTML::TreeBuilder::XPath };
         if ($@) {
             Plagger->context->log(error => "HTML::TreeBuilder::XPath is required. $@");
             return;
         }
 
+        my $selector = eval {
+            require HTML::Selector::XPath;
+            HTML::Selector::XPath->new;
+        };
+
+        if ($self->{extract_selector} && $@) {
+            Plagger->context->log(error => "HTML::Selector::XPath is required. $@");
+            return;
+        }
+
+        my $extractor = $self->{extract_selector} ? 'extract_selector' : 'extract_xpath';
+
         my $tree = HTML::TreeBuilder::XPath->new;
         $tree->parse($args->{content});
         $tree->eof;
 
-        for my $capture (keys %{$self->{extract_xpath}}) {
-            my @children = $tree->findnodes($self->{extract_xpath}->{$capture});
+        for my $capture (keys %{$self->{$extractor}}) {
+            my $xpath = $self->{extract_xpath}->{$capture} || do {
+                $selector->selector($self->{extract_selector}->{$capture});
+                $selector->to_xpath;
+            };
+            my @children = $tree->findnodes($xpath);
             if (@children) {
                 no warnings 'redefine';
                 local *HTML::Element::_xml_escape = \&xml_escape;
@@ -291,7 +307,7 @@
                     ? $children[0]->as_XML
                     : $children[0]->getValue;
             } else {
-                Plagger->context->log(error => "Can't find node matching $self->{extract_xpath}->{$capture}");
+                Plagger->context->log(error => "Can't find node matching $self->{$extractor}->{$capture}");
             }
         }
     }

各種ソーシャルブックマークのコメントを埋(ryのLDR版

LDR版も欲しいなあ

livedoorクリップに各種ソーシャルブックマークのコメントを埋め込むGreasemonkeyスクリプト(管理人日記) - むぅもぉ.jp

とのことだったので書いてみました。


とりあえず動いてるように見える版です。デフォルトだとキーバインドのBかBMっていう文字列クリックでメニューの上矢印のところにコメントを表示します。消すには適当なところをクリックとかで*1。初めは自分でポジションいじって表示しようと書いてたんだけど、面倒になって結局FlatMenu使った。表示位置も手抜き。結果のキャッシュとかもしてないし。

恥ずかしながらY!PipesでJSON(P)?でも出力できるって知らなかった。というか一回も使ったこと無かった。ちょっといじってみようかなと思った。でも今回みたいな使い方だとレスポンスが返ってくるまで結構時間がかかるので常用するのはつらいかなぁっていうのが正直なところです。これは僕の家の回線が遅いせいからかもしれないけど。

あと、HTMLエスケープをしてなかったので、Twitter statuses list for LDR - 口から出まかせの修正をした。HTMLエスケープとか書いてるとき最初に気付くべきだよなぁ。

追記

あぁそうか、entry_widgetsの下というかエントリーにappendChildすれば簡単だったんだ、とクリップのonkさんのコメント経由でid:aki77さんのソースを読んで気付いた。

ちょろっと変更して試しに以下の二通りを作ってみた。ちょっとわかりづらいけど、一つ目はid:aki77さんのやつみたいにエントリーがのびる。二つ目は次のエントリーにかぶる。ソースは後で貼る。


FlatMenuの引数にbase_elementを指定するとそのエレメントに、省略するとbodyにappendChildしてくれるので簡単に変更できた。LDR++

再追記

だいぶ書き換えた。というかFlatMenu使うのやめた。FlatMenu#snapとかFlatMenu#hideでインスタンスを全部消せるのがFlatMenuの利点だと(勝手に)思ったので。

関係ないけどGreasemonkeyのwindowからunsafeWindowで拡張されたオブジェクトのprototypeを使うのにいちいち

with(unsafeWindow) {
    new String('foo').func()
}

とか書いてるんだけどこれってなんかうまいことできないのかなぁ。むしろこう書くのが当然なのかなぁ。

*1:「その他」のメニューと同じです