h1

CIFS Service im NetApp in Windows-Domain integrieren

6. Mai 2008

Um einige CIFS-spezifische Komandos des NetApp ONTAP testen zu können, muss der NetApp Simulator in die Domain eines Windows 2003 servers integriert werden. Ich habe habe dazu einen virtuellen Windows Server laufen, den ich mittels dcpromo zum DC der Domain netapp.test machte.

Sonstige Konfig: Zwei Virtuelle Maschinen mittels VMware Fusin auf OS X 10.5 - die eine ist der Simulator von Netapp (in einem Ubuntu Linux) die andere der Windows 2003 Server. Alle virtuellen NICs sind auf das Netzwerk gebridged und bekommen ihre IPs von dem lokalen DHCPd im Netz - genauso wie der OS X Host.

An sich ist die Konfiguration des CIFS-Service am Netapp ein simples Vorhaben, wenn man die Fallstricke kennt:

1. Firewall am Windows Server deaktivieren - sonst keine Nameresolution. Kann man mittels host <dcname>.netapp.test prüfen.

2. Zeiten synchronisieren (am OS X Host wird das wohl der Fall sein, in der Windows-VM und dem Host-OS für den Simulator ist das wichtig - der Simulator nimmt die Zeit dann von seinem Host-OS!)

2. CIFS-Service stopen:  > cifs terminate

3. > cifs setup

Den defaults folgen  - so weit sinnvoll. Auf die Timeservices habe ich verzichtet - muss in dieser Testumgebung halt selber den Host für den Simulator (ein Ubuntuserver) aktuell halten (# ntpdate -v time.inode.at).

Das wars!

h1

Net::SSH::Perl und known_hosts

21. April 2008

Bei der Verwendung des Perl Moduls Net::SSH-Perl tritt folgendes Problem auf:

Eine Verbindung zu einem Host mit SSH1 erzeugt die folgende Meldung:

Argument "ssh-rsa" isn't numeric in numeric eq (==) at modules/Net/SSH/Perl/Key/RSA1.pm line 103, <FH> line 23.

Nach längerem Suchen entdeckte ich, dass das Modul Hosts.PM die Methode equal aus dem Modul RSA1.pm verwenden. Dabei wird folgende Ausgabe erzeugt, wenn man das Modul RSA1 kurzfristig umschreibt wie folgt:

sub equal {
my($keyA, $keyB) = @_;
print "$keyA->{rsa}
$keyB->{rsa}
bitsA: $keyA->{rsa}{bits}
bitsB: $keyB->{rsa}{bits}
keyA: $keyA->{rsa}{n}
keyB: $keyB->{rsa}{n}
$keyA->{rsa}{e}
$keyB->{rsa}{e}\n";
$keyA->{rsa} && $keyB->{rsa} &&
$keyA->{rsa}{bits} == $keyB->{rsa}{bits} &&
$keyA->{rsa}{n} == $keyB->{rsa}{n} &&
$keyA->{rsa}{e} == $keyB->{rsa}{e};
}

Ausgabe:

Use of uninitialized value in concatenation (.) or string at modules/Net/SSH/Perl/Key/RSA1.pm line 95, <FH> line 23.
HASH(0x96fe78)
HASH(0x9659e4)
bitsA: 768
bitsB: ssh-rsa
keyA: 1295114094267464959040618524315923090715719842401896780056623074041026914313434353851674959103867550024637278939333976156853100989243816594892986096194402545568572126024189142175098585647756961269395154835682416927930811763277092609
keyB:
35
AAAAB3NzaC1yc2EAAAABIwAAAGEAoDtFmzlg44nJ6JdBs218W3xUmR1TXvTpQYLnAn6djlQPj2d6+Ev0nPObZ0cucvyRqanlkcT4XI6CmKozv4+7v5X3NxLMxA82llPqBQJFUJx+pHJYkOiKiP1cAtI0wXu1
Argument "ssh-rsa" isn't numeric in numeric eq (==) at modules/Net/SSH/Perl/Key/RSA1.pm line 103, <FH> line 23.
HASH(0x96fe78)
HASH(0x952f74)
bitsA: 768
bitsB: 768
keyA: 1295114094267464959040618524315923090715719842401896780056623074041026914313434353851674959103867550024637278939333976156853100989243816594892986096194402545568572126024189142175098585647756961269395154835682416927930811763277092609
keyB: 1295114094267464959040618524315923090715719842401896780056623074041026914313434353851674959103867550024637278939333976156853100989243816594892986096194402545568572126024189142175098585647756961269395154835682416927930811763277092609
35
35

Weitere Recherchen ergaben, dass hier die Datei .ssh/known_hosts gelesen wurde, und diese erlaubt laut man sshd zwei verschiedene Formate:

Examples
closenet,…,130.233.208.41 1024 37 159…93 closenet.hut.fi
cvs.openbsd.org,199.185.137.3 ssh-rsa AAAA1234…..=

Net::SSH::Perl kommt aber mit zweiterem nicht zurecht!

Workarund: In meinem konkreten Fall möchte ich den Hostcheck komplett deaktivieren, um das Perl-Skript von der SSH-Konfig des Hosts vollkommen unabhängig zu machen. Das erreiche mit einem einzigen # an der richtigen Stelle des SSH1.pm:

    $ssh->{session}{id} = $session_id;
# disabled von Ingo: $ssh->check_host_key($keys{host});
my $session_key = join ”, map chr rand(255), 1..32;

Die Security-Implications sind hoffentlich klar: Es findet keine Überprüfung mehr statt, ob der kontaktierte Host nicht in irgend einer Form gespooft ist. Die Verbindung wird ohne Warnung und Prüfung aufgebaut und das Passwort übertragen! Nameresolution und Routing tragen somit die gesamte Verantwortung für die Vertraulichkeit des Passwortes. (Bei automatisierten Scripts in einer an sich gesicherten Umgebung erscheint mir das vertretbar)

http://rt.cpan.org/Public/Bug/Display.html?id=25175

h1

Net::SSH::Perl installieren

21. April 2008

Im Gegensatz zu Net::SSH bietet das Modul Net::SSH::Perl eine voll in Perl integrierten SSH-Client, der in den Perl-Scripts verwenet werden kann. D.h. dieser ist von der installierten SSH-Version unabhängig, forked nicht bei jedem Aufruf was für Performance und Sicherheit sorgt.

Das große Problem an diesem Modul ist die Installation. Es gibt zahlreiche Abhängigkeiten und die Installation via CPAN scheiterte sowohl auf Mac OS X (10.5.2) als auch im Ubuntu Server 6.01 (LTS). Als Troublemaker hab ich die Module Math::Pari, Math::BigInt::GMP und Crypt::DSA geortet. Diese habe ich nun manuell installiert. Dazu die folgenden Schritte zunächst für Ubuntu und dann für OS X:

Installation von Net::SSH::Perl auf Ubuntu 6.01.1 Server

Falls man das nicht schon hinter sich hat müssen perl und cpan installiert werden:

# apt-get install perl

Dann geht’s los …

Math::Pari

$sudo -s
# apt-get update
# apt-get upgrade
# apt-get install gcc
#apt-get install g++

Dann hole man sich das Tar von der Pari-Homepage und packe es im CPAN-Build-Verzeichnis aus:

# cd ~/.cpan/build
# wget http://pari.math.u-bordeaux.fr/pub/pari/unix/pari-2.3.3.tar.gz
# tar -xzf pari-2.3.3.tar.gz

Nun kann man den Anweisungen aus dem INSTALL folgen:

b) ./Configure

c) make all, make bench

d) make install

e) cp misc/gprc.dft /etc/gprc

Tipp: Wenn man diese Fehlermeldung bekommt “C compiler does not work. PARI/GP requires an ANSI C compiler” dann hat man vergessen den c++-Kompiler zu installieren. Siehe oben!

Math::BigInt::GMP

Damit dieses Modul installiert werden kann, muss man erst einmal eine GMP-Library im OS installieren:

# apt-get install libgmp3-dev

cpan> install Math::BigInt::GMP

Crypt::DSA

Crypt::DSA muss manuell (ohne CPAN) installiert werden, da make test sich aufhängt.

# wget http://search.cpan.org/CPAN/authors/id/B/BT/BTROTT/Crypt-DSA-0.14.tar.gz
# tar xzf Crypt-DSA-0.14.tar.gz
# cd Crypt-DSA-0.14
# perl Makefile.PL
# make
# make install

Nun kann man den Rest mit CPAN installieren:

cpan> install Net::SSH::Perl

Bei der Auswahl der Algorithmen würde ich noch DES3 hinzunehmen - NetApp z.B. unterstützt das out-of-the-box:

    [1] IDEA
[2] DES
[3] DES3
[4] Blowfish
[5] RC
Enter your choices, separated by spaces: [1] 1 3

Möchte man Tripple-DES ergänzen, nachdem man das Modul Net::SSH::Perl schon einmal nur mit IDEA installiert hat, so ruft man einfach in der cpan-Shell make Net::SSH::Perl auf.

Installation von Net::SSH::Perl auf Mac OS X

Zunächst ein Hinweis: Die Developer-Tools waren bei mir installiert (siehe http://developer.apple.com/tools/xcode/index.html ) - das muss so sein, schon alleine damit die später benötigte port-Software funktioniert.

Ansonsten versuchte ich sinngemäß zu verfahren wie beim Ubuntu-Server. Die Installation von Crypt::DSA mittels CPAN war kein Problem (OS X 10.5.2). Somit bleiben Math::Pari und GMP als “Sonderfälle”. Und da war nichts zu machen. Weder mittel CPAN noch durch den Weg “zu Fuß” mittels Download, Auspacken und dann ./Configure und make. Somit änderte ich die Strategie komplett und installierte das ganze mittels darwin-ports. Falls noch nicht geschehen, ist die Darwinport-Software zunächst zu installieren. (Siehe http://darwinports.com/ bzw. http://guide.macports.org/)

Installation von Pari

ich habe zunächst einmal Pari installiert. Das Paket liegt hier (http://pari.darwinports.com/), muss aber nicht heruntergeladen werden. Das macht das Komando:

$ sudo port install pari

Installation von Convert::PEM und Net::SSH::Perl

http://p5-convert-pem.darwinports.com/

Da hat sich ein Problem ergeben: Nach einiger Zeit bleibt der Installationsprozess hängen, die CPUs laufen auf jeweils 100% und nichts geht mehr weiter. Auch viel Geduld ändert da nichts. Wenn man die Installation im Debugmodus startet, sieht man die Ursache des Problems:

$sudo port -d install p5-convert-pem

Wenn CPAN für diesen User noch nicht konfiguriert ist, frägt Darwinport nach dem Kontinent für Downloads. Und aus dieser Schleife findet er icht mehr heraus. Die Lösung ist also, cpan zuvor zu konfigurieren und sicher zustellen, dass diese Konfiguration dauerhaft gespeichert wurde. (Ich hab dazu sudo -s und dann als root cpan gestartet, Bundle::CPAN installiert, CPAN nochmal gestartet und die diversen Dialoge beantwortet wobei ich die Frage nach der Speicherung der Konfiguration entgeggen dem Default mit yes statt mit no beantwortet hatte.)

Nach diesem Heckmeck durfte ich dann endlich Convert::PEM und Net::SSH::Perl installieren; und zwar so:

$ sudo port install p5-net-ssh-perl

Nacharbeiten

Die Module werden so out of the Box nicht gefunden. Man kann deren Verzeichnisse (/opt/local/lib/perl5/5.8.8) aber mit lib im Perlscript hinzufügen.

Veränderungen an den Modulen

Wenn man diese mit port installierten Module allerdings editiert und die Veränderten in ein eigenes Verzeichnis kopieren, funktioniert das ganze nur noch teilweise. Net::SSH::Perl kommt damit zurecht. Math::Pari sträubt sich aber. Das führt dazu, dass in diesem Fall nur SSH1 Verbindungen mit Net::SSH::Perl möglich sind.

h1

NetApp-Simulator für Mac OS X

9. April 2008

Den NetApp-Simulator in Mac OS X verwenden

Im Zuge der Entwicklung von Nagios Plugins für NetApp Speichersysteme, benötigte ich den NetApp Simulator um diese Plugins entwicklen und testen zu können. Da ich hier zur Zeit keinen Linux-Rechner betreibe entschied ich mich auf meinem iMac einen virtuellen Linuxserver zu installieren und dann dort den Simulator laufen zu lassen.

Beim Download des Simulators war eine Anleitung von Paul Hargreaves beigepackt die eine Installation des Simulator auf Windows (als Gastbetriebssystem) und dann einem Ubuntu 6.01 Desktop in einer VM beschreibt. Diese Anleitung ist an sich nicht schlecht, passte aber nicht ganz auf meine Anforderungen:

1. Habe ich OS X und nicht Windows, daher verwende ich VMware Fusion

2. Möchte ich nicht einen Desktop (mit GUI, …) installieren, wenn ich eigentlich nur einen Server brauche. Obendrein hätte ich die die Server-VM fix und fertig vorbereitet gehabt.

Also entschied ich mich für folgendes: Max OS X 10.5, VMware Fusion 1.1.1 und Ubuntu Server 6.01 LTS, NetApp Release 7.2.4 (Simulator).

Überblick:

  1. Einrichten des Gastsystemes
  2. VMware einrichten
  3. Installation Linux Server in der VM
  4. Installation des Simulators

Gastsystem einrichten

Am Mac OS X ist nichts speziell zu tun ausser VMware Fusion zu installieren. Die aktuelle Version (s.o.) läuft gut auf Leopard - aber Vorsicht: Time Machine sichert die VMs nicht! Workaround: Gelegentlich ein ZIP von der VM machen - das wird dann gesichert. (Zippen natürlich nur, wenn die VM abgeschalten ist)

VMware einrichten

In meiner Umgebung gibt es einen DHCP-Server auf der Firewall, der für das interne LAN ca. 10 freie Adressen hat. Der springende Punkt war nun - im Gegensatz zur Dokumentation von Paul Hargreaves - die virtuellen Netzwerkkarten als bridged einzurichten. Nur so ist es möglich, dass von Seiten des Hostbetriebssystemes (also OS X) auf die IP und somit den Webserver des Simulator zugegriffen wird. Das ist z.B. nötig, um über die Weboberfläche des Simulators diesen zu konfigurieren.

Also richte ich zwei virtuelle Netzwerkkarten auf der VM ein (dazu muss das Gastbetriebssystem heruntergefahren werden) und beide werden über /etc/network/interfaces als DHCP-Clients konfiguriert. (Ich bin mir inzwischen nicht mehr so sicher, ob beide NICs wirklich nötig sind.)

Linux Server in der VM installieren

Ich hab eine schon früher vorbereitete Installation von Ubuntu Server verwendet. Auf Updates (apt-get upgrade) und VMware Tools habe ich verzichtet. Aber sehr wichtig: Es wird Perl benötigt, sonst kann man später keine Disken dem Simulator hinzufügen.

apt-get install perl

Dann kopiert man das Simulator-Tar auf die Linuxmaschine - mit z.B. scp. Wenn man dabei nicht noch den sshd am Linuxrechner installieren will (was mit apt-get install open-ssh-server möglich wäre) muss man am Mac den sshd aktivieren. Das läuft über die Systemeinstellungen -> Sharing -> “Entfernte Anmeldungen” aktivieren.

Installation des Simulators

Siehe dem Simulator beigepackte Doku - hier nur ein paar Tipps:

./setup.sh

Im Folgenden sind die Default-Antworten ok. Lediglich die an sich unnötige Frage, ob man die Installation fortsetzen will muss natürlich mit yes statt no beantwortet werden.

Bei der Frage ” Which network interface schould the simulator use?” habe ich dediziert eth2 angegeben.

Dann kann man wieder den defaults folgen.

Als Nächster Schritt ist der Simulator mit /sim/runsim.sh zu starten und einige Fragen zur Erstinstallation zu beantworten. Dabei schaltet der Simulator die NIC in den Promiscuity-Mode, was auch das Umschalten des Hostsystemadapters zur Folge hat, weswegen man von OS X um ein Adminpasswort gefragt wird. Das ist lt. NetApp Doku so gewollt und scheint mir auch einigermassen plausibel.

Etwas später kommt die Frage: “Please enter the IP adress for Network Interface ns0″. Hier wird dann eine vom DHCP-Server vorgschlagene Adresse als Default angegeben. Das ist ok, nur diese bitte aufschrieben, da wir sie gleich brauchen werden. Der Rest sollte klar sein, sobald man zur CIFS-Installation kommt kann man mit Ctrl+C abbrechen.

Zugriff auf die Weboberfläche vom Simulatir erfolgt dann über einen Webbrowser. Safari ist nicht mit dem Simulator kompatibel - ich habe Firefox verwendet:

http://<ip die der Sim über DHCP bekommen hat>

Dann Klick auf na_admin und root als User und das zuvor gesetzte Passwort eingeben. That’s it.

h1

Perl-Doku in Textmate

3. April 2008

In Textmate gibts eine feine Funktion für Perlprogrammierer: Ctrl+H öffnet die Dokumentation zu dem Begriff, auf dem gerade der Cursor steht. Das geht aber nur, wenn Perldoc installiert ist - sonst sieht man nur ein leeres Fenster.

Also sudo cpan im Terminal und dann install Perldoc

h1

SEO-Monitoring 3: Daten auswerten

27. Februar 2008

Wie in “SEO-Monitoring 2: Daten holen” beschrieben, erhalten wir mit dem Skript get_google.pl jeden Tag ein neues Verzeichnis, in dem die Suchergebnisse als HTML-Files angelegt sind. Ein Vorteil des modularen Ansatzes (One task one tool) ist, dass es keineswegs nötig ist diese Verzeichnisstruktur mit dem Skript aufzubauen und zu befüllen. Genausogut kann man das manuell mit dem Browser machen, und die Seiten mit “Speichern als …” als HTML-File ablegen. Das Skript get_google.pl macht ja nichts anderes, als einen “geskripteten” Browser zur Verfügung zu stellen.

Results von get_google.pl (kleiner Ausschnitt)

In dem Bild oben sehen wir einen Ausschnitt aus dem Ergebnis von get_google.pl bei der Suche nach irgendwas in 1030 Wien um 9h05. Somit sind die Suchergebnisse für einen bestimmten Zeitpunkt und Begriff einmal vollständig archiviert, nur die Übersicht hat man so natürlich nicht … Daher ein weiteres Skript, das diese Verzeichnisse und alle Dateien systematisch durchsucht und daraus ein CSV-File (Kommaseperierte Datei) generiert. Dieses CSV-Ausgabefile soll z.B. aussehen wie folgt:

"Zeit[Epochenekunden]“,”Datum”,”Uhrzeit”,”Suchbegriff(e)”,”tad-position”,”ad-position”,”s-position”,”Anz. der Vorkommen in den S.E.”,
“1204013102″,”2008-02-26″,”09h05″,”foo”,”0″,”1″,”11″,”2″,
“1204013102″,”2008-02-26″,”09h05″,”bar”,”0″,”1″,”3″,”4″,
“1204013102″,”2008-02-26″,”09h05″,”foo+bar”,”0″,”0″,”1″,”2″,

So was sehen wir da oben nun: Zu dem Suchbegriff “foo” wurde am 26. Februar um 9h05 eine bestimmte URL in den Google-Ergebnissen an der 11 Position angezeigt. In den Anzeigen (AdWords) war diese URL im rechten Block an 1. Stelle und im oberen Block gar nicht gelistet. In den ersten 100 Ergebnissen (ohne AdWords-Bereich), war diese URL 2 mal gelistet. Das alles entnehmen wir der ersten Zeile nach den Spaltenüberschriften (zweite Zeile im o.g. Ausschnitt).

Das bei Eingabe des Suchwortes “bar” wird diese URL in den AdWords-Anzeigen oben nicht, auf der rechten Seite an erster Position und in den Suchergebnissen an 3. Stelle gelistet. Insgesamt ist diese URL 4 mal in den ersten 100 Ergebnissen zu finden. Das entnehmen wir der zweiten Zeile nach den Spaltenüberschriften (dritte Zeile im Beispiel oben).

Und nun die letzte Zeile: Hier wurde nach “foo bar” gesucht. Die URL taucht in den Anzeigen gar nicht auf, dafür in den Suchergebnissen an erster Stelle und das zwei mal.

Dieses Beispiel ist übrigens fiktiv! Wenn jetzt wer verwundert innehält und frägt, was daran jetzt übersichtlich sein soll, sag ich - nur Geduld, denn eine CSV-Datei ist eine hervorragende Kandidatin für den Import in die unterschiedlichsten Anwendungen zur weiteren Verarbeitung.

Und damit zu dem Skript. Dieses benötig klarerweise einige Angaben: Nach welchen URLs in den Suchergebnissen gesucht werden soll; wo diese Suchergebnisse zu finden sind und wohin das CSV-File zu schreiben ist. Das meiste davon habe ich in dem Beispielskript fest kodiert - lediglich welches Unterverzeichnis in den Ergbnissen durchsucht werden soll wird beim Aufruf mitgegeben.

Damit das Skript ordentlich arbeiten kann, müssen beim Ablegen der Suchergebnisse als HTML-Files einige Konventionen eingehalten werden:

  • Das Basisverzeichnis für alle nun folgenden Verzeichnisse ist mit der Variable $basedir anzugeben. Es empfielt sich hier einen absoluten Pfad wie “/Users/Ingo/…./SEO-Monitor” einzusetzen, wenn man das ganze mit einem Scheduler starten will.
  • In dem über die Variable $htmldir definierten Verzeichnis wird je befragtem Server ein eigenes Verzsichnis angelegt, z.B. www.google.ch. Je Tag ist ein eigenes Unterverzeichnis anzulegen im Format yyy-mm-dd.
  • Je Abfrage sind alle Ergebnisseiten zu benamsen wie folgt: Epochensekunden_Uhrzeit_Suchbegriffe_SSeite.html. Also z.B. sind die Ergebnisse 11-20 (zweite Seite) einer Suche nach “foo bar” am 27 Februar 2008 um 15h55 auf google.at in dieser Datei abzulegen: /Users/Ingo/…/SEO-Monitor/google-results/www.google.at/2008-02-27/1204124118_15h55_foo+bar_S2.html

Aus dieser Datei bzw. ihrem Namen werden nun einige Informationen extrahiert: Die Zeit beispielsweise und die Seitennummer aber auch der Suchbegriff und der befragte Google-Server. Sehr wichtig ist die Kombination aus Zeit (Epochensekunden) und Suchbegriffen - diese definieren gemeinsam den Filegroupindex, legen also fest, welche Dateien zu einem bestimmten Suchbegriff und Zeitpunkt angelegt wurden. Alle Ergebnisse einer Filegroup werden dann in einer Zeile der ausgegeben CSV zusammengefasst!

Beispiel: Diese Dateien gehören zu ein und der selben Filegroup die den Namen “1204124118_foo+bar” trägt:

1204124118_15h55_foo+bar_S1.html
1204124118_15h55_foo+bar_S2.html
….
1204124118_15h55_foo+bar_S100.html

Je wie oft nun die gesuchten URLs in den Suchergebnissen vorkommen, findet sich dann in einer Zeile des ausgegeben CSV-Files.

Das Skript durchsucht in seinem Hauptteil nun Token für Token jeder Datei. zunächst wird der Suchbegriff extrahiert. (Dieser ist zwar auch im Dateinamen zu finden, aber wir nehmen lieber den aus der Datei). Dann wird gesucht:

  • Auf Seite 1:
  • Anzeigen rechts, hier gibt es das Tag “<a id=an1, …” - das ist praktisch, denn die Nummer gibt die Position wieder. Ablegen in einen Hash (%ad_pos) mit dem Filegroupindex als Schlüssel.
  • Anzeigen oben, hier gibt es das Tag “<a id=pa1, …” - siehe oben. Ablegen in einen Hash (%tad_pos) mit dem Filegroupindex als Schlüssel.
  • Auch wenn es unwahrscheinlich ist, dass die selbe URL in den Anzeigen auf Seite 1 mehrfach vorkommt, so wird doch vom Skript sichergestellt, dass die jeweils beste Position erhalten bleibt.
  • Auf Seite 1 und allen folgenden Seiten
    • Die Tags der Suchergebnisse; wenn href und class=l, dann in diesem Tag nach den URLs suchen; das jeweils beste Position wird in einen Hash (%s_pos) mit dem Filegroupindex als Schlüssel abgelegt.

    Es werden also Anzeigen auf den Seiten 2-100 ignoriert - das entspricht aber dem normalen Userverhalten - wer schaut schon auf Seite 2 auf eine Anzeige?!

Sonst ist noch anzumerken, dass natürlich mehrere URLs gesucht werden können, z.B. apartments-wien.at und apartments-vienna.at - die jeweils beste Position wird in der Ausgabe angezeigt. Das ist sinnvoll, da so manche Organisation ja den selben Webauftritt unter verschiedenen URLs anbietet.

Am Ende des Skriptes wird dann ermittelt, welche Dateigruppen es gab - diese landen in einem Array namens @uFGIs (uniq FileGroupIndices). Dessen Elemente werden dann der Reihe nach in die Hashes %ad_pos usw. eingesetzt und so das CSV-File geschrieben.

That’s it. Zur Auswertung dieses CSVs dann wann anders.

P.S. Ja der Quellcode, den veröffentliche ich demnächst hier:

http://ingo.lantschner.name/Nagios.html

h1

SEO-Monitoring 2: Daten sammmeln

20. Februar 2008

Wie beschrieben, das Ziel ist über jene Schnittstelle, die auch der Benutzer einsetzt - also einen Webbrowser - zu erfassen, was Google bezüglich bestimmter Suchergebnisse anzeigt. Dies erledigt das Skript get_google.pl:

#!/usr/bin/perl -w
# get_google.pl -  query Google.at und speichere Ergebnis in eine Datei
# Rev. 0.6a # Copyright 2008 by Ingo Lantschner (ingo@boxbe.com)  # http://ingo.lantschner.name   # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.   # You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.   use strict;
use LWP::UserAgent;
use URI::Escape ('uri_escape');
use Time::localtime;
my $debug =1;
my @search = (	"foo+bar",
		"foo",
		"bar",
		); ## Suchbegriff hier!
my $path_prefix = "./google-test";
my $heute = localtime;
my $epochensekunden = time();
my $browser = LWP::UserAgent->new;
$browser->agent("Mozilla Firefox");

# Verzeichnis anlegen ( ./<path_prefix>/JJJJ-MM-TT/)
chdir "/Users/ingo/Sites/seo/SEO-Monitoring/Versuch2"; # wegen Aufruf durch Apple-Skript
my $datum = sprintf("%04d-%02d-%02d", $heute->year+1900, $heute->mon+1, $heute->mday);
printf "$datumn" if $debug > 1;
my $path = $path_prefix . "/" . $datum;
print "$pathn" if $debug > 1;
if ( -d $path ) {
	printf "Info: Verzeichnis $path existiert schon.n" if $debug > 0;
} else {
	mkdir $path
	  or die "Fehler: Kann Verzeichnis $path nicht anlegen: $!";
}

foreach	(@search) {
	print "nSuchberiff: $_n" if $debug > 1;
	my $store = $path . "/" . "$epochensekunden" . "_" . $heute->hour . "h" . $heute->min . "_" . "$_";
	my $i = 0; # Zähler für Seiten
	while ( ++$i < 11 ) {
		my $file = $store . "_S$i.html"; # Seitennummer an Dateiname anhängen
		print "Dateiname: $filen" if $debug > 0;
		if ( $i == 1 ) { # Seite 1
			my $response = $browser->get(
		  		'http://www.google.at/search?hl=de&q=' .
				uri_escape($_) .
				'&btnG=Suche&meta=',
				':content_file' => $file,
			);
			die "Error: ", $response->status_line
			 unless $response->is_success;
		} else { # Seiten 2 bis ... (http://www.google.at/search?q=apartment+wien&hl=de&start=10&sa=N)
			my $start = ($i - 1) * 10; # Startzahl: 10, 20, ... 100
			print "Start: $startn" if $debug > 1;
			my $response = $browser->get(
		  		'http://www.google.at/search?q=' . uri_escape($_) . '&hl=de&start=' . $start . '&sa=N',
				':content_file' => $file,
			);
			die "Error: ", $response->status_line
			 unless $response->is_success;
			}

		my $wartezeit = 6; # Warten nächste Seite
		print "Wartezeit auf nächste Seite $i: $wartezeitn" if $debug > 1;
		sleep $wartezeit;
	}
	my $wartezeit = 8; # Warten nach Suchbegriffwechsel
	print "Wartezeit zum nächsten Suchbegriff: $wartezeitn" if $debug > 1;
	sleep $wartezeit;
}

Hinweis: Vor dem Einsatz dieses Scripts, ist die Erlaubnis dazu von Google einzuholen!

Als Ergebnis erhalten wir im Verzeichnis, das mit

my $path_prefix = "./google-test";

definiert wurde jeden Tag ein neues Unterverzeichnis, das dann mit den HTML-Files gefüllt wird: Jede Abfrage (also jeweils 10 Suchergebnisse) in einer Datei. Das ist dann zum Parsen zwar eine echte Herausforderung, dafür hat diese Methode den Vorteil, dass sie auf den Voreinstellungen für Google beruht und daher die “User-Experience” der meisten Benutzer exakt wiedergibt. Klar wäre es verlockend gewesen, sofort 100 Ergebnisse im Google anzeigen zu lassen. Nur verändert Google das Ranking auch abhängig davon, wie viele Ergebnisse je Seite man anzeigen lässt. Daher diese etwas mühsamere Methode.

Ausgewertet (parsing der HTML-Files) wird mit einem anderen Modul - diese Trennung halte ich für wichtig, weil so jederzeit auf die historischen Daten noch einmal zurück gegriffen werden kann.

h1

OS X: Perl-Skripts automatisch starten

20. Februar 2008

Eine sehr einfache Möglichkeit um Perl-Programme oder andere Skripts regelmäßig und vor allem automatisch zu starten, ist dies dem iCal zu überlassen. Die Erinnerungsfunktion des iCal erlaubt die Ausführung eines Apple-Skripts (*.scpt) und von diesem aus wäre dann das Perl Skript aufzurufen. iCal als Task-Scheduler (Cron-Ersatz)

Das zugehörige Apple-Skript, um ein Perlskript zu starten ist sehr kurz und schmerzlos zu erstellen, wenn man alles in eine Zeile schreibt - dies muss man natürlich mit dem Apple-eigenen Script-Editor machen und dann als z.B. get_google.scpt abspeichern:

do shell script "/usr/bin/perl /Users/ingo/Sites/SEO-Monitoring/get_google.pl"

Mir war nicht klar, in welchem Verzeichnis dieses Skript startet, welches also das Arbeitsverzeichnis ist. Daher verwende ich absolute Pfade im Apple-Skript und im Perlskript spring ich erst einmal per chdir in das von mir beabsichtigte Verzeichnis:

#!/usr/bin/perl -w
# get_google.pl -  suche in Google.at und speichere Ergebnis in eine Datei ...
chdir "/Users/ingo/Sites/SEO-Monitoring"; # wegen Aufruf durch Apple-Skript ...
h1

SEO-Monitoring 1: Grundlagen

19. Februar 2008

Platzierung im Google systematisch beobachten - Professionelles Monitoring für Whitehat-SEOs

Die letzten Wochen habe ich mich damit beschäftigt, Webseiten in der wohl wichtigsten Suchmaschine auffiindbar zu machen. Zu den veschiedenen Techniken und was davon erlaubt und was unerwünscht ist, existieren jede Menge Artikel im Netz - ich gehe hier auf dieses Thema nicht weiter ein.

Was mir gefehlt hat, war eine Möglichkeit, die Fortschritte und Rückschläge meiner Arbeit systematisch protokoliert zu haben und sie so auswerten zu können.

Auf Grund meiner Kenntnisse in Nagios und Perl, war es naheliegend diese Werkzeuge einzusetzen. Bei der Frage, wie ich an die Ergebnisse der Suchmaschine herankomme entschied ich mich letztendlich für Abfragen mittels Perlskript und LWP. Die von Google angebotenen Schnittstelle Ajax ist mir zu riskant, denn ich will die Rohdaten so bekommen, wie sie ein Benutzer auch sieht, der die Suchbegriffe in Google eintippt. Übrigens: Google möchte nicht, dass seine Server automatisiert abgefragt werden, ohne dass man sich dazu vorher die Erlaubnis holt. Das sollte man bedenken und es ist sicher sinnvoll, bezüglich der Häufigkeit der Abfragen Maß zu halten und die sleep-Funktion einzusetzen.

Aufbau:

Das System besteht aus zwei Teilen:

1. get_google.pl speichert die Ergebnisse der Abfragen als HTML-Dateien auf Festplatte. Abgefragt werden die ersten 100 Ergebnisse um den Fortschritt bei der Optimierung verfolgen zu können.

2. parse_google.pl liesst diese Dateien aus, sucht die zu überwachenden URLs und erstellt eine CSV-Datei mit Zeit und der Platzierung dieser URL. Berücksichtigt werden sowohl die Anzeigen (falls jemand Google-Ads verwendet) und die Suchergebnisse.

3. Eine dritte Komponente sollte erlauben, Änderungen an den optimierten Seiten und Google-Add-Kampagnen mit Zeitstempel zu erfassen um diese dann in die aus 2.) erstellten Grafiken und Übersichten einblenden zu können.

Soviel für heute, Details folgen demnächst.

h1

iMovie-Export: ohne Kammeffekte

15. November 2007

Scharfe Titel hab ich ja schon - aber wie bekomme ich diese Kämme an den Konturen weg?

Vorab: Die kammartigen Verzerrungen an den Konturen bewegter Objekte sind nur am Computermonitor zu sehen, nicht am Fernseher. Warum? Weil der Computermonitor so gut ist, dass er diese Abweichungen anzeigt. Das Problem entsteht daraus, dass DV ein interleaced-Format ist, also Halbbilder abspeichert, die dann wiederum zusammengesetzt werden müssen. Progressive, im Gegensatz zu interleaced, Formate speichern ganze, also vollständige Bilder (genauer Frames) ab - und die sehen gut aus, am Computer genauso wie am TV.

Also wie bekomme ich progressive Bilder im Export? Die Option dazu versteckt sich ganz hinten im untersten Untermenü zur Größe der Frames und nennt sich “Videoquelle (Deinterleaced)“. Mangelns Kontext und Doku zu dieser Option, kann ich nur raten, dass damit dem Exporter von iMovie gesagt wird, dass die PAL-Halbbilder zu ganzen Frames zusammengesetzt werden sollen. Frage man mich bitte nicht, warum das nicht Standard ist!

iMovie-Export: Übersicht iMovie-Export: Videoeinstellungen

 Deinterleace

Das Ergebnis der obigen Bildschirmschüsse war ein 2,5 GB großes Video-File für den 12 Minuten Film, das sowohl gestochen scharfe Titel-Schriften, als auch Kammeffekt-freie Bewegtszenen zeigte. Schön!

http://www.foolishpassion.org/vidding-tips/interlacing-video.html