Я хотел бы очистить RSS-канал iTunes top X и вставить его в дБ - PullRequest
0 голосов
/ 23 февраля 2009

Предпочтительно, я бы хотел сделать это с некоторыми сценариями оболочки bash, возможно, с некоторыми PHP или PERL и базой данных MySQL. Мысли

Ответы [ 4 ]

1 голос
/ 10 марта 2009

Из того, что я могу сказать, он не поддерживается активно, но Скриптелла может оказать некоторую помощь. Очень простой XML-скрипт, работающий на Java.

Пример загрузки RSS в базу данных :

<!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>
1 голос
/ 23 февраля 2009

Вот решение, использующее Perl, с помощью (конечно!) Группы модулей.

Он использует SQLite, так что вы можете легко его запустить (определение (упрощенной) БД находится в конце скрипта). Также он использует хеши Perl и простые операторы SQL вместо правильных объектов и слоя ORM. Мне было проще анализировать XML напрямую, а не использовать модуль RSS (я пробовал XML :: Feed), потому что вам нужен доступ к определенным тегам (name, preview ...).

Вы можете использовать его в качестве основы для добавления дополнительных функций, большего количества полей в БД, таблицы для жанра ... но, по крайней мере, у вас есть база, на которой вы можете расширить (и, возможно, вы сможете опубликовать результат с открытым исходным кодом).

#!/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);
0 голосов
/ 23 февраля 2009

Я очищаю фид Stack Overflow, чтобы выполнить дополнительную фильтрацию, используя PHP DOMDocument , а затем методы DOM, чтобы получить доступ к тому, что я хочу. Я бы посоветовал разобраться в этом.

0 голосов
/ 23 февраля 2009

Ну, я не совсем уверен, какой ответ вы ищете, но я не думаю, что вам нужно делать какие-либо сценарии оболочки. Беспокойство PHP и Perl были бы вполне способны загрузить RSS-канал и вставить данные в MySQL. Настройте PHP или Perl-скрипт так, чтобы он выполнял каждое X-количество часов / дней / что угодно с помощью cronjob, и все будет готово.

Ничего особенного сказать не могу, с тем, насколько неопределенным был ваш вопрос.

...