// der php hacker

// archiv

Hausgemachte Twitter Services

Geschrieben am 07. Mai 2009 von Cem Derin

Ich habe es schon oft gesagt, und ich sage es hier und jetzt wieder: Twitter ist für mich die nächste Evolutionäre Stufe einer Symbiose aus Web 2.0 und IRC. Ich persönlich nutze Twitter heute, wie ich damals das IRC verwendet habe. Man “idlet” vor sich hin, kommt zu jeder Tages- und Nachtzeit schnell mit jemandem ins Gespräch, wenn man nur einen Kommentar in den Raum wirft. Man hält gemeinsamen Kontakt zu Freunden, Bekannten und Gleichgesinnten. Twitter ist da im Grunde nicht anders.

Das IRC habe ich aber auch zu anderen Zwecken benutzt: Bots haben für mich Währungen umgerechnet, Fremdsprachen übersetzt, mich mit neusten News Informiert. All das geht auch mit Twitter. Und wenigstens die letzten beiden Beispiele sind schon umgesetzt worden. Erinnert also frappierend an das frühere IRC. Warum also Twitter nicht mit Mehrwert anreichern, wenn man den Dienst ohnehin schon exzessiv nutzt.

Ich möchte euch heute eine Anleitung und Anregung an die Hand geben, mit der ihr euch schnell und einfach selbst Twitter-Dienste auf eure persönlichen Bedürfnisse zugeschnitten bauen könnt.

Unser Anwendungsfall

Für meinen Twitter-Account verwende ich den Dienst RSSFriends. Mit diesem Dienst erhalte ich einen RSS Feed, in dem ich informiert werde, wenn mir eine neue Person folgt, wenn eine Person aufhört mir zu folgen. Der Dienst bietet noch mehr Informationen, aber wir belassen es zunächst einmal dabei.

Ich möchte diesen Feed nun auswerten, um mir einen Bot zu schreiben, der mich via Twitter Informiert, wenn mir ein Benutzer aufhört zu folgen und mit einen Link zu meinem zu diesem Zeitpunkt letzten Tweet mitschickt. Damit möchte ich einen Eindruck davon bekommen, was Leute dazu veranlasst, mir nicht weiter zu folgen.

So weit so gut. Ich würde sagen: Frisch ans  Werk.

Einen Bot registrieren

Vermutlich bin ich einer der wenigen Twitter Power-User, der tatsächlich nur einen Account besitzt (ok, es sind in Wirklichkeit zwei: Ich habe einen für mein Blog registriert. Den nutz eich zwar nicht, will ich hierfür aber auch nicht verwenden). Aus diesem Grund lege ich mir einen neuen Account für meinen Bot an: @cemoboter. Ich folge mit dem Bot meinem persönlichen Account und mein persönlicher Account dem Bot. So kann ich im Bedarfsfall auch persönliche Nachrichten hin und herschicken.

Das Script

Natürlich verwende ich, wie wäre es auch anders zu erwarten, mal wieder das Zend Framework. Das Grundscript ist recht simpel: Ich baue eine Verbindung zu Twitter mit dem Zugang meines Bots auf. Ich lese die letzte Nachricht aus, ermittle den Zeitpunkt der selbigen und wandle das Datum in einen Unix-Timestamp um. Startet unser Bot zum ersten mal, wird der Zeitstempel auf den aktuellen Zeitpunkt gesetzt.

<?php
	include 'Zend/Service/Twitter.php';
	include 'Zend/Feed/Rss.php';

	$bot = new ArrayObject();
	$bot->username 	= 'cemoboter';
	$bot->password 	= 'xxx';
	$bot->notify 	= 'unset';

	$twitterBot = new Zend_Service_Twitter($bot->username, $bot->password);
	$lastUpdate = $twitterBot->status->userTimeline(array('count' => 1))->getIterator();
	$time = strtotime($lastUpdate->status->created_at);

	if(!$time) {
		$time = time();
	}
?>

Wir werden nach jedem (erfolgreichen) Durchlauf des Bot-Scriptes eine Meldung in unsere Timeline absetzen. Damit müssen wir keine eigenen Daten pflegen.

Follow/Unfollow-Feed auslesen

Zum auslesen des Feeds stellt das Zend Framework uns eine tolle Klasse bereit: Zend_Feed_Rss. Die Benutzung ist denkbar einfach:

	$followFeed = new Zend_Feed_Rss(
		'http://rssfriends.com/followers/'.
		$bot->notify
	);

Der Feed sagt uns allerdings nicht nur, wer uns nicht mehr folgt, sondern auch wer uns nun begonnen hat zu folgen. Das interessiert uns an dieser Stelle allerdings nicht. Aus diesem Grund prüfen wir im folgenden Code, ob es sich um ein “unfollow” handelt. Außerdem prüfen wir bei jedem Eintrag im Feed, ob wir uns noch zeitlich noch nach dem letzten Durchlauf befinden. Ist das nicht mehr der Fall, brechen wir die foreach-Schleife ab.

	foreach($followFeed as $entry) {
		$pubTime = strtotime($entry->pubTime());
		if($pubTime < $last) {
			break;
		}

		if(strstr($entry->title(), 'Unfollow')) {
			$info = split(' ', $entry->title);
			echo '@unset: '. $info[1]. ' folgt dir nicht mehr. Du hast nun '. $info['2']. ' Follower.';
			echo PHP_EOL;
		}
	}

Der “böse Tweet”

Wir wollen aber wissen, welcher Tweet den Ausschlag gegeben hat. Dazu lesen wir unsere Timeline aus, und ermitteln den letzten Tweet, bevor der Benutzer sich entschied uns nicht mehr zu folgen. Aber Achtung: Das ist nur eine Vermutung: Der Benutzer könnte einen viel früheren Tweet als ausschlaggebend empfunden haben. Vor allem, wenn man in kurzer Zeit mehrere Tweets abgesetzt hat, kann dies der Fall sein. Aber zumindest hat man einen ungefähren Zeitpunkt.

	foreach($followFeed as $entry) {
		$pubTime = strtotime($entry->pubTime());
		if($pubTime < $last) {
			break;
		}

		if(strstr($entry->title(), 'Unfollow')) {
			$theBadTweet = null;
			foreach($twitterBot->status->userTimeline(
				array('id' => $bot->notify)
			)->status as $status) {
				$tweetTime = strtotime($status->created_at);
				if($tweetTime < $pubTime) {
					$theBadTweet = 'http://twitter.com/'.
									$bot->notify.'/statuses/'.
									$status->id;
					break;
				}
			}

			$info = split(' ', $entry->title);
			if(!$theBadTweet) {
				echo 	'@'. $bot->notify.': '.
						$info[1].
						' folgt dir nicht mehr. Du hast nun '.
						$info['2'].
						' Follower.';
				echo PHP_EOL;
			} else {
				echo 	'@'. $bot->notify.': '.
						$info[1].
						' folgt dir nicht mehr seit '.
						$theBadTweet.
						'. Du hast nun '.
						$info['2'].
						' Follower.';
				echo PHP_EOL;
			}
		}
	}

Nun wird unser Script ausgaben machen, wenn es im Feed Einträge für verlorene Follower gibt. Nun wollen wir die Meldungen aber direkt an Twitter senden und einen Tweet absetzen, wenn das Script durchgelaufen ist. Ein Tweet ist einfach abgesetzt:

	$twitterBot->status->update('Beep!');

Twitter ist aber nicht doof. Tweets, die mit exakt dem gleichen Inhalt hintereinander abgesetzt werden, nimmt Twitter nur einmal an. Daher ergänzen wir das ganze um die aktuelle Zeit. Unser Script sollte also nun ungefähr so aussehen:

	include 'Zend/Service/Twitter.php';
	include 'Zend/Feed/Rss.php';

	$bot = new ArrayObject();
	$bot->username 	= 'cemoboter';
	$bot->password 	= 'xxx';
	$bot->notify 	= 'unset';

	$twitterBot = new Zend_Service_Twitter(
		$bot->username,
		$bot->password
	);

	$lastUpdate =
		$twitterBot->
		status->
		userTimeline(
			array('count' => 1)
		)->
		getIterator()
	;
	$last = strtotime($lastUpdate->status->created_at);

	if(!$last) {
		$last = time();
	}

	$followFeed = new Zend_Feed_Rss(
		'http://rssfriends.com/followers/'.
		$bot->notify
	);

	foreach($followFeed as $entry) {
		$pubTime = strtotime($entry->pubDate());
		if($pubTime < $last) {
			break;
		}

		if(strstr($entry->title(), 'Unfollow')) {
			$theBadTweet = null;
			foreach($twitterBot->status->userTimeline(
				array('id' => $bot->notify)
			)->status as $status) {
				$tweetTime = strtotime($status->created_at);
				if($tweetTime < $pubTime) {
					$theBadTweet = 'http://twitter.com/'.
									$bot->notify.'/statuses/'.
									$status->id;
					break;
				}
			}

			$info = split(' ', $entry->title);
			if(!$theBadTweet) {
				$message=	'@'. $bot->notify.': '.
							$info[1].
							' folgt dir nicht mehr. Du hast nun '.
							$info['2'].
							' Follower.';
			} else {
				$message= 	'@'. $bot->notify.': '.
							$info[1].
							' folgt dir nicht mehr seit '.
							$theBadTweet.
							'. Du hast nun '.
							$info['2'].
							' Follower.';
			}
			$twitterBot->status->update($message);
		}
	}

	$twitterBot->status->update('Beep @ '. date('H:i:s'));
	$twitterBot->accountEndSession();

Job einrichten

Nun kommen wir zu dem Teil, wo einige sicherlich in die Röhre gucken müssen: Das einrichten eines Cron Jobs für das Script. Das einrichten möchte ich hier nicht erläutern, aber ein paar Worte zum Intervall: Die Twitter-API gestattet 100 Calls pro Stunde. Jeder Abruf der API entspricht einem Call. Ich habe das Script testweise so eingerichtet, dass es alle 15 Minuten ausgeführt wird. Das sollte genug Platz schaffen, selbst wenn wir einen Haufen Follower innerhalb weniger Minuten verlieren.

Download

Wer möchte kann sich das Script hier herunterladen. Beachtet bitte, dass ihr das Zend Framework in der Version 1.7.8 benötigt.

Geschrieben in Allgemein Kommentieren

// kommentieren

// senden
theme von mir, software von wordpress, grid von 960 grid system. funktioniert in allen browsern, aber der safari bekommt das mit der schrift am schönsten hin.