Hi,
hab hier gerade ein sehr komisches Problem.
Baue einen Crawler für eine Seite. Muss mich dazu Authentifizieren und bekomme dann Zugriff auf mein Profil.
Dazu habe ich mir mit urllib.request.build_opener einen Opener gebaut der dies tut.
Nun muss ich mit diesem Opener große Dateien runterladen (>1GB). Der direkte weg mit .read() fällt dadurch weg.
Dachte nun das urllib.request.urlretrive ja genau das macht was ich haben will (url -> file). Anscheinend hat der opener diese methode aber nicht (warum auch immer).
Kann mir jemand sagen, wie ich das am besten mache? Muss ich die übliche .read(CHUNK) Route gehen oder gibt es da was eleganteres?
euch einen schönen Abend!
p91
urllib.request.build_opener mit urllib.request.urlretrieve?
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Und wie immer die Empfehlung: Schau Dir mal das requests-Modul an! Das hat eine viel angenehmere API als die "ollen" Module der Standard-Lib bezüglich HTTP.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Hi,
stimmt, aber es bleibt dabei:
OpenerDirector hat kein urlretrieve, nur ein open() von dem man dann read() oder read(CHUNK) machen kann.
Und das "normale" urlretrieve finde ich zwar aber das geht nicht weil dann nicht die Authentifizierte Verbindung verwendet wird
(wenn ich es richtig verstehe)
Verwende übrigens Python 3.
stimmt, aber es bleibt dabei:
OpenerDirector hat kein urlretrieve, nur ein open() von dem man dann read() oder read(CHUNK) machen kann.
Und das "normale" urlretrieve finde ich zwar aber das geht nicht weil dann nicht die Authentifizierte Verbindung verwendet wird
(wenn ich es richtig verstehe)
Verwende übrigens Python 3.
Hi,
urllib.request habe ich mir schon angeguckt aber ich befürchte, dass kann ich nicht verwenden.
Das Problem ist, dass ich gleichzeitig Verbindungen zu verschiedenen Seiten habe und für jede Seite meine Auth halten muss.
Ergo kann ich keinen Default-Handler installieren und dann einfach urllib.reqeust.urlopen() oder urllib.reqeust.urlretrieve() verwenden
sondern habe für jede Seite einen eigenen Handler. Nur stellt dieser Handler AFAIK nur open() bereit aber kein äquivalent zu urlretrieve.
Hab mittlerweile eine Lösung mit shutils aber versuche immer noch Download resume Funktionalität einzubauen und schön ist es auch nicht wirklich.
Hier einfach mal etwas Code, vlt. mache ich ja einen fundamentalen Fehler und kapiere deshalb nicht, was ich falsch mache:
euch noch einen schönen Tag,
p91
urllib.request habe ich mir schon angeguckt aber ich befürchte, dass kann ich nicht verwenden.
Das Problem ist, dass ich gleichzeitig Verbindungen zu verschiedenen Seiten habe und für jede Seite meine Auth halten muss.
Ergo kann ich keinen Default-Handler installieren und dann einfach urllib.reqeust.urlopen() oder urllib.reqeust.urlretrieve() verwenden
sondern habe für jede Seite einen eigenen Handler. Nur stellt dieser Handler AFAIK nur open() bereit aber kein äquivalent zu urlretrieve.
Hab mittlerweile eine Lösung mit shutils aber versuche immer noch Download resume Funktionalität einzubauen und schön ist es auch nicht wirklich.
Hier einfach mal etwas Code, vlt. mache ich ja einen fundamentalen Fehler und kapiere deshalb nicht, was ich falsch mache:
Code: Alles auswählen
# -*- coding: utf-8 -*-
from urllib.parse import urlencode
from urllib.request import build_opener, HTTPCookieProcessor
from http.cookiejar import CookieJar
from time import sleep
from shutil import copyfileobj
import os
import re
class CookieCon_ret(object):
def __init__(self, encoding='utf-8', userAgent=None):
self._encoding = encoding
self._cookiejar = CookieJar()
self._opener = build_opener(HTTPCookieProcessor(self._cookiejar))
if not userAgent is None:
self._opener.addheaders = [('User-agent', userAgent)]
def urlretrieve(self, url, folder, optname = None):
"""Used for files"""
with self._opener.open(url) as sock:
foo = sock.info()['Content-Disposition']
if optname is None:
#yeah, this is not correct but regex is a fucking pain in the ass right now
filename = foo[22:-1]
else:
filename = optname
filepath = os.path.join(folder, filename)
if not os.path.exists(filepath):
with open(filepath, "wb") as file:
copyfileobj(sock, file)
euch noch einen schönen Tag,
p91
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Das hatte ich sogar verlinkt
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Oh, Entschuldigung, das hatte ich gar nicht gesehen
Leider ist requests keine Alternative da das ganze nur mit Python 3.3 Standard Libs gemacht werden sollte (macht den Support einfacher).
Habs aber glaube ich, jetzt gelöst (zumindest hat es bei meinen tests jetzt immer funktioniert)
[EDIT]
Da war ein tab zu viel drin da es Teil einer Klasse ist
Leider ist requests keine Alternative da das ganze nur mit Python 3.3 Standard Libs gemacht werden sollte (macht den Support einfacher).
Habs aber glaube ich, jetzt gelöst (zumindest hat es bei meinen tests jetzt immer funktioniert)
Code: Alles auswählen
def urlretrieve(self, url, folder, optname = None):
"""Used for files"""
with self._opener.open(url) as sock:
foo = sock.info()['Content-Disposition']
if optname is None:
#yeah, this is not correct but regex is a fucking pain in the ass right now
filename = foo[22:-1]
else:
filename = optname
filepath = os.path.join(folder, filename)
if not os.path.exists(filepath):
file_options = "wb"
currentSize = 0
else:
file_option = "ab"
currentSize = os.path.getsize(filepath)
maxSize = int(sock.headers['Content-Length'])
if currentSize < maxSize:
if currentSize:
self._opener.add_header("Range","bytes=%s-" % (currentSize))
with self._opener.open(url) as sock, open(filepath, file_options) as file:
copyfileobj(sock, file)
if currentSize:
self._opener.remove_header("Range","bytes=%s-" % (currentSize))
Da war ein tab zu viel drin da es Teil einer Klasse ist
Zuletzt geändert von p90 am Samstag 28. Dezember 2013, 16:51, insgesamt 1-mal geändert.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Es mag sein, dass es an den komischen Einrückungen liegt, die Du verwendest (nimm doch bitte *vier* Spaces - wie es PEP8 vorschreibt), aber Deine Methode ist für meinen Geschmack etwas lang und macht zu viel.
Die Ermittlung des Dateinamens und die Bestimmung der Dateiattribute könnte man locker auslagern.
Dein Docstring ist imho wenig aussagekräftig und passt so gar nicht zum Funktionsnamen.
Die Ermittlung des Dateinamens und die Bestimmung der Dateiattribute könnte man locker auslagern.
Dein Docstring ist imho wenig aussagekräftig und passt so gar nicht zum Funktionsnamen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
problematischer ist ja, dass immer zwei mal ein "GET"-Request auf die URL gemacht wird. Wie man aus dem ersten ein "HEAD" macht, müßte man irgendwo nachlesen. Aber mit ein bißchen aufräumen, sieht die Methode gleich viel schlanker aus:
Code: Alles auswählen
def get_filename_from_url(self, url):
with self._opener.open(url) as sock:
return sock.info()['Content-Disposition'].split(':',1)[-1].strip()
def retrieve_url(self, url, folder, optname=None):
"""Used for urls"""
filename = optname if optname else self.get_filename_from_url(url)
filepath = os.path.join(folder, filename)
if os.path.exists(filepath):
self._opener.add_header("Range","bytes=%d-" % os.path.getsize(filepath))
with self._opener.open(url) as sock, open(filepath, "ab") as file:
copyfileobj(sock, file)
self._opener.headers.pop('Range', None)
@p90: Das mit `requests` würde ich mir auch noch mal überlegen. Das hat keine weiteren Abhängigkeiten und macht diesen ganzen `urllib`-Murks wesentlich benutzbarer.
ja, die Funktion muss ich noch etwas verfeinern, bin da gerade auch noch dran.Hyperion hat geschrieben:Es mag sein, dass es an den komischen Einrückungen liegt, die Du verwendest (nimm doch bitte *vier* Spaces - wie es PEP8 vorschreibt), aber Deine Methode ist für meinen Geschmack etwas lang und macht zu viel.
Die Ermittlung des Dateinamens und die Bestimmung der Dateiattribute könnte man locker auslagern.
Dein Docstring ist imho wenig aussagekräftig und passt so gar nicht zum Funktionsnamen.
Zu PEP8: ich verwende nur Tabs, das sind beim Editieren dann auch hier Tabs. Warum nun aus einem Tab 8 Leerzeichen in der Forensoftware werden weiß ich leider nicht.
stimmt, das muss ich noch ändern, zweimal GET ist wirklich nicht so schön. Danke für die Anmerkungen!Sirius3 hat geschrieben:problematischer ist ja, dass immer zwei mal ein "GET"-Request auf die URL gemacht wird. Wie man aus dem ersten ein "HEAD" macht, müßte man irgendwo nachlesen. Aber mit ein bißchen aufräumen, sieht die Methode gleich viel schlanker aus:Code: Alles auswählen
def get_filename_from_url(self, url): with self._opener.open(url) as sock: return sock.info()['Content-Disposition'].split(':',1)[-1].strip() def retrieve_url(self, url, folder, optname=None): """Used for urls""" filename = optname if optname else self.get_filename_from_url(url) filepath = os.path.join(folder, filename) if os.path.exists(filepath): self._opener.add_header("Range","bytes=%d-" % os.path.getsize(filepath)) with self._opener.open(url) as sock, open(filepath, "ab") as file: copyfileobj(sock, file) self._opener.headers.pop('Range', None)
Jo, von dem was ich jetzt über requests gelesen habe sieht es schon sehr schön aus. Wenn ich das jetzt nur für mich schreiben würde, würde ich es auch benutzen. Da ich das ganze aber auch an meine Mitstudenten weiter geben möchte (bzw. auch an jeden anderen den es interessiert) ist halt ein "Installiert dir Python3.3" einfacher als ein "Installiere dir Python3, dann installiert dir easy_setup oder pip, dann installiere dir noch requests".BlackJack hat geschrieben:@p90: Das mit `requests` würde ich mir auch noch mal überlegen. Das hat keine weiteren Abhängigkeiten und macht diesen ganzen `urllib`-Murks wesentlich benutzbarer.