Web scraping mit Ruby/Mechanize

Praktisch jede Interaktion mit einer Website oder Webapplikation kann gescriptet, d.h. automatisiert werden. Das Abgrasen von Webseiten nach bestimmten Informationen wird auch als Scraping bezeichnet(für die nicht menschlichen Besucher dieser Seite sei das erwähnt *g*) Scripte können einem eine ganze Menge Arbeit abnehmen und sogar Dinge tun, die manuell unmöglich wären. Ich beschäftige mich mit dem Thema schon seit einer ganzen Weile und möchte hier nun die von mir favorisierte Methode dafür vorstellen, die Bibliothek Mechanize für die Scriptsprache Ruby.

Mechanize hat seinen Ursprung in Perl, mittlerweile gibt es jedoch auch Implementierungen der API für Python und eben Ruby. Für PHP gibt es mit Snoopy ein ähnliches Projekt, wenn es auch bei weitem nicht so fortgeschritten ist. Mechanize bietet die Möglichkeit mit einfachen Methoden eine art Webbrowser zu simulieren. Alle Beispiele wurden mit Mechanize Version 0.9.2 und Ruby 1.8.7 getestet.

Installation / Initialisierung

Mechanize kann mit Gems(ähnlich CPAN oder PEAR) installiert werden(# gem install mechanize --remote), einige Distributionen bieten aber auch eigene Pakete an. Ein Ruby-Script kann daraufhin Mechanize inkludieren und ein Objekt erstellen:

require 'rubygems' # ist unter Umständen notwendig
require 'mechanize'
agent = Mechanize.new

Jetzt ist Mechanize einsatzbereit, die folgenden Beispiele bauen darauf auf. Außerdem können mit dem agent nun noch grundlegende Einstellungen vorgenommen werden:

agent.set_proxy('localhost', '8000')
agent.user_agent = 'Individueller User-Agent'
agent.user_agent_alias = 'Linux Mozilla'

Die Einstellung ‘user_agent_alias‘ wählt einen User-Agent String aus dem folgenden Satz von Beispielen aus: Windows IE 6, Windows IE 7, Windows Mozilla, Mac Safari, Mac FireFox, Mac Mozilla, Linux Mozilla, Linux Konqueror, iPhone und Mechanize. Die Timing Einstellungen können ebenfalls sehr wichtig sein:

agent.open_timeout = 3 # setzt timeouts
agent.read_timeout = 4
agent.keep_alive = false # default ist true

Hier folgen nun einige Beispiele, vielleicht werde ich mit der Zeit auch noch ein paar ergänzen, falls jemand Vorschläge hat, immer her damit. Ich habe auf http://apoc.sixserv.org/requestinfo ein kleines Skript am laufen das nützliche Informationen zum HTTP-Request liefert, das kann zum Experimentieren mit Mechanize sehr nützlich sein. Einige Beispiele findet man auch in den GUIDE und EXAMPLES Dateien des Mechanize Pakets. Continue reading

Soup.io rbot Plugin/ ruby API

Mit Twitter kann ich sehr leicht über meinen rbot publizieren, damit ich in der selben Frequenz auch soup.io verwende, was für spezielleren Content besser geeignet ist, muss es schon ebenfalls über den rbot funktionieren. Nach langem suchen stellte ich überrascht fest das das große Web 2.0 Projekt Soup.io keine API zum leichten publizieren(außerhalb des Browsers) besitzt. Da muss also erstmal eine art API gestrickt werden. Mit Hilfe von Mechanize baute ich die Browseranfragen nach und fasste es in einer kleinen Ruby Klasse zusammen. Es wird nicht jeder Content-Typ unterstützt aber für meine Zwecke reicht dies völlig aus. Dann noch schnell eine rbot-Plugin Klasse zum bedienen der eigenen “API” und fertig war die erste Version meines soupio-Plugins.
Hier eine Liste der möglichen Befehle(Argumente in eckigen Klammern sind Optional):

soup identify   => Jeder Benutzer im Channel kann dem Bot seine 
Soup.io-Zugangsdaten im Query mitteilen.

soup login => Neuer Login falls die gespeicherte SessionId verloren 
oder ungültig wird. (Normalerweise nicht notwendig.)

soup link  []
soup image <url> [<description>]
soup text <text>
soup quote <source>: <quote>
soup video <youtube-url> [<description>]</pre>
<p>Die SoupIoClass-Klasse kann übrigens auch außerhalb des Plugins, in jeder Ruby-Anwendung verwendet werden. Hier eine kleine Referenz, diesmal die optionalen Argumente in spitzen Klammern:</p>
<pre lang="ruby" line="1">soup = SoupIoClass.new('[Username]', '[Password]'<, '[Domain]', '[Session-ID]'>)
soup.new_link '[URL]'<, '[Title]', '[Description]'>
soup.new_image '[URL]'<, '[Description]'>
soup.new_text '[Text]'<, '[Title]'>
soup.new_quote '[Quote]'<, '[Source]'>
soup.new_video '[Youtube-URL]'<, '[Description]'></pre>
<p>Die Domain und SessionId kann mit soup.sessid und soup.domain abgefragt werden. Die SessionId ist praktisch unbegrenzt lange haltbar, weshalb diese beiden Daten zwischengespeichert werden können um bei häufiger Nutzung der Klasse sich nicht ständig neu Anmelden zu müssen.</p>
<p>Die Version 0.1 ist bereits <a href="http://rbot.noway.ratry.ru/plugins/show/19">veröffentlicht</a>, ich muss mich noch um die Validierung und Fehlerabfragen kümmern aber sonst sollte das Plugin schon funktionieren. Fehler bitte bei mir Melden.<br />
<strong>Update:</strong> Version 0.2 veröffentlicht. (nur kleine Änderungen)<br />
<strong>Update:</strong> Version 0.3 veröffentlicht. (Bugfix für eigene Domains)<br />
<strong>Update:</strong> <a href="http://rbot.noway.ratry.ru/files/soupio-0.4.rb">Version 0.4</a> veröffentlicht. (Änderungen an soup.io)</p>
					</div><!-- .entry-content -->
		
		<footer class="entry-meta">
												<span class="cat-links">
				<span class="entry-utility-prep entry-utility-prep-cat-links">Posted in</span> <a href="http://sixserv.org/category/code/" rel="category tag">Development</a>, <a href="http://sixserv.org/category/rbot/" rel="category tag">RBot</a>, <a href="http://sixserv.org/category/code/ruby/" rel="category tag">Ruby</a>			</span>
									<span class="sep"> | </span>
							<span class="tag-links">
				<span class="entry-utility-prep entry-utility-prep-tag-links">Tagged</span> <a href="http://sixserv.org/tag/bot/" rel="tag">bot</a>, <a href="http://sixserv.org/tag/code/" rel="tag">Development</a>, <a href="http://sixserv.org/tag/irc/" rel="tag">irc</a>, <a href="http://sixserv.org/tag/plugin/" rel="tag">plugin</a>, <a href="http://sixserv.org/tag/rbot/" rel="tag">RBot</a>, <a href="http://sixserv.org/tag/ruby/" rel="tag">Ruby</a>, <a href="http://sixserv.org/tag/soupio/" rel="tag">soup.io</a>, <a href="http://sixserv.org/tag/web20/" rel="tag">web2.0</a>			</span>
						
									<span class="sep"> | </span>
						<span class="comments-link"><a href="http://sixserv.org/2009/02/11/soupio-rbot-plugin-ruby-api/#comments" title="Comment on Soup.io rbot Plugin/ ruby API"><b>6</b> Replies</a></span>
			
					</footer><!-- #entry-meta -->
	</article><!-- #post-313 -->

				
					
	<article id="post-142" class="post-142 post type-post status-publish format-standard hentry category-code category-linux category-php category-rbot category-ruby tag-hddtemp tag-irc tag-linux tag-networking tag-php tag-plugin tag-rbot tag-ruby tag-sensors tag-xinetd">
		<header class="entry-header">
						<h1 class="entry-title"><a href="http://sixserv.org/2009/01/22/xinetd-info-script/" title="Permalink to xinetd: info script" rel="bookmark">xinetd: info script</a></h1>
			
						<div class="entry-meta">
				<span class="sep">Posted on </span><a href="http://sixserv.org/2009/01/22/xinetd-info-script/" title="20:00" rel="bookmark"><time class="entry-date" datetime="2009-01-22T20:00:29+00:00" pubdate>22. January 2009</time></a><span class="by-author"> <span class="sep"> by </span> <span class="author vcard"><a class="url fn n" href="http://sixserv.org/author/apoc/" title="View all posts by apoc" rel="author">apoc</a></span></span>			</div><!-- .entry-meta -->
			
						<div class="comments-link">
				<a href="http://sixserv.org/2009/01/22/xinetd-info-script/#comments" title="Comment on xinetd: info script">2</a>			</div>
					</header><!-- .entry-header -->

				<div class="entry-content">
			<p>Ich wollte von unterwegs aus den Status meines Heimservers abrufen können. Dabei ging es mir vorallem um die Temperatur von CPU, Mainboard und den Festplatten. Der auf sixserv.org laufende rbot(im Freenode idled der in #sixserv) soll auf Kommando den Status anzeigen. Soweit so gut. Ein kleines Ruby-Skript das auf dem Server zuhause läuft erfasst die Temperaturen per “sensors” und “hddtemp”. Der xinetd-Daemon konfigurierte ich daraufhin so das auf einen Port das Skript gebunden wird. Es erwartet bevor es die Daten übermittelt ein Passwort, einfach zum zusätzlichen Schutz auch wenn das vielleicht gar nicht nötig ist. Jemand der einen Portscan durchführt könnte eben so informationen zum System gelangen, die Passwortabfrage verhindert dies.</p>
<p>Zunächst zu dem Ruby-Script(z.B. /opt/botinfo.rb):</p>
<pre lang="ruby" line="1">#!/usr/bin/ruby

i = Kernel.gets
if i.chomp != 'DASGEHEIMEPASSWORT' then
	# puts 'Wrong Password'
	exit
end

puts `uptime`.lstrip

# HDD Temps:
matches = `cat /proc/partitions`.scan /([s|h]d[a-z])/
matches.uniq!
matches.each do |disk|
	print "#{disk}: #{`hddtemp -n /dev/#{disk}`.chomp}.0*C (#{$1}GB) "
end
puts 

systemp = `sensors`

temp1 = systemp.scan /CPU Temp:    \+([0-9]+)\.0.C/
temp2 = systemp.scan /M\/B Temp:    \+([0-9]+)\.0.C/

puts "System: #{temp2[0]}.0*C #{temp2[1]}.0*C | CPUs: #{temp1[0]}.0*C #{temp1[1]}.0*C"
</pre>
<p>Hier muss natürlich sensors und hddtemp installiert sein, aber dieses Script kann praktisch alles mögliche an Informationen sammeln und ausgeben.<br />
Die Konfiguration von xinetd gestaltet sich sehr einfach, in dem Verzeichnis /etc/xinetd.d einfach eine neue Datei für das Script erstellen(z.B. “botinfo”):</p>
<pre lang="bash" line="1">
service botinfo
{
    disable         = no
    port            = 8888
    socket_type     = stream
    protocol        = tcp
    wait            = no
    user            = apoc
    server          = /opt/botinfo.rb
    type            = unlisted
}
</pre>
<p>Den Port, User und den Skript Pfad entsprechend anpassen und xinetd neu starten. Mit netcat kann es man danach testen:</p>
<pre lang="bash" line="1">$ nc localhost 8888
DASGEHEIMEPASSWORT
18:40:35 up 3 days, 41 min,  4 users,  load average: 0.00, 0.02, 0.20
sda: 30.0*C (10GB) sdb: 29.0*C (10GB)
System: 39.0*C 38.0*C | CPUs: 37.0*C 36.0*C
</pre>
<p>Der Port muss ggf. vom Router geforwarded werden damit ein Entfernter Server darauf zugreifen kann. Auch ein dyndns ist hilfreich, sofern man über keine statische IP verfügt. Ein einfaches rbot-Plugin um diese Daten vom irc aus abzufragen sieht z.B. so aus:</p>
<pre lang="ruby" line="1">require 'socket'

class BotinfoPlugin < Plugin
  def help(plugin, topic="")
    'info => return system information'
  end

  def info(m, params)
    sock = TCPSocket.new('heimserver.dyndns.org', 8888)
    sock.puts('DASGEHEIMEPASSWORT')
    m.reply sock.recv(1024)
    sock.close
  end
end
plugin = BotinfoPlugin.new
plugin.map 'info'
</pre>
<p>Die Daten können ebenfalls von einem PHP-Script aus abgefragt werden. Keines Beispiel:</p>
<pre lang="php" line="1"><?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, "heimserver.dyndns.org", "8888");

$pass = "DASGEHEIMEPASSWORT\n\n";
socket_write($socket, $pass, strlen($pass));

echo socket_read($socket, 2048);
?></pre>
<p>Vielleicht findet das ja irgendjemand interessant <img src="http://sixserv.org/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /></p>
					</div><!-- .entry-content -->
		
		<footer class="entry-meta">
												<span class="cat-links">
				<span class="entry-utility-prep entry-utility-prep-cat-links">Posted in</span> <a href="http://sixserv.org/category/code/" rel="category tag">Development</a>, <a href="http://sixserv.org/category/linux/" rel="category tag">Linux</a>, <a href="http://sixserv.org/category/code/php/" rel="category tag">PHP</a>, <a href="http://sixserv.org/category/rbot/" rel="category tag">RBot</a>, <a href="http://sixserv.org/category/code/ruby/" rel="category tag">Ruby</a>			</span>
									<span class="sep"> | </span>
							<span class="tag-links">
				<span class="entry-utility-prep entry-utility-prep-tag-links">Tagged</span> <a href="http://sixserv.org/tag/hddtemp/" rel="tag">hddtemp</a>, <a href="http://sixserv.org/tag/irc/" rel="tag">irc</a>, <a href="http://sixserv.org/tag/linux/" rel="tag">Linux</a>, <a href="http://sixserv.org/tag/networking/" rel="tag">Networking</a>, <a href="http://sixserv.org/tag/php/" rel="tag">PHP</a>, <a href="http://sixserv.org/tag/plugin/" rel="tag">plugin</a>, <a href="http://sixserv.org/tag/rbot/" rel="tag">RBot</a>, <a href="http://sixserv.org/tag/ruby/" rel="tag">Ruby</a>, <a href="http://sixserv.org/tag/sensors/" rel="tag">sensors</a>, <a href="http://sixserv.org/tag/xinetd/" rel="tag">xinetd</a>			</span>
						
									<span class="sep"> | </span>
						<span class="comments-link"><a href="http://sixserv.org/2009/01/22/xinetd-info-script/#comments" title="Comment on xinetd: info script"><b>2</b> Replies</a></span>
			
					</footer><!-- #entry-meta -->
	</article><!-- #post-142 -->

				
					
	<article id="post-90" class="post-90 post type-post status-publish format-standard hentry category-rbot category-ruby tag-bot tag-drb tag-irc tag-plugin tag-rbot tag-ruby">
		<header class="entry-header">
						<h1 class="entry-title"><a href="http://sixserv.org/2008/09/15/rbot-remote/" title="Permalink to Rbot Remote" rel="bookmark">Rbot Remote</a></h1>
			
						<div class="entry-meta">
				<span class="sep">Posted on </span><a href="http://sixserv.org/2008/09/15/rbot-remote/" title="23:14" rel="bookmark"><time class="entry-date" datetime="2008-09-15T23:14:48+00:00" pubdate>15. September 2008</time></a><span class="by-author"> <span class="sep"> by </span> <span class="author vcard"><a class="url fn n" href="http://sixserv.org/author/apoc/" title="View all posts by apoc" rel="author">apoc</a></span></span>			</div><!-- .entry-meta -->
			
						<div class="comments-link">
				<a href="http://sixserv.org/2008/09/15/rbot-remote/#respond" title="Comment on Rbot Remote"><span class="leave-reply">Reply</span></a>			</div>
					</header><!-- .entry-header -->

				<div class="entry-content">
			<p>Ich setze schon lange den grandiosen IRC-Bot “<a href="http://ruby-rbot.org/">rbot</a>” ein. Ein überaus vielseitiger und einfach zu erweiternder Bot, der dazu auch noch in meiner Lieblings Script-Sprache <a href="http://www.ruby-lang.org/">Ruby</a> geschrieben ist. Vielleicht komme ich dazu einige meiner Plugins, die ich für ihn geschrieben habe, hier zu Veröffentlichen.</p>
<p>Eines der Features von rbot welches ich erst kürzlich entdeckt habe und was absolut genial ist, ist das <a href="http://ruby-rbot.org/rbot-trac/wiki/RbotRemote">Rbot Remote Interface</a>. Per Default hört der Bot nämlich auf Port 7268(127.0.0.1) und stellt dort ein <a href="http://segment7.net/projects/ruby/drb/">DRb(Distributed Ruby)</a> Interface zur Verfügung. Dieses erlaubt es von Außen den Bot zu steuern und beispielsweise Funktionen eines Plugins auszuführen. RbotRemote kann z.B. dazu genutzt werden bei neuen SVN-Commits im RSS Plugin das Updaten eines Commit-Feeds zu starten. Denkbar ist dies natürlich auch für neue Blog-Posts innerhalb von WordPress etc.</p>
<p>Da DRb logischerweise nur für Ruby zur Verfügung steht muss bspw. eine PHP-Webapplikation ein Ruby-Skript starten welches die gewünschte Aktionen am rbot auslöst. Hier als Beispiel-Skript wird eine Nachricht an #sixserv(btw: im Freenode) gesendet:</p>
<pre lang="ruby">#!/usr/bin/ruby

require 'drb'

rbot = DRbObject.new_with_uri("druby://localhost:7268")
id = rbot.delegate(nil, "remote login owner [Owner/Auth Passwort]")[:return]
rbot.delegate(id, "dispatch say #sixserv Hallo Welt!")</pre>
<p>In <a href="http://ruby-rbot.org/rbot-trac/browser/bin/rbot-remote">/bin/rbot-remote</a> gibt es ein ähnliches, etwas komplexeres Beispiel welches die Eingaben von stdin erwartet.</p>
<p>Eine weitere Möglichkeit ist wie schon erwähnt eine Methode eines Plugins zu starten. Hier ein ganz einfaches rbot-(Remote)Plugin:</p>
<pre lang="ruby">class SimplePlugin < RemotePlugin
  include RemotePlugin
  def sayfoo(m, params)
    @bot.say '#sixserv', 'foo'
    if params.has_key?(:bar) then
      @bot.say '#sixserv', params[:bar]
    end
  end
end

plugin = SimplePlugin.new
plugin.remote_map 'sayfoo'
plugin.remote_map 'sayfoo :bar'</pre>
<p>Wird die Methode extern aufgerufen kann man natürlich kein m.reply verwenden, wenn die Nachricht im Channel landen soll, ich habe das hier ganz einfach gelöst indem ich den Channel fest eingebunden habe. Hier noch das Skript welches sayfoo mit Parameter aufruft:</p>
<pre lang="ruby">#!/usr/bin/ruby

require 'drb'

rbot = DRbObject.new_with_uri("druby://localhost:7268")
id = rbot.delegate(nil, "remote login owner [Owner/Auth Passwort]")[:return]
rbot.delegate(id, "sayfoo bar")</pre>
<p>Update: Das Plugin auf remote_map geändert, thanks for the hint tango!</p>
					</div><!-- .entry-content -->
		
		<footer class="entry-meta">
												<span class="cat-links">
				<span class="entry-utility-prep entry-utility-prep-cat-links">Posted in</span> <a href="http://sixserv.org/category/rbot/" rel="category tag">RBot</a>, <a href="http://sixserv.org/category/code/ruby/" rel="category tag">Ruby</a>			</span>
									<span class="sep"> | </span>
							<span class="tag-links">
				<span class="entry-utility-prep entry-utility-prep-tag-links">Tagged</span> <a href="http://sixserv.org/tag/bot/" rel="tag">bot</a>, <a href="http://sixserv.org/tag/drb/" rel="tag">drb</a>, <a href="http://sixserv.org/tag/irc/" rel="tag">irc</a>, <a href="http://sixserv.org/tag/plugin/" rel="tag">plugin</a>, <a href="http://sixserv.org/tag/rbot/" rel="tag">RBot</a>, <a href="http://sixserv.org/tag/ruby/" rel="tag">Ruby</a>			</span>
						
									<span class="sep"> | </span>
						<span class="comments-link"><a href="http://sixserv.org/2008/09/15/rbot-remote/#respond" title="Comment on Rbot Remote"><span class="leave-reply">Leave a reply</span></a></span>
			
					</footer><!-- #entry-meta -->
	</article><!-- #post-90 -->

				
				
			
			</div><!-- #content -->
		</section><!-- #primary -->

		<div id="secondary" class="widget-area" role="complementary">
			<aside id="search-2" class="widget widget_search">	<form method="get" id="searchform" action="http://sixserv.org/">
		<label for="s" class="assistive-text">Search</label>
		<input type="text" class="field" name="s" id="s" placeholder="Search" />
		<input type="submit" class="submit" name="submit" id="searchsubmit" value="Search" />
	</form>
</aside><aside id="categories-206200171" class="widget widget_categories"><h3 class="widget-title">Categories</h3>		<ul>
	<li class="cat-item cat-item-63"><a href="http://sixserv.org/category/books/" >Books</a>
</li>
	<li class="cat-item cat-item-83"><a href="http://sixserv.org/category/censorship/" >Censorship</a>
</li>
	<li class="cat-item cat-item-5"><a href="http://sixserv.org/category/code/" >Development</a>
<ul class='children'>
	<li class="cat-item cat-item-96"><a href="http://sixserv.org/category/code/ccpp/" >C/C++</a>
</li>
	<li class="cat-item cat-item-15"><a href="http://sixserv.org/category/code/java-coding/" >Java</a>
</li>
	<li class="cat-item cat-item-93"><a href="http://sixserv.org/category/code/javascript/" >JavaScript</a>
</li>
	<li class="cat-item cat-item-23"><a href="http://sixserv.org/category/code/php/" >PHP</a>
</li>
	<li class="cat-item cat-item-88"><a href="http://sixserv.org/category/code/python/" >Python</a>
</li>
	<li class="cat-item cat-item-27"><a href="http://sixserv.org/category/code/ruby/" >Ruby</a>
</li>
</ul>
</li>
	<li class="cat-item cat-item-49"><a href="http://sixserv.org/category/hardware/" >Hardware</a>
</li>
	<li class="cat-item cat-item-9"><a href="http://sixserv.org/category/linux/" >Linux</a>
</li>
	<li class="cat-item cat-item-3"><a href="http://sixserv.org/category/meta-talk/" title="Über das Sixserv.org Blog und Sixserv im Allgemeinen.">Meta</a>
</li>
	<li class="cat-item cat-item-7"><a href="http://sixserv.org/category/networking/" >Networking</a>
</li>
	<li class="cat-item cat-item-108"><a href="http://sixserv.org/category/nodejs/" >Node.js</a>
</li>
	<li class="cat-item cat-item-28"><a href="http://sixserv.org/category/rbot/" >RBot</a>
</li>
	<li class="cat-item cat-item-97"><a href="http://sixserv.org/category/sdl/" >SDL</a>
</li>
	<li class="cat-item cat-item-12"><a href="http://sixserv.org/category/torrent/" >Torrent</a>
</li>
	<li class="cat-item cat-item-44"><a href="http://sixserv.org/category/web/" >Web</a>
</li>
	<li class="cat-item cat-item-17"><a href="http://sixserv.org/category/windows/" >Windows</a>
</li>
	<li class="cat-item cat-item-24"><a href="http://sixserv.org/category/wordpress/" >Wordpress</a>
</li>
		</ul>
</aside><aside id="linkcat-2" class="widget widget_links"><h3 class="widget-title">Blogroll</h3>
	<ul class='xoxo blogroll'>
<li><a href="http://geekosphere.org/">teh geek\o/sphere.org</a></li>

	</ul>
</aside>
		<aside id="recent-posts-2" class="widget widget_recent_entries">		<h3 class="widget-title">Recent Posts</h3>		<ul>
					<li>
				<a href="http://sixserv.org/2012/08/15/jquery-svg-ui/">jQuery-SVG UI</a>
						</li>
					<li>
				<a href="http://sixserv.org/2011/02/12/feedability-nodejs-feed-proxy-with-readability/">Feedability: Node.js Feed Proxy With Readability</a>
						</li>
					<li>
				<a href="http://sixserv.org/2010/11/30/live-transcoding-for-video-and-audio-streaming/">Live Transcoding for Video and Audio Streaming</a>
						</li>
					<li>
				<a href="http://sixserv.org/2010/07/26/memory-debugging-or-a-universal-game-trainer-with-python-and-ptrace/">Memory Debugging or a “Universal Game Trainer” with Python and ptrace</a>
						</li>
					<li>
				<a href="http://sixserv.org/2010/05/21/dynamic-loading-of-sdl/">Dynamic Loading of SDL</a>
						</li>
				</ul>
		</aside><aside id="recent-comments-2" class="widget widget_recent_comments"><h3 class="widget-title">Recent Comments</h3><ul id="recentcomments"><li class="recentcomments"><span class="comment-author-link"><a href='http://www.jamescoyle.net' rel='external nofollow' class='url'>James</a></span> on <a href="http://sixserv.org/2010/11/30/live-transcoding-for-video-and-audio-streaming/comment-page-1/#comment-255788">Live Transcoding for Video and Audio Streaming</a></li><li class="recentcomments"><span class="comment-author-link"><a href='https://github.com/sriemer/ugtrain' rel='external nofollow' class='url'>Sebastian Riemer</a></span> on <a href="http://sixserv.org/2010/07/26/memory-debugging-or-a-universal-game-trainer-with-python-and-ptrace/comment-page-1/#comment-146809">Memory Debugging or a “Universal Game Trainer” with Python and ptrace</a></li><li class="recentcomments"><span class="comment-author-link">Bobby Pardridge</span> on <a href="http://sixserv.org/2010/11/30/live-transcoding-for-video-and-audio-streaming/comment-page-1/#comment-100509">Live Transcoding for Video and Audio Streaming</a></li><li class="recentcomments"><span class="comment-author-link">bstd</span> on <a href="http://sixserv.org/2010/11/30/live-transcoding-for-video-and-audio-streaming/comment-page-1/#comment-72032">Live Transcoding for Video and Audio Streaming</a></li><li class="recentcomments"><span class="comment-author-link">impro</span> on <a href="http://sixserv.org/2009/01/24/ivacy-vpn-unter-linux-pptp-und-socks5/comment-page-1/#comment-29927">Ivacy VPN unter Linux: PPTP/OpenVPN und Socks5-Gateway</a></li></ul></aside><aside id="meta-2" class="widget widget_meta"><h3 class="widget-title">Meta</h3>			<ul>
						<li><a href="http://sixserv.org/wp-login.php">Log in</a></li>
			<li><a href="http://sixserv.org/feed/">Entries <abbr title="Really Simple Syndication">RSS</abbr></a></li>
			<li><a href="http://sixserv.org/comments/feed/">Comments <abbr title="Really Simple Syndication">RSS</abbr></a></li>
<li><a href="https://wordpress.org/" title="Powered by WordPress, state-of-the-art semantic personal publishing platform.">WordPress.org</a></li>			</ul>
</aside>		</div><!-- #secondary .widget-area -->

	</div><!-- #main -->

	<footer id="colophon" role="contentinfo">

			

			<div id="site-generator">
								<a href="http://wordpress.org/" title="Semantic Personal Publishing Platform" rel="generator">Proudly powered by WordPress</a>
			</div>
	</footer><!-- #colophon -->
</div><!-- #page -->


</body>
</html>