Download einer TS-Datei

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo

ich möchte mit Hilfe von Python eine Serie von Dateien (etwa 4000) herunterladen. Die URL für die erste dieser Dateien lautet: "http://50.7.85.162/video/dKUnnPlCvapkvG ... 4710835.ts". Für alle folgenden Dateien erhöht sich der Zahlenwert im Dateinamen um jeweils 1. Die URL für die zweite Datei wäre deshalb "http://50.7.85.162/video/dKUnnPlCvapkvG ... 4710836.ts" und die der dritten "http://50.7.85.162/video/dKUnnPlCvapkvG ... 4710837.ts"

Ich bin in Punkto Programmieren zwar nicht gänzlich unerfahren, mit Python beschäftige ich mich allerdings erst seit einigen Wochen. Nun sollte man gleich nach ein paar Wochen Python-Erfahrung sich nicht unbedingt würde.

Ich habe zwar schon einige kleinere Programme geschrieben, aber ein solches ist wohl noch einige Hausnummern zu groß für mich. Daher habe ich mich nach einem Beispielprogramm umgesehen und dieses gefunden:

Code: Alles auswählen

#!/usr/bin/env python2.7
# -*- coding: iso-8859-1 -*-

import urllib2
import os

url = "http://50.7.85.162/video/dKUnnPlCvapkvGuuTMcKGg/2/media_144710835.ts"

file_name = 'C:/Users/User/Downloads/Medien' + url.split('/')[-1]
u = urllib2.urlopen(url)
f = open(file_name, 'wb')
meta = u.info()
file_size = int(meta.getheaders("Content-Length")[0])
print "Downloading: %s Bytes: %s" % (file_name, file_size)
os.system('cls')
file_size_dl = 0
block_sz = 8192
while True:
    buffer = u.read(block_sz)
    if not buffer:
        break
    file_size_dl += len(buffer)
    f.write(buffer)
    status = r"%10d  [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size)
    status = status + chr(8)*(len(status)+1)
    print status,
f.close()

Es soll mir eine Datei der Serie herunterladen. Wenn das klappen würde, schaffe ich den Rest, also den Download aller Dateien, mit Sicherheit auch ohne fremde Hilfe.

Leider komme ich, oder besser gesagt das Programm, nur bis zum Aufruf von urllib2.urlopen(url) in Zeile 10. Als Fehlermeldung bekomme ich:

Code: Alles auswählen

Traceback (most recent call last):
  File "D:\Divers\Python\PyProjekte\download\src\download.py", line 66, in <module>
    u = urllib2.urlopen(url)
  File "C:\Program Files\OpenOffice 4\program\python-core-2.7.6\lib\urllib2.py", line 127, in urlopen
    return _opener.open(url, data, timeout)
  File "C:\Program Files\OpenOffice 4\program\python-core-2.7.6\lib\urllib2.py", line 410, in open
    response = meth(req, response)
  File "C:\Program Files\OpenOffice 4\program\python-core-2.7.6\lib\urllib2.py", line 523, in http_response
    'http', request, response, code, msg, hdrs)
  File "C:\Program Files\OpenOffice 4\program\python-core-2.7.6\lib\urllib2.py", line 448, in error
    return self._call_chain(*args)
  File "C:\Program Files\OpenOffice 4\program\python-core-2.7.6\lib\urllib2.py", line 382, in _call_chain
    result = func(*args)
  File "C:\Program Files\OpenOffice 4\program\python-core-2.7.6\lib\urllib2.py", line 531, in http_error_default
    raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
    urllib2.HTTPError: HTTP Error 404: Not Found
Das bedeutet wohl, dass das referenzierte Objekt nicht gefunden werden konnte. Tatsächlich kann mit dieser URL die gewünschte Datei vom Browser aus (FF) heruntergeladen werden.

Damit ist es also bei mir schon aus. Kann mir jemand hier unter die Arme greifen und mir sagen, was hier falsch sein könnte und vielleicht auch, was ich tun muss, um mein Ziel zu erreichen.

MfG, kodela
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@kodela:
Ich vermute mal, der Server testet auf bestimmte Header, z.B. einen bekannten User-Agenten. Probiers mal mit:

Code: Alles auswählen

request = urllib2.Request(<url>, headers={'user-agent': 'Mozilla/5.0'})
urllib2.urlopen(request).read()
Im Zweifelsfalle müsstest Du mal die Kommunikation mit einem Browser nachvollziehen und alle Headerfelder wie der Browser setzen (z.B. könnten Zwischencookies mit Weiterleitungen im Spiel sein etc.)
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @jerch:

Danke für Deine Antwort. Mir ist allerdings nicht klar, wie ich die von Dir vorgeschlagenen beiden Zeilen in den Code integrieren muss. Sie müssen ja irgend wie die Zeile "u = urllib2.urlopen(url)" ersetzen, denn die ist es ja, von der das Problem ausgeht.

Ich habe das einmal so gemacht. Da bekomme ich aber ein erstes Problem mit "url" in den beiden spitzen Klammern. Ich bin mit Python noch nicht so weit, die Bedeutung dieser spitzen Klammern zu kennen. Ich habe sie testweise also einmal entfernt, dann werden die beiden Zeilen von Dir akzeptiert. Ob und was sie aber bewirken, kann ich nicht beurteilen.

Damit besteht aber das Problem weiter. In der Zeile "u = urllib2.urlopen(url)" wird ja der Variablen "u" etwas zugewiesen, auf das in der Zeile "meta = u.info()" zurückgegriffen wird. Und auf "meta" kann im weiteren Verlauf ja auch nicht verzichtet werden.

Kannst Du mir bitte helfen und mir etwas dazu sagen, wie ich die von Dir vorgeschlagenen Zeilen in den vorhandenen Code integrieren muss.

MfG, kodela
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @jerch:

Den ursprünglichen Code habe ich zwischenzeitlich mit verschiedenen Quellen ausprobiert. Er funktioniert grundsätzlich einwandfrei, aber eben nicht mit allen Quellen.

MfG, kodela
BlackJack

@kodela: Es liegt ziemlich sicher am User-Agent. Ich hab's mal mit `requests` gelöst und da ist das einzige was man machen muss damit es klappt, den User-Agent zu setzen:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
import logging
from itertools import count
import requests

logging.basicConfig()
LOG = logging.getLogger(__name__)
LOG.setLevel(logging.INFO)

CHUNK_SIZE = 32 * 1024


def main():
    base_url = 'http://50.7.85.162/video/dKUnnPlCvapkvGuuTMcKGg/2/'
    filename_template = 'media_{0}.ts'
    start_number = 144710835
    for file_number in count(start_number):
        filename = filename_template.format(file_number)
        url = base_url + filename
        response = requests.get(
            url, headers={'User-Agent': 'Mozilla/5.0'}, stream=True
        )
        if not response.ok:
            raise RuntimeError(
                '{0} {1}: {2}'.format(
                    response.status_code, response.reason, response.url
                )
            )

        LOG.info('saving %r', filename)
        with open(filename, 'wb') as ts_file:
            ts_file.writelines(response.iter_content(CHUNK_SIZE))


if __name__ == '__main__':
    main()
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

kodela hat geschrieben:Da bekomme ich aber ein erstes Problem mit "url" in den beiden spitzen Klammern.
Ah sorry, der Schnipsel war als Pseudocode gedacht, da verwende ich die spitzen Klammern manchmal als Platzhalter. Du kannst direkt Dein `urlopen` mit Deiner URL damit so ersetzen:

Code: Alles auswählen

...
file_name = 'C:/Users/User/Downloads/Medien' + url.split('/')[-1]
request = urllib2.Request(url, headers={'user-agent': 'Mozilla/5.0'})
u = urllib2.urlopen(request)
f = open(file_name, 'wb')
...
Das von BlackJack genutzte Request-Modul hat die schönere API, vllt. willst Du eher das benutzen als urllib2.
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @jerch:

Tausend Dank für Deine Hilfe. So funktioniert es jetzt einwandfrei.

Deine Frage, ob ich das von BlackJack genutzte Request-Modul wegen der schöneren API vielleicht eher benutzen möchte, als urllib2 ist eigentlich keine Frage, denn was hier die Spezialisten nutzen, da gehört ja BlackJack ohne jeden Zweifel dazu, das kann auf die eine oder andere Weise nur vorteilhaft sein. Ich werde mich sofort mit seinem Code beschäftigen. Danke für den Hinweis. Das hätte ich jetzt direkt übersehen.

MfG, kodela
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @BlackJack:

Danke für Deine Superausarbeitung. Ich hätte sie fast übersehen, weil ich direkt den letzten Beitrag öffnete und das war der von jerch. Und da damit mein (kopierter) Code funktionierte, kam ich gar nicht mehr auf den Gedanken, dass da noch weitere Beiträge sein könnten. Erst durch den Hinweis von jerch kam ich auf Deinen Beitrag und wollte Deinen Code eben ausführen, scheiterte aber am fehlenden Modul "requests". Kannst Du mir sagen, wie ich zu diesem Modul komme.

MfG, kodela
BlackJack

@kodela: Installieren. :-) Ist ja reines Python, sollte also Problemlos mit `pip` gehen. Dokumentation findet man hier: http://docs.python-requests.org/en/latest/
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @BlackJack:

Zunächst Danke für Deine Hinweise. Damit ist es mir gelungen, requests zu installieren. Das Programm lief einwandfrei damit. Das Ergebnis ist allerdings falsch. Es ist immer die selbe Datei, die heruntergeladen wird und sie ist mit 33 KB wesentlich kleiner, als zu erwarten wäre. Die ersten drei Dateien haben eine Größe von 680, 738 und 864 KB.

Ich stelle hier das funktionierende Skript ein, falls Du es für Vergleichszwecke verwenden möchtest:

Code: Alles auswählen

#!/usr/bin/env python2.7
# -*- coding: iso-8859-1 -*-

import urllib2
import os

url = "http://50.7.85.162/video/dKUnnPlCvapkvGuuTMcKGg/2/media_144710835.ts"

file_name = 'C:/Users/User/Downloads/Medien/' + url.split('/')[-1]
request = urllib2.Request(url, headers={'user-agent': 'Mozilla/5.0'})
u = urllib2.urlopen(request)
f = open(file_name, 'wb')
meta = u.info()
file_size = int(meta.getheaders("Content-Length")[0])
print "Downloading: %s Bytes: %s" % (file_name, file_size)
os.system('cls')
file_size_dl = 0
block_sz = 8192
while True:
    buffer = u.read(block_sz)
    if not buffer:
        break
    file_size_dl += len(buffer)
    f.write(buffer)
    status = r"%10d  [%3.2f%%]" % \
             (file_size_dl, file_size_dl * 100. / file_size)
    status = status + chr(8)*(len(status)+1)
    print status,
f.close()
Der Zielpfad muss natürlich angepasst werden.

Ich habe keine Ahnung, warum nur ein Block, und der nicht richtig, heruntergeladen wird. Einige Bytesequenzen stimmen mit den korrekt geladenen Dateien überein. Aber man kann auch nicht sagen, dass ein heruntergeladener Block der erste Block der herunterzuladenden Datei sei.

MfG, kodela
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo,

ich habe das Skript jetzt so umgearbeitet, dass alle Teilstücke in die erste Datei geschrieben werden. Nach dem Start des Skripts kann das Video noch während des Downloads über einen Player, zum Beispiel dem VLC, wiedergegeben werden.

Code: Alles auswählen

#!/usr/bin/env python2.7
# -*- coding: iso-8859-1 -*-

import urllib2
import os

#url = "http://50.7.85.162/video/dKUnnPlCvapkvGuuTMcKGg/2/media_144710835.ts"
url_1 = "http://50.7.85.162/video/dKUnnPlCvapkvGuuTMcKGg/2/media_"
url_2 = 144710835
url_3 = ".ts"

url = url_1 + str(url_2) + url_3
file_name = 'D:/VLC/Aufnahmen/' + url.split('/')[-1]
request = urllib2.Request(url, headers={'user-agent': 'Mozilla/5.0'})
u = urllib2.urlopen(request)
f = open(file_name, 'wb')
meta = u.info()
file_size = int(meta.getheaders("Content-Length")[0])
print "Downloading: %s Bytes: %s" % (file_name, file_size)
os.system('cls')
file_size_dl = 0
block_sz = 8192
while True:
    while True:
        buffer = u.read(block_sz)
        if not buffer:
            break
        file_size_dl += len(buffer)
        f.write(buffer)
    url_2 += 1
    url = url_1 + str(url_2) + url_3
    request = urllib2.Request(url, headers={'user-agent': 'Mozilla/5.0'})
    u = urllib2.urlopen(request)
    os.system('cls')
f.close()
Ich gehe davon aus, dass man das eine oder andere noch verbessern kann und wäre für entsprechende Hinweise dankbar.

MfG, kodela
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @BlackJack,

mittlerweile habe ich herausgefunden, warum Dein Programmvorschlag nicht funktionierte. Die URL wurde falsch gebildet.

Hier die funktionierende Version:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8

from __future__ import absolute_import, division, print_function
import logging
from itertools import count
import requests

logging.basicConfig()
LOG = logging.getLogger(__name__)
LOG.setLevel(logging.INFO)

CHUNK_SIZE = 32 * 1024

def main():
    base_url = 'http://50.7.85.162/video/dKUnnPlCvapkvGuuTMcKGg/2/'
    base_path = 'D:/VLC/Aufnahmen/'
    filename_template = 'media_{0}.ts'
    start_number = 144710835
    for file_number in count(start_number):
        filename = filename_template.format(file_number)
        url = base_url + filename
        file_path = base_path + filename
        response = requests.get(
            url, headers={'User-Agent': 'Mozilla/5.0'}, stream=True
        )                
        if not response.ok:
            raise RuntimeError(
                '{0} {1}: {2}'.format(
                    response.status_code, response.reason, response.url
                )
            )
        LOG.info('saving %r', file_path)
        with open(file_path, 'wb') as ts_file:
            ts_file.writelines(response.iter_content(CHUNK_SIZE))

if __name__ == '__main__':
    main()
url wird aus base_url und filename gebildet. Bei Dir entsprach filename aber dem kompletten Pfad, unter dem der Download gespeichert werden soll. Ich habe daher für filename nur den Dateinamen im engeren Sinne gesetzt und in base_path den Pfad ohne Dateiname verwendet.

Für url wird damit nur der Dateiname im engeren Sinne zu base_url hinzugefügt und für die zu erstellende Datei hat man mit file_path, gebildet aus base_path und filename, den vollständigen Pfad.

MfG, kodela
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @BlackJack,

mein Ziel war ja, alle Einzelteile, aus denen das Video besteht, zu einer Gesamtdatei zusammenzufügen. Dies ist mir nun auch mit der von Dir vorgeschlagenen Version mit Verwendung des requests-Moduls gelungen. Hier das Ergebnis:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8

from __future__ import absolute_import, division, print_function
import logging
from itertools import count
import requests

logging.basicConfig()
LOG = logging.getLogger(__name__)
LOG.setLevel(logging.INFO)

CHUNK_SIZE = 32 * 1024

def main():
    base_url = 'http://50.7.85.162/video/dKUnnPlCvapkvGuuTMcKGg/2/'
    base_path = 'D:/VLC/Aufnahmen/'
    filename_template = 'media_{0}.ts'
    start_number = 144710835
    dest_file = base_path + filename_template.format(start_number)
    ts_file = open(dest_file, 'wb')
    for file_number in count(start_number):
        filename = filename_template.format(file_number)
        url = base_url + filename
        response = requests.get(
            url, headers={'User-Agent': 'Mozilla/5.0'}, stream=True
        )                
        if not response.ok:
            raise RuntimeError(
                '{0} {1}: {2}'.format(
                    response.status_code, response.reason, response.url
                )
            )
        LOG.info('download %r', filename)
        ts_file.writelines(response.iter_content(CHUNK_SIZE))

if __name__ == '__main__':
    main()
MfG, kodela
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo,

ich wollte das ein Stück weiter oben gezeigte Skript so umarbeiten, dass der Hauptteil des Codes in der main() Funktion eingebettet ist. Das sollte dann so aussehen:

Code: Alles auswählen

#!/usr/bin/env python2.7
# -*- coding: iso-8859-1 -*-

from __future__ import print_function

import urllib2

url = 'http://50.7.85.162/video/dKUnnPlCvapkvGuuTMcKGg/2/media_144710835.ts'
dst_folder = 'D:/VLC/Aufnahmen/'
block_sz = 32 * 1024

def main():
    m = url.index('_')+1
    n = url[m:].index('.')
    url_fix = url[0:m]
    file_praefix = url_fix.split('/')[-1]
    file_nummer = int(url[m:m+n])
    file_ext = url[n+m:]
    file_name = dst_folder + file_praefix + str(file_nummer) + file_ext
    request = urllib2.Request(url, headers={'user-agent': 'Mozilla/5.0'})
    url_open = urllib2.urlopen(request)
    file_open =  open(file_name, 'wb')
    print('Download: %s' % (file_praefix + str(file_nummer) + file_ext))
    while True:
        while True:
            buffer = url_open.read(block_sz)
            if not buffer:
                break
            file_open.write(buffer)
        file_nummer += 1
        url = url_fix + str(file_nummer) + file_ext
        request = urllib2.Request(url, headers={'user-agent': 'Mozilla/5.0'})
        url_open = urllib2.urlopen(request)
        print('Add:', file_praefix + str(file_nummer) + file_ext)
    file_open.close()    
    
if __name__ == "__main__":
    main()
Damit bekomme ich aber folgende Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Users\Rudi\Documents\NetBeansProjects\Testprojekt\src\testprojekt.py", line 38, in <module>
    main()
  File "C:\Users\Rudi\Documents\NetBeansProjects\Testprojekt\src\testprojekt.py", line 13, in main
    m = url.index('_')+1
UnboundLocalError: local variable 'url' referenced before assignment
Diese Meldung kommt nicht, wenn ich die Zeile 31 auskommentiere.

Kann mir dies jemand erklären, ich verstehe es nicht.

MfG, kodela
BlackJack

@kodela: `url` wird in der Funktion etwas zugewiesen und damit ist es ein lokaler Name. Einer der Gründe warum man Konstanten auf Modulebene komplett in Grossbuchstaben schreiben sollte.
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

@BlackJack:

Danke, jetzt funktioniert es. Wieder etwas dazu gelernt.

MfG, kodela
Antworten