SweetPotato::Plagger このページをアンテナに追加 RSSフィード

2009-02-14

手書きブログのEFT&RONDO ROBEのCF::S+EFT&LantisのEFTをCodeReposにコミット 01:42  手書きブログのEFT&RONDO ROBEのCF::S+EFT&LantisのEFTをCodeReposにコミット - SweetPotato::Plagger を含むブックマーク はてなブックマーク -  手書きブログのEFT&RONDO ROBEのCF::S+EFT&LantisのEFTをCodeReposにコミット - SweetPotato::Plagger  手書きブログのEFT&RONDO ROBEのCF::S+EFT&LantisのEFTをCodeReposにコミット - SweetPotato::Plagger のブックマークコメント

手書きブログのEFTは大きな画像やコメント画像をぶっこぬきたい時に。

RONDE ROBEとLantisは最新アニメCD&DVDリリース情報をいち早く入手したい人向け。

トラックバック - http://plagger.g.hatena.ne.jp/SweetPotato/20090214

2008-09-02

CodeReposコミッタになりました CodeReposコミッタになりました - SweetPotato::Plagger を含むブックマーク はてなブックマーク - CodeReposコミッタになりました - SweetPotato::Plagger CodeReposコミッタになりました - SweetPotato::Plagger のブックマークコメント

まずは,ここにあるスクリプト類を順次コミットしていこうかと。

トラックバック - http://plagger.g.hatena.ne.jp/SweetPotato/20080902

2008-04-22

Store::Fastladderを使っていてpermalinkとか未読記事とかに問題が出てきたのでパッチ作った 22:55 Store::Fastladderを使っていてpermalinkとか未読記事とかに問題が出てきたのでパッチ作った - SweetPotato::Plagger を含むブックマーク はてなブックマーク - Store::Fastladderを使っていてpermalinkとか未読記事とかに問題が出てきたのでパッチ作った - SweetPotato::Plagger Store::Fastladderを使っていてpermalinkとか未読記事とかに問題が出てきたのでパッチ作った - SweetPotato::Plagger のブックマークコメント

OpenFLとStore::Fastladderを組み合わせて使っていたんだけど,いくつか問題が出てきた。

  1. 未読記事が10件しか表示されない
  2. Filter::TruePermalinkを使ってもtrueなpermalinkがDBに格納されない
  3. 記事本文のHTMLコメントが見えてしまう
  4. 記事がStore::FastladderによってDBに格納される度に未読になる

1.は先日の記事でこちらを参考にして解決できたんだけど残りが問題。

DBにはMySQLを使ってるんだけど「MySQLの問題じゃねーだろー」と思ってOpenFL(Windows版 0.0.2)とStore::Fastladder(Revision 2029)のソースを眺めた。

関係してるのは以下の箇所かな。

app\controllers\api_controller.rb (line.31-33)

  def unread
    conditions = @sub.viewed_on ? ["stored_on >= ?", @sub.viewed_on] : nil
    items = @sub.feed.items.find(:all, :conditions => conditions, :order => "created_on DESC, id DESC", :limit => MAX_UNREAD_COUNT)

OpenFLは記事が未読か否かをstored_onカラムの値を見て判断すると。

lib\crawler.rb (line.174-176)

    items = items.reject { |item|
      feed.items.exists?(["link = ? and digest = ?", item.link, item.digest])
    }

OpenFLのクローラは,既に同じリンクの記事がDBに格納されていた場合,記事のdigestを比較する。そしてdigestが同じ(≒記事本文に変化なし)であれば,その記事はDBに格納しないと。

Plagger\Plugin\Store\Fastladder.pm (line.93-96)

        my $item = $self->rs('Items')->find_or_new({
            feed_id => $feed->id,
            link    => $entry->link,
        });

Store::Fastladderは$entry->permalinkではなく$entry->linkの値をDB格納していると。

というわけでこんなパッチに

--- Fastladder.pm.rev2029	Tue Apr 22 18:53:39 2008
+++ Fastladder.pm	Tue Apr 22 20:53:46 2008
@@ -92,29 +92,28 @@
     for my $entry (@{ $args->{feed}->entries }) {
         my $item = $self->rs('Items')->find_or_new({
             feed_id => $feed->id,
-            link    => $entry->link,
+            link    => $entry->permalink,
         });
 
         $item->set_columns({
             title          => $entry->title || '',
-            body           => $entry->body,
+            body           => do { my $body = $entry->body || '' ; $body =~ s/<!--.*?-->//g; $body },
             author         => $entry->author,
             category       => join(', ', @{$entry->tags}) || undef,
             digest         => $entry->digest,
             enclosure      => $entry->has_enclosure ? $entry->enclosure->url : undef,
             enclosure_type => $entry->has_enclosure ? $entry->enclosure->type : undef,
         });
-        $item->created_on( $entry->date || $now );
-        $item->modified_on( $entry->date || $now );
-        $item->stored_on( $now );
-        $item->updated_on( $now ) if $item->is_changed;
 
-        if ($item->is_column_changed('digest')) {
+        if (!$item->in_storage || $item->is_column_changed('digest')) {
+            $item->created_on( $entry->date || $now ) if !$item->in_storage;
+            $item->modified_on( $entry->date || $item->created_on );
+            $item->stored_on( $now );
+            $item->updated_on( $now );
             my $subs = $me->subscriptions({ feed_id => $feed->id })->first;
             $subs->update({ has_unread => ref($self->schema->storage) =~ /SQLite/ ? 'true' : \'true' }); # XXX
+            $item->insert_or_update;
         }
-
-        $item->insert_or_update;
     }
 
     # update status

記事本文のHTMLコメントは思い切って落とすことにした。ひょっとしたらOpenFL側で非表示にできるのかもしれないけど「どうせ表示されないなら格納時に落としちゃっていいじゃん」という発想。

ところでupdated_onカラムの存在意義を誰か教えてください。他のソースも頑張って読んだけどさっぱり分からない。

トラックバック - http://plagger.g.hatena.ne.jp/SweetPotato/20080422

2008-03-28

Windows XP SP2 に ActivePerl, Plagger, Fastladder (OpenFL), MySQL をインストールした Windows XP SP2 に ActivePerl, Plagger, Fastladder (OpenFL), MySQL をインストールした - SweetPotato::Plagger を含むブックマーク はてなブックマーク - Windows XP SP2 に ActivePerl, Plagger, Fastladder (OpenFL), MySQL をインストールした - SweetPotato::Plagger Windows XP SP2 に ActivePerl, Plagger, Fastladder (OpenFL), MySQL をインストールした - SweetPotato::Plagger のブックマークコメント

新しくノートPCを購入したので, 折角だからと頑張ってみたよ.

ActivePerl, Plagger

d:id:charsbar さんのPPMリポジトリ (http://ppm.tcool.org/) から Plagger 0.7.17 を入手するために, http://downloads.activestate.com/ActivePerl/Windows/5.8/ から ActivePerl 5.8.8.817 (ActivePerl-5.8.8.817-MSWin32-x86-257965.msi) をダウンロードしてインストール.

インストール後にPPMを起動し, 下記の通りプロンプトから入力.

ppm> rep add tcool http://ppm.tcool.org/server/ppmserver.cgi?urn:PPMServer
Repositories:
[1] ActiveState Package Repository
[2] tcool
ppm> rep off 1
Repositories:
[1] tcool
[ ] ActiveState Package Repository
ppm> install Plagger
(中略... 途中の質問にはすべてデフォルト回答.)
Successfully installed Plagger version 0.7.17 in ActivePerl 5.8.8.817.
ppm> quit

OpenFL

http://fastladder.org/ja/ から最新版 (私の場合, fastladder-0.0.2-win32.exe) をダウンロードしてインストール.

MySQL

http://dev.mysql.com/downloads/ から5.0 (私の場合, mysql-essential-5.0.51a-win32.msi) をダウンロードしてインストール.

インストール後の設定は, DBエンジンにInnoDBを, 文字コードにutf8を使用する部分だけ間違えなければ大丈夫だと思う.

OpenFLの設定

fastladder\config\database.yml.mysql を fastladder\config\database.yml にリネーム. 内容は下記のように.

production:
  adapter: mysql
  encoding: utf8
  database: fastladder_production
  username: root
  password: **********
  socket: /var/run/mysqld/mysqld.sock
データベースの作成

今回はプロンプトからやってみた. GUI Tools を使っても良さそう.

...\fastladder>mysqladmin -u root -p create fastladder_production
Enter password: **********

...\fastladder>
テーブルの作成

fastladder\migrate.bat を実行するだけでOKなんて楽だね...って, エラーが出て中断されたよ.

...\fastladder>migrate
Creating database...don't close this window.
Please run "start -> programs -> Fastladder -> Upgrade Database" if you have
aborted.
(中略...)
== 2 CreateFeeds: migrating ===================================================
-- create_table(:feeds)
rake aborted!
Mysql::Error: #42000BLOB/TEXT column 'description' can't have a default value: C
REATE TABLE `feeds` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `feed
link` varchar(255) NOT NULL, `link` varchar(255) NOT NULL, `title` text NOT NULL
, `description` text DEFAULT '' NOT NULL, `subscribers_count` int(11) DEFAULT 0
NOT NULL, `image` varchar(255) DEFAULT NULL, `icon` varchar(255) DEFAULT NULL, `
modified_on` datetime DEFAULT NULL, `created_on` datetime NOT NULL, `updated_on`
 datetime NOT NULL) ENGINE=InnoDB

(See full trace by running task with --trace)

...\fastladder>

「BLOB/TEXT型の列はデフォルト値を持てない」とのこと. fastladder-discuss-ja に同様の報告と対処法があったので, それを参考にファイル内容を書き換える.

fastladder\db\migrate\002_create_feeds.rb

上記エラーの原因を修正.

before:

      t.text :description, :default => "", :null => false

after:

      t.text :description, :null => false
fastladder\db\migrate\006_create_items.rb

こちらもそのままだと同様のエラーが出るようなので修正.

before:

      t.text :title, :default => "", :null => false

after:

      t.text :title, :null => false

修正後, 再び fastladder\migrate.bat を実行し, 無事終了.

OpenFLサーバの起動

...\fastladder>server

...\fastladder>ruby-win32\bin\ruby script\server -e production
=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with production environment...
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready.  INT => stop (no restart).
** Mongrel 1.1.2 available at 0.0.0.0:3000
** Use CTRL-C to stop.

プロンプトは放置プレイ.

OpenFLアカウントの作成

http://localhost:3000/ から. 作成したアカウントの member_id なるものは 1 になるらしい.

Store::Fastladderの入手

svn co http://svn.bulknews.net/repos/plagger/branches/fastladder-crawler/plagger/

Store::Fastladder 他を適切なディレクトリへ移動.

さらに依存モジュールをPPMからインストール (私の場合, DBIx::Class::Schema::Loader と DateTime::Format::MySQL がなくて怒られたので, 両者を ppm install した).

動作テスト

テスト用のYAMLを以下に.

plugins:
  - module: Subscription::Config
    config:
      feed:
        - url: http://plagger.g.hatena.ne.jp/SweetPotato/

  - module: Store::Fastladder
    config:
      connect_info:
        - dbi:mysql:fastladder_production
        - root
        - **********
        - on_connect_do:
            - SET NAMES utf8
      member_id: 1

あとはいつものように plagger -c test.yaml と.

動作しましたか? 動作しましたか. やりましたね.

後で気づいたんだけど, RubyのMySQLライブラリをインストールする必要があったようなので gem install mysql した.

あと, 未読エントリが10件しか表示されかったのでこちらを読んで解決した.

参考

トラックバック - http://plagger.g.hatena.ne.jp/SweetPotato/20080328

2008-01-07

[][] Web::Scraper for CustomFeed::Script 栗田出版販売コミック刊行予定情報  Web::Scraper for CustomFeed::Script 栗田出版販売コミック刊行予定情報 - SweetPotato::Plagger を含むブックマーク はてなブックマーク -  Web::Scraper for CustomFeed::Script 栗田出版販売コミック刊行予定情報 - SweetPotato::Plagger  Web::Scraper for CustomFeed::Script 栗田出版販売コミック刊行予定情報 - SweetPotato::Plagger のブックマークコメント

このコードの最新版はCodeReposに置いてあります。

まんがの森コミックリストよりも情報が早いと噂の栗田出版販売コミック刊行予定情報をWeb::Scraper+Plaggerでenjoy!

assets/plugins/CustomFeed-Script/bookkurita-comicdb.pl

シンタックスハイライトするとなぜか表示されないので普通のスーパーpreで。見にくくてサーセン。

#!/usr/local/bin/perl
# author: SweetPotato
use strict;
use warnings;
use utf8;

use DateTime;
use Encode qw( decode );
use URI;
use Web::Scraper 0.22;
use YAML;

my $url = 'http://www3.kuradashi-shinkan.com/kanko/comicdb.asp';

my $s = scraper {
    my $publisher;
    process '//body/div/center/table/tr[not(@align)]',
      'entry[]' => scraper {
        process '/tr/td[position()=1 or position()=2]',
          'tags[]' => ['text', \&trim];
        process '/tr/td[1]', publisher => ['text', \&trim];
        process '/tr/td[2]', series => ['text', \&trim];
        process '/tr/td[3]', title  => ['text', \&trim];
        process '/tr/td[4]', author => ['text', \&trim];
        process '/tr/td[5]', price  => ['text', \&trim];
        process '/tr/td[6]',
          date => ['text', \&trim, \&mk_date],
          part_or_day => ['text', \&trim, sub { m!/(.*?)$!; $1 } ];
        process '/tr/td[7]', isbn => ['text', \&trim];
        result qw( tags publisher series title author price date part_or_day isbn );
    };
    result qw( entry );
};
$s->user_agent->env_proxy;

my $res = $s->user_agent->get($url);
unless ($res->is_success) {
    die "GET $url failed: " . $res->status_line;
}

my @entry = @{ $s->scrape(decode('cp932', $res->content)) || [] };
for my $e (@entry) {
    $e->{body} = &mk_body($e);
    delete $e->{$_} for qw( publisher series price part_or_day isbn );
}

binmode STDOUT, ":utf8";
print YAML::Dump +{
    title => '栗田出版販売 コミック刊行予定情報',
    link  => $url,
    entry => \@entry,
};

# guess year
sub mk_date {
    my ($month, $day) = (shift =~ m!(.*)/(.*)!) or return;
    $day = &part_to_day($day);

    my $today = DateTime->now(time_zone => 'Asia/Tokyo')->truncate(to => 'day');
    my $this = $today->clone->set(month => $month, day => $day);
    my $last = $this->clone->subtract(years => 1);
    my $next = $this->clone->add(years => 1);
    my @date = sort { DateTime::Duration->compare($a->[1], $b->[1], $today) }
               map { [$_->[0], $_->[1]->is_positive ? $_->[1] : $_->[1]->inverse ] }
               map { [$_, $today - $_] } ($this, $last, $next);

    $date[0]->[0]->ymd;
}

sub mk_body {
    my $entry = shift;

    $entry->{part_or_day} =~ /^\d+$/
        ? join ', ', map { $entry->{$_} } qw( author publisher series price isbn )
        : join ', ', map { $entry->{$_} } qw( part_or_day author publisher series price isbn );
}

sub part_to_day {
    $_ = shift;
    return $_ if /^\d+$/;
    return 21 if /下/;
    return 11 if /中/;
    return 1;
}

sub trim { s/^\s*|\s*$//g; $_ }

config.yaml

plugins:
  - module: Subscription::Config
    config:
      feed:
        - url: 'script:/path/to/bookkurita-comicdb.pl'

  - module: CustomFeed::Script

  - module: Publish::iCal
    config:
      dir: /path/to/dir
      filename: kurita.ics
トラックバック - http://plagger.g.hatena.ne.jp/SweetPotato/20080107