できれば、いくつかの bash シェル スクリプト、おそらく PHP または PERL と MySQL db を使用してそうしたいと考えています。考え?
4 に答える
私の知る限り、それは積極的に維持されていませんが、Scriptellaはある程度の助けになる可能性があります。Java上で実行される非常に単純なxmlスクリプト。
<!DOCTYPE etl SYSTEM "http://scriptella.javaforge.com/dtd/etl.dtd">
<etl>
<connection id="in" driver="xpath" url="http://snippets.dzone.com/rss"/>
<connection id="out" driver="text" url="rss.txt"/>
<connection id="db" driver="hsqldb" url="jdbc:hsqldb:db/rss" user="sa" classpath="hsqldb.jar"/>
<script connection-id="db">
CREATE TABLE Rss (
ID Integer,
Title VARCHAR(255),
Description VARCHAR(255),
Link VARCHAR(255)
)
</script>
<query connection-id="in">
/rss/channel/item
<script connection-id="out">
Title: $title
Description: [
${description.substring(0, 20)}...
]
Link: $link
----------------------------------
</script>
<script connection-id="db">
INSERT INTO Rss (ID, Title, Description, Link)
VALUES (?rownum, ?title, ?description, ?link);
</script>
</query>
</etl>
これは、Perl を使用したソリューションであり、(もちろん!) 多数のモジュールの助けを借りています。
SQLite を使用しているため、簡単に実行できます ((単純な) DB の定義はスクリプトの最後にあります)。また、適切なオブジェクトと ORM レイヤーの代わりに、Perl ハッシュと単純な SQL ステートメントを使用します。特定のタグ (名前、プレビュー...) にアクセスする必要があるため、RSS モジュール (XML::Feed を試しました) を使用する代わりに、XML を直接解析する方が簡単であることがわかりました。
より多くの機能、DB のより多くのフィールド、ジャンルのテーブルを追加するための基礎として使用できます...しかし、少なくともこの方法で、拡張できる基礎が得られます (そして、結果をオープンとして公開できるかもしれません) -ソース)。
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig; # to parse the RSS
use DBIx::Simple; # DB interaction made easy
use Getopt::Std; # always need options for a script
use PerlIO::gzip; # itunes sends a gzip-ed file
use LWP::Simple 'getstore'; # to get the RSS
my %opt;
getopts( 'vc:', \%opt);
# could also be an option, but I guess it won't change that much
my @URLs= (
'http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/topsongs/limit=10/xml',
);
# during debug, it's nice to use a cache of the feed instead of hitting hit every single run
if( $opt{c}) { @URLs= ($opt{c}); }
# I like using SQLite when developping,
# replace with MySQL connect parameters if needed (see DBD::MySQL for the exact syntax)
my @connect= ("dbi:SQLite:dbname=itunes.db","","", { RaiseError => 1, AutoCommit => 0 }) ;
my $NS_PREFIX='im';
# a global, could be passed around, but would make the code a bit more verbose
my $db = DBIx::Simple->connect(@connect) or die "cannot connect to DB: $DBI::errstr";
foreach my $url (@URLs)
{ add_feed( $url); }
$db->disconnect;
warn "done\n" if( $opt{v});
sub add_feed
{ my( $url)= @_;
# itunes sends gziped RSS, so we need to unzip it
my $tempfile= "$0.rss.gz"; # very crude, should use File::Temp instead
getstore($url, $tempfile);
open( my $in_feed, '<:gzip', $tempfile) or die " cannot open tempfile: $!";
XML::Twig->new( twig_handlers => { 'feed/title' => sub { warn "adding feed ", $_->text if $opt{v}; },
entry => \&entry,
},
map_xmlns => { 'http://phobos.apple.com/rss' => $NS_PREFIX },
)
->parse( $in_feed);
close $in_feed;
}
sub entry
{ my( $t, $entry)= @_;
# get the data
my %song= map { $_ => $entry->field( "$NS_PREFIX:$_") } qw( name artist price);
if( my $preview= $entry->first_child( 'link[@title="Preview"]') )
{ $song{preview}= $preview->att( 'href'); }
# $db->begin_work;
# store it
if( ($db->query( 'SELECT count(*) FROM song WHERE name=?', $song{name})->flat)[0])
{ warn " skipping $song{name}, already stored\n" if $opt{v};
}
else
{
warn " adding $song{name}\n" if $opt{v};
if( my $artist_id= ($db->query( 'SELECT id from ARTIST where name=?', $song{artist})->flat)[0])
{ warn " existing artist $song{name} ($artist_id)\n" if $opt{v};
$song{artist}= $artist_id;
}
else
{ warn " creating new artist $song{artist}\n" if $opt{v};
$db->query( 'INSERT INTO artist (name) VALUES (??)', $song{artist});
# should be $db->last_insert_id but that's not available in DBD::SQLite at the moment
$song{artist}= $db->func('last_insert_rowid');
}
$db->query( 'INSERT INTO song ( name, artist, price, preview) VALUES (??)',
@song{qw( name artist price preview)});
$db->commit;
}
$t->purge; # keeps memory usage lower, probably not needed for small RSS files
}
__END__
=head1 NAME
itunes2db - loads itunes RSS feeds to a DB
=head1 OPTIONS
-c <file> uses a cache instead of the list of URLs
-v verbose
=head1 DB schema
create table song ( id INT PRIMARY KEY, name TEXT, artist INT, price TEXT, preview TEXT);
create table artist (id INT PRIMARY KEY, name TEXT);
あなたが探している答えの種類はよくわかりませんが、シェル スクリプトを作成する必要はないと思います。PHP と Perl のどちらでも、RSS フィードをダウンロードして MySQL にデータを挿入することができます。PHP または Perl スクリプトを設定して、X 時間/日ごとに実行するように設定し、cronjob を使用して実行します。
あなたの質問がどれほど漠然としていたかを考えると、他に言うことはあまりありません。
スタック オーバーフローのフィードをスクレイピングして、PHP のDOMDocumentを使用して追加のフィルタリングを実行し、次に DOM メソッドを使用して必要なものにアクセスしています。それを調べることをお勧めします。