Dateien herunterladen und in einem Verzeichnis ablegen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Ich wollte das Print aus der Funktion in ein Logfile umleiten. Leider scheint diese Idee falsch zu sein. Ich wollte innerhalb der Funktion das Logging mit logger = initialize_logger() aufrufen. Bitte erklärt mir doch was ich falsch gemacht habe.

Code: Alles auswählen

def fetch_whole_year(symbol, year):     
      logger = initialize_logger()     
      for symbol in symbol:     
          last_week = datetime.date(year, 12, 31).isocalendar()[1]     
          for week in range(1, last_week + 1):     
              try:     
                  if not exists_file(symbol, year, week):     
                      data = pull_file(symbol, year, week)     
                      print_data_length(data)     
                      save_file(symbol, year, week, data)     
              except IOError as e:     
                  print(e)     
                  logger.error(e)     
              else:     
                  print("File for {}/{}/{} already fetched.".format(     
                      symbol, year, week)     
                  )     
                  logger.info("File for {}/{}/{} already fetched.".format(     
                      symbol, year, week)     
                  )     
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Ich habe drei Funktionen, die noch nicht wie gewünscht funktionieren. Bei der Funktion fetch_whole_year ist das Logging nicht richtig implementiert.
In meinen Post davor habe ich meine Idee gezeigt. Hier noch einmal die Funktion ohne das Logging.
Frage: Wie wird das Logging richtig einhebaut? In dieser Funktion soll dann auch die nächste Funktion initialize_logger aufgerufen werden. Wie rufe ich die zweite Funktion initialize_logger in der Funktion fetch_whole_year auf? Sollte die Funktion initilise_logger auch durch diese Funktion aufgerufen werden? Das Absenden der Email sollte dann abschliessend durch die Funktion initialise_logger erfolgen. Nachdem das Logfile geschrieben wurde soll dieses per Email verschickt werden. Ich habe eine Funktion send_email geschrieben. Hier sind noch zwei Fehler zu beheben.
1. Hier rufe ich die Funktion generate_logfile auf. Wie ich aber gelernt habe sollte die Fuktion generate_logfile nicht mehrfach aufgerufen werden. Welche Idee ist richtig?
2. Fehler beim Versenden der Email. Ich bekomme folgende Fehlermeldung:

Code: Alles auswählen


def fetch_whole_year(symbol, year):
    for symbol in symbol:
        last_week = datetime.date(year, 12, 31).isocalendar()[1]
        for week in range(1, last_week + 1):
            try:
                if not exists_file(symbol, year, week):
                    data = pull_file(symbol, year, week)
                    print_data_length(data)
                    save_file(symbol, year, week, data)
            except IOError as e:
                print(e)
            else:
                print("File for {}/{}/{} already fetched.".format(
                    symbol, year, week)
                )


def initialize_logger():
    logfile_name = generate_logfile()
    print(logfile_name)
    ensure_logdir_exists(logfile_name)
    logger = logging.getLogger('Data download')
    logger.setLevel(logging.DEBUG)
    handler = logging.FileHandler(logfile_name)
    handler.setLevel(logging.DEBUG)
    formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    # application' code
    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')

Code: Alles auswählen

def send_email():
    email_user = 'user'
    email_pwd = 'passwd'

    SENDER = 'absender@example.com'
    RECIPIENT = 'empfenger@example.com'

    logfile = generate_logfile()
    fp = open(logfile, 'rb')
    msg = MIMEText(fp.read())
    fp.close()

    msg['From'] = SENDER
    msg['To'] = RECIPIENT
    msg['Subject'] = 'The  logfile from %s' % logfile

    try:
        server = smtplib.SMTP('wpxxxxxx.mailout.server-he.de', '25')
        server.set_debuglevel(True)
        server.ehlo()
        server.starttls()
        server.login(email_user, email_pwd)
        server.sendmail(SENDER, [RECIPIENT], msg.as_string())
        server.close()
        print 'Email send successfully.'
    except:
        print "Failed to send the email."

Code: Alles auswählen

reply: '354 Enter message, ending with "." on a line by itself\r\n'
reply: retcode (354); Msg: Enter message, ending with "." on a line by itself
data: (354, 'Enter message, ending with "." on a line by itself')
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: Du verwendest Logger falsch. Wenn Du logging verwendest, dann brauchst Du nicht auch noch alles per print auszugeben, weil das ja durch eine passende Logger-Konfiguration passieren kann. Innerhalb einer Funktion sollte gar kein spezieller Logger initialisiert werden. Das passiert am Anfang des Hauptprogramms, wo man die Konfiguration auch per Konfigurationsdatei erledigen kann, so dass man bei geänderten Anforderungen ans Logging das Programm gar nicht anfassen muß. Sodann hat normalerweise jedes Modul einen modulweiten logger. Die Log-Meldungen sind falsch. Für Exceptions gibt es logger.exception, das auch den Stacktrace mitloggt. Für erfolgreiche Downloads wird immer "already fetched" ausgegeben, was ja nicht stimmt, wenn die Datei eben noch nicht existiert hat.

Zur Email: Du merkst gar nicht, was falsch läuft, weil Du jede Exception mit einer nichtssagenden Ausgabe unterdrückst. So funktioniert Exception-Handling nicht, wie wir schon mehrfach betont haben. Die Ausgabe kommt daher, dass Du debuglevel auf True gesetzt hast, sind also kein Zeichen für einen Fehler.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Ich bekomme bei der Ansicht der Emailquelldaten folgenden Fehler gemeldet.
X-ACL-Warn: Message does not conform to RFC2822 standard und die Email landet immer im Spammordner
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: dann solltest Du schauen ob msg.as_string() RFC2822-konform ist (wovon ich mal ausgehe) oder ob Dein Mail-Gateway inkompatibel ist.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Fehler im Mail-gateway gefunden. Jetzt landet die Email im Posteingangsordner. Danke
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Ich bin immer noch beim Logging. Leider verstehe ich die Details nicht, obwohl ich schon Stunden lese und google bemühe. Bitte erklärt doch einem Erstklässler wie ich das Logging in meinen Programm richtig zum Laufen bringe. Ich bekomme immer nur die Meldungen aus den Zeilen unterhalb von # application code und nicht die Meldung aus der Funktion fetch_whole_year. In dem Logfile sollen auch die Informationen über den erfolgreichen Download der anderen Dateien. Nicht nur die defekten, oder nicht vorhandenen Dateien.

Code: Alles auswählen

def initialize_logger():                                                      
      logfile_name = generate_logfile()
      print(logfile_name)
      ensure_logdir_exists(logfile_name)                                
      logger = logging.getLogger('Data download')                               
      logger.setLevel(logging.DEBUG)                
      handler = logging.FileHandler(logfile_name)                               
      handler.setLevel(logging.DEBUG)                                           
      formatter = logging.Formatter(                                            
          '%(asctime)s - %(name)s - %(levelname)s - %(message)s'                
      )                                                                         
      handler.setFormatter(formatter)                                           
      logger.addHandler(handler)                                                
                                                                                
      # application' code                                                       
      logger.debug('debug message')                                             
      logger.info('info message')                                               
      logger.warn('warn message')                                               
      logger.error('error message')                                    
      logger.critical('critical message')           

Code: Alles auswählen

def fetch_whole_year(symbol, year):                                  
      for symbol in symbol:                                                     
          last_week = datetime.date(year, 12, 31).isocalendar()[1]     
          for week in range(1, last_week + 1):                                  
              try:                                             
                  if not exists_file(symbol, year, week):                       
                      data = pull_file(symbol, year, week)                      
                      print_data_length(data)                                   
                      save_file(symbol, year, week, data)                       
              except Exception as e:                                            
                  logging.exception(e)                                          
              else:                                                             
                  print("File for {}/{}/{} already fetched.".format(            
                      symbol, year, week)                                       
                  )              

Code: Alles auswählen

Traceback (most recent call last):
  File "TickDataCsv.py", line 103, in fetch_whole_year
    data = pull_file(symbol, year, week)
  File "TickDataCsv.py", line 55, in pull_file
    response = urllib2.urlopen(url)
  File "/usr/lib64/python2.7/urllib2.py", line 154, in urlopen
    return opener.open(url, data, timeout)
  File "/usr/lib64/python2.7/urllib2.py", line 437, in open
    response = meth(req, response)
  File "/usr/lib64/python2.7/urllib2.py", line 550, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/lib64/python2.7/urllib2.py", line 475, in error
    return self._call_chain(*args)
  File "/usr/lib64/python2.7/urllib2.py", line 409, in _call_chain
    result = func(*args)
  File "/usr/lib64/python2.7/urllib2.py", line 558, in http_error_default
    raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
HTTPError: HTTP Error 404: Not Found
ERROR:root:HTTP Error 404: Not Found
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: print ≠ logging
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Danke für die Antwort. Das habe ich mittlerweile auch herausgefunden. Ich brauche ein Beispielprogramm bei dem ich einmal sehe, wie das Logging richtig eingesetzt wird. Das heißt ich erstelle die Lognachrichten selbst?
Benutzeravatar
Kebap
User
Beiträge: 686
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

aaron hat geschrieben:Ich brauche ein Beispielprogramm bei dem ich einmal sehe, wie das Logging richtig eingesetzt wird.
Sicherlich hast du dir schon die offizielle Dokumentation zu Logging samt Beispielen angeschaut, bevor du hier Grundsätzliches erfragst?

https://docs.python.org/3.6/howto/logging.html
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Ich beschäftige mich immer noch mit dem Logging in meinem Programm. Ich möchte euch bitten mir die fehlenden Zeilen Code einmal zu schreiben. Ich verbringe mit diesem Teil des Programmes schon viele Tage. Ich finde kein Beispiel. Auch die Dokumentation hilft mir nicht, weil ich nicht weiß, wie das Logging richtig eingebaut wird.

Code: Alles auswählen

def initialize_logger():                                                         
      logfile_name = generate_logfile()                                            
      print(logfile_name)                                                          
      ensure_logdir_exists(logfile_name)                                           
      logger = logging.getLogger('Data download')                                  
      logger.setLevel(logging.DEBUG)                                               
      handler = logging.FileHandler(logfile_name)                                  
      handler.setLevel(logging.DEBUG)                                              
      formatter = logging.Formatter(                                               
          '%(asctime)s - %(name)s - %(levelname)s - %(message)s'                   
      )                                                                            
      handler.setFormatter(formatter)                                              
      logger.addHandler(handler)                                                   
                                                                                   
      # application' code                                                          
      logger.debug('debug message')                                                
      logger.info('info message')                                                  
      logger.warn('warn message')                                                  
      logger.error('error message')                                                
      logger.critical('critical message')                                          

Code: Alles auswählen

def fetch_whole_year(symbol, year):                                              
      for symbol in symbol:                                                        
          last_week = datetime.date(year, 12, 31).isocalendar()[1]                 
          for week in range(1, last_week + 1):                                     
              try:                                                                 
                  if not exists_file(symbol, year, week):                          
                      data = pull_file(symbol, year, week)                         
                      print_data_length(data)                                      
                      save_file(symbol, year, week, data)                          
              except Exception as e:                                               
                  logging.exception(e)                                             
              else:                                                                
                  print("File for {}/{}/{} already fetched.".format(               
                      symbol, year, week)                                          
                  )          
Aufgerufen wird das Logging in der Funktion main()

Code: Alles auswählen

def main():                                                                      
      initialize_logger()     
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: was ist denn nun Dein Problem? Was möchtest Du mit Logging erreichen, was hast Du im Moment. Wie weicht das Ergebnis, das Du hast von dem ab, das Du willst?
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was funktioniert denn nicht? Fuer mich geht dein code (nachdem ich etwas drumrum gebaut habe was du nicht zeigst)

Code: Alles auswählen

import os
import logging

def generate_logfile():
    return "/tmp/test-foo/logfile.log"

def ensure_logdir_exists(logfile_name):
      dir = os.path.dirname(logfile_name)
      if not os.path.exists(dir):
            os.makedirs(dir)


def initialize_logger():
      logfile_name = generate_logfile()
      print(logfile_name)
      ensure_logdir_exists(logfile_name)
      logger = logging.getLogger('Data download')
      logger.setLevel(logging.DEBUG)
      handler = logging.FileHandler(logfile_name)
      handler.setLevel(logging.DEBUG)
      formatter = logging.Formatter(
          '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
      )
      handler.setFormatter(formatter)
      logger.addHandler(handler)

      # application' code
      logger.debug('debug message')
      logger.info('info message')
      logger.warn('warn message')
      logger.error('error message')
      logger.critical('critical message')


def main():
    initialize_logger()


if __name__ == '__main__':
     main()
Bekomme ich eine Datei mit Eintraegen, so wie erwartet.

In deiner fetch_whole_year Funktion rufst du kein logging auf, nur so am Rande. Insofern kann da dann auch nichts geloggt werden.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Danke für die Antworten. Das ist ja genau meine Frage, wie rufe ich das Logging in der Funktion fetch_whole-year auf? Hier noch einmal die Funktionen, die genau das machen was sie sollen. Das Ergebnis ist ein Logfile mit folgendem Inhalt. Ich möchte, dass die Fehlermeldungen, wie die Datei ist auf dem Server nicht vorhanden, oder die Datei ist beschädigt.

Code: Alles auswählen

2017-04-26 15:39:35,141 - Data download - DEBUG - debug message
2017-04-26 15:39:35,141 - Data download - INFO - info message
2017-04-26 15:39:35,141 - Data download - WARNING - warn message
2017-04-26 15:39:35,141 - Data download - ERROR - error message
2017-04-26 15:39:35,141 - Data download - CRITICAL - critical message

Code: Alles auswählen

def generate_logfile():                                                          
      return os.path.join("log", str(datetime.date.today())+'.log')                
                                                                                   
                                                                                   
  def ensure_logdir_exists(logfilename):                                           
      if not os.path.exists(os.path.dirname(logfilename)):                         
          os.makedirs(os.path.dirname(logfilename))                                
                                                                                   
                                                                                   
  def initialize_logger():                                                         
      logfile_name = generate_logfile()                                            
      print(logfile_name)                                                          
      ensure_logdir_exists(logfile_name)                                           
      logger = logging.getLogger('Data download')                                  
      logger.setLevel(logging.DEBUG)                                               
      handler = logging.FileHandler(logfile_name)                                  
      handler.setLevel(logging.DEBUG)                                              
      formatter = logging.Formatter(                                               
          '%(asctime)s - %(name)s - %(levelname)s - %(message)s'                   
      )                                                                            
      handler.setFormatter(formatter)                                              
      logger.addHandler(handler)                                                   
                                                                                   
      # application' code                                                          
      logger.debug('debug message')                                                
      logger.info('info message')                                                  
      logger.warn('warn message')                                                  
      logger.error('error message')                                                
      logger.critical('critical message'
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der Trick ist das getLogger mit dem gleichen Namen immer den gleichen Logger zurueckgibt. Der ist an anderer Stelle (also initialize_logger) konfiguriert worden, aber benutzen kannst du ihn ueberall mit

Code: Alles auswählen

logging.getLogger("Data download").info("text")
Ueblicherweise verwendet man stattdessen das hier https://docs.python.org/2/howto/logging ... g-tutorial beschriebene

Code: Alles auswählen

# modul-global!
logger = logging.getLogger(__name__)
Und statt in initialise_logger einen Namen anzugeben, machst du nur "logger = logging.getLogger()", womit du den root-logger bekommst. Alle anderen Logger mit Namen wie "mein.package.submodul" delegieren immer weiter nach oben, bis zur Wurzel.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der Trick ist das getLogger mit dem gleichen Namen immer den gleichen Logger zurueckgibt. Der ist an anderer Stelle (also initialize_logger) konfiguriert worden, aber benutzen kannst du ihn ueberall mit

Code: Alles auswählen

logging.getLogger("Data download").info("text")
Ueblicherweise verwendet man stattdessen das hier https://docs.python.org/2/howto/logging ... g-tutorial beschriebene

Code: Alles auswählen

# modul-global!
logger = logging.getLogger(__name__)
Und statt in initialise_logger einen Namen anzugeben, machst du nur "logger = logging.getLogger()", womit du den root-logger bekommst. Alle anderen Logger mit Namen wie "mein.package.submodul" delegieren immer weiter nach oben, bis zur Wurzel.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Als Ergebnis möchte ich eine Ausgabe wie folgt haben:
File for AUDJPY/2017/1 already fetched.
File for AUDJPY/2017/2 already fetched.
File for AUDJPY/2017/3 already fetched.
File for AUDJPY/2017/4 already fetched.
File for AUDJPY/2017/5 already fetched.

Das Logging muß ja in der Schleife aufgerufen werden.
1. wenn die Datei nicht vorhanden, oder beschädigt ist.
2. wenn die Datei schon heruntergeladen wurde.
Der Inhalt des Logfiles sieht so aus:
2017-04-26 17:45:21,064 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:21,140 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:21,215 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:21,300 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:21,381 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:21,470 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:21,559 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:21,636 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:21,736 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:21,823 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:21,921 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:22,006 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:22,086 - Data download - ERROR - HTTP Error 404: Not Found
2017-04-26 17:45:22,179 - Data download - ERROR - HTTP Error 404: Not Found

ERROR - HTTP Error 404: Not Found ist ja richtig. Nur möchte ich wissen welche Datei nicht vorhanden, oder beschädigt ist.

Hier noch einmal die Funktion. So schwer kann das doch nicht sein. Das HOWTO bringt mich nicht weiter, weil ich nicht erkennen kann, wie ich was in der Schleife aufrufe.

Code: Alles auswählen

def fetch_whole_year(symbol, year):                                              
      for symbol in symbol:                                                        
          last_week = datetime.date(year, 12, 31).isocalendar()[1]                 
          for week in range(1, last_week + 1):                                     
              try:                                                                 
                  if not exists_file(symbol, year, week):                          
                      data = pull_file(symbol, year, week)                         
                      print_data_length(data)                                      
                      save_file(symbol, year, week, data)                          
              except Exception as e:                                               
                  logging.getLogger("Data download").error(e)                      
              else:                                                                
                  print("File for {}/{}/{} already fetched.".format(               
                      symbol, year, week)                                          
                  )    
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na dann musst du doch nur die dazu notwendigen Daten loggen, also symbol, year, week, bzw. den Filenamen der dazugehoert.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: so

Code: Alles auswählen

import logging
logger = logging.getLogger('Data download')

def fetch_whole_year(symbol, year):
    for symbol in symbol:
        last_week = datetime.date(year, 12, 31).isocalendar()[1]
        for week in range(1, last_week + 1):
            try:
                if not exists_file(symbol, year, week):
                    data = pull_file(symbol, year, week)
                    print_data_length(data)
                    save_file(symbol, year, week, data)
            except Exception:
                logger.exception("while downloading {}/{}/{}".format(symbol, year, week))
            else:
                logger.info("File for {}/{}/{} already fetched.".format(symbol, year, week))

def initialize_logger():
    logfile_name = generate_logfile()
    ensure_logdir_exists(logfile_name)
    logging.basicConfig(filename=logfile_name, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.DEBUG)
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: wenn Du am aktuellen Datum aufhören willst, dann prüf einfach auf das aktuelle Datum:

Code: Alles auswählen

last_day = min(datetime.date(year, 12, 31), datetime.date.today())
new_year, last_week, _ = day.isocalendar()
if new_year > year:
    last_week = 52
elif new_year < year:
    return
Antworten