Mit urllib nur bestimmten Teil auslesen?

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Benutzeravatar
Schaf220
User
Beiträge: 113
Registriert: Montag 11. August 2008, 16:00
Wohnort: Bremen
Kontaktdaten:

Hallo liebe Community,
ich weiß leider nicht mehr weiter. Also möchte ein Logfile auslesen. Das Log ist aber nur online zu bekommen. Deshalb lade ich es mit urllib2 versucht. Das geht ja noch gut, aber es ist meist 2 MB groß und ich möchte zum Beipsiel nur die letzten 100 KB auslesen, damit nur das neu hinzugekommende Material übernommen werden kann. Das Log ist keine HTML-Seite. Es ist eine *.log. Naja der Inhalt wird jedenfalls im Browser angezeigt, ist halt nur Text, deshalb kommt ein HTML-Parser nicht in Frage denke ich. Habt ihr vieleicht eine Idee, wie ich die letzten 100 KB aus dem Log downloaden kann?

Zurzeit lade ich noch alles runter und prüfe die Zeilen bis der neue Teil anfängt, das dauert schon einige Zeit.
PS: (Das ist alles nur Quick und Dirty)

Code: Alles auswählen

#! /usr/bin/env python
# -*- coding: utf-8 -*-

from urllib2 import urlopen 
from sqlite3 import dbapi2 as sqlite

class LogFileSaver(object):
    
    def __init__(self):
        self.logList = []
        self.dbNameNew = "BO_SKSB.sqlite"
        self.__conNewDB = sqlite.connect(self.dbNameNew)
        self.__curNewDB = self.__conNewDB.cursor()
        self.serverID = 1
        self.link = "http://logs.gameservers.com/173.199.108.158:3074/8d3be2c0-1a32-4ebd-9d1c-b387024f28cf" 
        self.lastGameDiff = 1000 # Differenz von der maximalen Anzahl der Spiele
                     
    def getLog(self):
        f = urlopen(self.link)
        self.__curNewDB.execute('SELECT SLastGame FROM bous_server WHERE ID=' + str(self.serverID))
        lastGame = self.__curNewDB.fetchone()[0]
        line = f.readline()
        while line:
            pos1 = line.find(":")                    
            gameCounter = int(line[:pos1]) # gamecounter
            if gameCounter < (lastGame-self.lastGameDiff):
                print "ServerRestart"
                self.logList.append(line)
            elif gameCounter < lastGame:
                print "Warte bis an richtiger Stelle"
            elif gameCounter > lastGame:
                    print "Neue Daten!"
                    self.logList.append(line)
            elif gameCounter == lastGame:
                pass
            else:
                self.logList.append(line)
            
            self.__conNewDB.commit()
            line = f.readline()
        self.__curNewDB.execute('UPDATE bous_server SET SLastGame = ' + str(gameCounter) + 'WHERE ID =' + str(self.serverID))

if __name__ == "__main__":
    log = LogFileSaver()
    log.getLog() 
Zuletzt geändert von Schaf220 am Sonntag 23. Januar 2011, 16:47, insgesamt 1-mal geändert.
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Hallo,

ich habe jetzt auch nur auf die Schnelle und aus Interesse nachgesehen. So wie es sich mir darstellt, musst du das explizit über den HTTP-Header machen:

Code: Alles auswählen

import urllib2

url = "http://logs.gameservers.com/173.199.108.158:3074/8d3be2c0-1a32-4ebd-9d1c-b387024f28cf"

req = urllib2.Request(url)
req.add_header("Range", 'bytes=-1025')
f = urllib2.urlopen(req)
print f.read(1024)
Allerdings war bei meiner Quelle dieser mögliche negative Wert für das Feld "Range" gar nicht dokumentiert. Es scheint aber zu funktionieren.

Besten Gruß,

brb
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Barabbas hat geschrieben:Allerdings war bei meiner Quelle dieser mögliche negative Wert für das Feld "Range" gar nicht dokumentiert. Es scheint aber zu funktionieren.
Es handelt sich ja auch um "Range", nicht "Content-Range" (wie verlinkt). Gueltige Werte fuer Range sind "Byte Ranges" und die geben den Fall sogar explizit als Beispiel an:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1 hat geschrieben:Examples of byte-ranges-specifier values (assuming an entity-body of length 10000):
...
- The final 500 bytes (byte offsets 9500-9999, inclusive):
bytes=-500
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Nebenbei: Man sollte niemals normale String-Konkatenierungstechniken bei SQL-Queries nutzen. Stichwort SQL Injection!

Code: Alles auswählen

# falsch
        self.__curNewDB.execute('SELECT SLastGame FROM bous_server WHERE ID=' + str(self.serverID))
# richtig
        self.__curNewDB.execute('SELECT SLastGame FROM bous_server WHERE ID=?', (self.serverID,))
Selbiges gilt natürlich auch für die "update"-Stelle ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Schaf220
User
Beiträge: 113
Registriert: Montag 11. August 2008, 16:00
Wohnort: Bremen
Kontaktdaten:

Vielen Dank für die Hilfe, es hat mir wirklich sehr geholfen!
BlackJack

@Schaf220: Warum ist das eigentlich eine ``while``-Schleife mit `readline()`-Aufrufen und keine ``for``-Schleife über `f`?

Und das mit dem `commit()` sieht komisch aus. Was Du da eventuell mehrfach "committest" ist das 'SELECT' von *vor* der Schleife. Das würde ich wenn es denn nötig sein sollte direkt vor der Schleife nach dem 'SELECT' machen und dann halt auch nur einmal.

Dafür fehlt augenscheinlich ein `commit()` nach dem 'UPDATE'.

Ansonsten sehen die Namensschreibweisen und die doppelten Unterstriche irgendwie so aus, als wenn da nicht in Python programmiert werden sollte. Die Namen sind auch nicht immer gut gewählt. `f` ist zum Beispiel zu kurz, `logList` enthält den Datentyp, und `__curNewDB` ist eine kryptische Abkürzung.
Antworten