Archive for the ‘SEO’ Category

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. http://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

Advertisements
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

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.