Open Source im professionellen Einsatz
Linux-Magazin 01/2015
© vichienrat jangsawang, 123RF

© vichienrat jangsawang, 123RF

Perl-Skript überwacht Besucherstatistik von Youtube-Videos

Chartstürmer

Damit Hobby-Youtuber Michael Schilli erfährt, wenn seine Guckerzahlen durch die Decke gehen, analysiert ein Perl-Skript täglich Trends und schlägt Alarm, falls ein Video plötzlich zum Hit wird.

1035

Steht ein Hobby-Handwerker wie ich heute vor einem scheinbar unlösbaren mechanischen Problem, zum Beispiel weil das Gehäuse eines Gadgets sich gegen das Garantie-verachtende Öffnen sträubt, hilft meist ein Youtube-Video weiter. Auch bei nicht ganz einfach zu bedienender Software wie Gimp zeigt meist ein Fachmann in einem Screencast auf Youtube wie man als Hobbyist auch komplizierte Aufgaben löst.

Schiff der Träume

Als es mir vor einiger Zeit gelang, Gimps Scissor-Tool erfolgreich anzuwenden, machte ich gleich einen Screencast daraus. Danach wartete ich vergeblich darauf, dass dieses meisterlich produzierte Video in den Charts aufsteigt. Erst setzte ich mir monatliche Erinnerungstermine in Evernote, um in regelmäßigen Abständen die Anzahl der Views auf Youtube zu inspizieren. Aber das kostet Zeit, die ich nicht habe. Dank des CPAN-Moduls WebService::GData::YouTube geht es nun auch automatisch.

Hierzu listet die Yaml-Datei in Listing 1 die IDs der zu überwachenden Videos auf. Die Hex-Nummern habe ich einfach aus den entsprechenden Youtube-URLs extrahiert. So stammt zum Beispiel der String »_Cxu3-UP0G8« aus der URL-Zeile des Browsers ( Abbildung 1 ).

Listing 1

youtube-watch.yml

01 -
02   name: GIMP - Scissors Select Tool
03   id: _Cxu3-UP0G8
04 -
05   name: How to fix Acura/Honda not starting in hot weather
06   id: ssYpyXjGw9g
07 -
08   name: Flip it: Record Messages and play them Backwards
09   id: LdSTIa2Tx4o
10 -
11   name: Scored a goal at Garfield Square
12   id: bvOvnyJTyss
Abbildung 1: Der Hobbyproduzent dieses Youtube-Screencast möchte wissen, wie sich seine Userzahlen entwickeln (297 Views bisher).

Das Skript in Listing 2 geht nun mit Hilfe des Yaml-Moduls vom CPAN der Reihe nach durch die Einträge der Yaml-Datei und übergibt jeweils die Video-ID an die Methode »get_video_by_id()« des Pakets WebService::GData::YouTube. Dieses wiederum kontaktiert den API-Server von Youtube und bekommt einen Wust an Metadaten über das Video zurück. Unter dem Schlüssel »_feed« findet das Skript im Eintrag »yt$statistics« den Wert für »ViewCount« , also die Anzahl der Aufrufe des Videos.

Listing 2

youtube-viewcounts

01 #!/usr/local/bin/perl -w
02 use strict;
03 use WebService::GData::YouTube qw();
04 use YAML qw( LoadFile );
05 use Json qw( to_json );
06
07 my @result = ();
08 my $videos =
09   LoadFile( "youtube-watch.yml" );
10 my $yt = WebService::GData::YouTube->new();
11
12 for my $video ( @$videos ) {
13
14   my $meta =
15     $yt->get_video_by_id( $video->{ id } );
16
17   $video->{ count } = $meta->{ _feed }->
18     { 'yt$statistics' }->{ viewCount };
19
20   push @result, $video;
21 }
22
23 print to_json( \@result,
24     { pretty => 1, canonical => 1 } );

Die Zeilen 23 und 24 formen die Ausgabedaten noch schnell mittels des Json-Moduls vom CPAN in das maschinenlesbare Format um, damit nachfolgende Skripte wie Listing 3 sie leicht verarbeiten können. Dabei setzt es die Optionen »pretty« , um die Ausgabe auch für menschliche Konsumenten leicht lesbar darzustellen, und »canonical« , damit die sonst in Perl unsortierten Hashschlüssel sortiert herauskommen. Im Ergebnisarray »@result« führt dann jedes Element die Felder »name« (Titel des Videos), »count« (den in Zeile 17 hineingeschmuggelten Viewcount) und »id« , die eindeutige Youtube-Kennung des Videos.

Listing 3

viewcounts-todb

01 #!/usr/local/bin/perl -w
02 use strict;
03 use DBD::SQLite;
04 use Json qw( from_json );
05 use DBI;
06 my $dbh = DBI->connect(
07   "dbi:SQLite:dbname=viewcounts.db",
08   "", "", { RaiseError => 1} );
09
10 my $data = from_json( join '', <STDIN> );
11
12 for my $video ( @$data ) {
13   my $sth = $dbh->prepare(
14     "INSERT INTO
15      views(video_id,views,queried)
16      VALUES(?,?,CURRENT_TIMESTAMP)" );
17   $sth->execute( $video->{ id },
18                  $video->{ count } );
19 }

Abbildung 2 zeigt die Ausgabe des Skripts und offenbart, dass meine bislang wenig öffentlich bekannte Tätigkeit als Automechaniker an 20 Jahre alten Honda-Motoren mit etwa 56000 Aufrufen zu den Highlights meines Oeuvres gehört, während der Gimp-Screencast mit nur 297 Aufrufen noch (!) vor sich hin dümpelt.

Abbildung 2: Die Json-Ausgabe von Listing 2 mit den von Youtube eingeholten Guckerzahlen pro Video.

Tägliche Tests

Läuft Listing 1 täglich mittels eines Cronjobs einmal ab, steht danach die Archivierung und spätere Auswertung der Daten an. Dazu dient in Listing 3 die Minidatenbank SQlite, die ihre Daten in einer einzigen Datei ablegt, aber SQL-Abfragen erlaubt.

Das in Listing 4 gezeigte Datenbankschema enthält Felder für die Youtube-ID des Videos ( »video_id« ), die Anzahl der Views ( »views« ) und den Datumstempel der Abfrage ( »queried« ). Mit dem Befehl

Listing 4

viewcounts.sql

1 CREATE TABLE views (
2   video_id TEXT,
3   views    INTEGER,
4   queried  DATE
5 );
sqlite3 viewcounts.db <viewcounts.sql

erzeugt SQlite dann die Datenbank in der frischen Datei »viewcounts.db« . Damit kann dann Listing 3 als zweite Brennstufe mit Hilfe von

youtube-viewcounts | viewcounts-todb

die von Listing 2 erzeugten Json-Daten entgegennehmen und für jeden Array-Eintrag einen Datenbankrecord anlegen.

Das Datumsfeld jedes neuen Eintrags füllt es in Zeile 16 mit »CURRENT_TIMESTAMP« , was SQlite in der Datenbank durch das aktuelle Datum mit Uhrzeit ersetzt. So entsteht für jedes überwachte Video pro Tag ein Datenbankeintrag mit Zeitstempel, der sich hinterher – zeitlich sortiert – leicht wieder herausholen lässt.

Anhand der in Abbildung 3 gezeigten Datenbankeinträge versucht nun Listing 5 herauszufinden, ob die Zuschauerzahlen nur stetig ansteigen oder sich explosionsartig erhöhen. In diesem Fall soll das Skript später den interessierten Beobachter alarmieren.

Listing 5

hit-detect

01 #!/usr/local/bin/perl -w
02 use strict;
03 use DBI;
04 use DBD::SQLite;
05 use Statistics::LineFit;
06 use YAML qw( LoadFile );
07 use Json qw( to_json );
08
09 my $dbh = DBI->connect(
10   "dbi:SQLite:dbname=viewcounts.db",
11   "", "", { RaiseError => 1} );
12
13 my $videos =
14   LoadFile( "youtube-watch.yml" );
15
16 for my $video ( @$videos ) {
17   my $sth = $dbh->prepare(
18     "SELECT views from views
19      WHERE video_id = ? ORDER BY
20      queried ASC" );
21   $sth->execute( $video->{ id } );
22
23   my @xvalues = ();
24   my @yvalues = ();
25
26   my $x = 1;
27   while ( my @row =
28           $sth->fetchrow_array ) {
29     push @xvalues, $x;
30     push @yvalues, $row[0];
31     $x++;
32   }
33
34   my $last_x = pop @xvalues;
35   my $last_y = pop @yvalues;
36
37   my $fit = Statistics::LineFit->new();
38   $fit->setData (\@xvalues, \@yvalues) or
39     die "Invalid data";
40
41   my ($intercept, $slope) =
42     $fit->coefficients();
43
44   my $y_predicted = $intercept +
45                     $last_x * $slope;
46
47   if( abs( $last_y - $y_predicted ) >
48                              3 * $slope ) {
49     print
50     "Hooray, $video->{ name } is a hit!\n";
51   }
52 }
Abbildung 3: In der SQlite-Datenbank speichert das Skript täglich die aktuellen View-Zahlen ab.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 3 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

comments powered by Disqus