Heim > Artikel > Backend-Entwicklung > Beispiel für eine Python-Implementierung eines Multithread-HTTP-Downloaders
In diesem Artikel wird die Verwendung von Python zum Schreiben eines Multithread-HTTP-Downloaders und zum Generieren einer ausführbaren .exe-Datei vorgestellt.
Umgebung: Windows/Linux + Python2.7.x
Single-Threaded
Führen Sie zuerst Single-Threading ein, bevor Sie Multi-Threading einführen. Die Idee, einen einzelnen Thread zu schreiben, ist:
1. Analysieren Sie die URL.
3. Erstellen Sie ein http-Anfragepaket;
Laden Sie die Datei herunter.
Nach Benutzereingabe-URL analysiert. Wenn der analysierte Pfad leer ist, lautet der zugewiesene Wert „/“. Wenn die Portnummer leer ist, lautet der zugewiesene Wert „80“. Der Dateiname der heruntergeladenen Datei kann entsprechend den Wünschen des Benutzers geändert werden. Um eine Änderung anzuzeigen, geben Sie „Sonstiges“ ein, um anzugeben, dass keine Änderungen erforderlich sind.
Mehrere Parsing-Funktionen sind unten aufgeführt:#解析host和path def analyHostAndPath(totalUrl): protocol,s1 = urllib.splittype(totalUrl) host, path = urllib.splithost(s1) if path == '': path = '/' return host, path #解析port def analysisPort(host): host, port = urllib.splitport(host) if port is None: return 80 return port #解析filename def analysisFilename(path): filename = path.split('/')[-1] if '.' not in filename: return None return filename
Mit Webserver verbinden
Verwenden Sie das Socket-Modul, um eine Verbindung zum Webserver herzustellen, basierend auf dem Host und dem Port, die Sie durch Parsen der URL erhalten haben. Der Code lautet wie folgt:
import socket from analysisUrl import port,host ip = socket.gethostbyname(host) s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect((ip, port)) print "success connected webServer!!"
Erstellen Sie ein HTTP-Anforderungspaket
Erstellen Sie ein HTTP-Anforderungspaket basierend auf dem Pfad, dem Host und dem Port, die Sie beim Parsen der URL erhalten haben.
from analysisUrl import path, host, port packet = 'GET ' + path + ' HTTP/1.1\r\nHost: ' + host + '\r\n\r\n'
Laden Sie die Datei herunter
Senden Sie die Datei an den Server und holen Sie sich die Antwort basierend auf der Konstruktion HTTP-Anforderungspaket „Content-Length“ im Nachrichtenheader.
def getLength(self): s.send(packet) print "send success!" buf = s.recv(1024) print buf p = re.compile(r'Content-Length: (\d*)') length = int(p.findall(buf)[0]) return length, bufLaden Sie die Datei herunter und berechnen Sie die Downloadzeit.
def download(self): file = open(self.filename,'wb') length,buf = self.getLength() packetIndex = buf.index('\r\n\r\n') buf = buf[packetIndex+4:] file.write(buf) sum = len(buf) while 1: buf = s.recv(1024) file.write(buf) sum = sum + len(buf) if sum >= length: break print "Success!!" if __name__ == "__main__": start = time.time() down = downloader() down.download() end = time.time() print "The time spent on this program is %f s"%(end - start)
Multithreaded
Erfassen Sie das Feld „Content-Length“ im Header der Antwortnachricht. In Kombination mit der Anzahl der Threads ist der segmentierte Download gesperrt. Anders als beim Single-Threaded ist hier der gesamte Code in eine Datei integriert und im Code werden mehr integrierte Python-Module verwendet.
Erhalten Sie „Content-Length“:def getLength(self): opener = urllib2.build_opener() req = opener.open(self.url) meta = req.info() length = int(meta.getheaders("Content-Length")[0]) return lengthKombinieren Sie entsprechend der erhaltenen Länge die Anzahl der Threads, um den Bereich zu teilen:
def get_range(self): ranges = [] length = self.getLength() offset = int(int(length) / self.threadNum) for i in range(self.threadNum): if i == (self.threadNum - 1): ranges.append((i*offset,'')) else: ranges.append((i*offset,(i+1)*offset)) return rangesImplementieren Sie beim Schreiben von Inhalten in die Datei den Thread und verwenden Sie lock anstelle von lock.acquire(). .lock.release(); Verwenden Sie file.seek(), um die Datei-Offset-Adresse festzulegen, um die Genauigkeit beim Schreiben von Dateien sicherzustellen.
def downloadThread(self,start,end): req = urllib2.Request(self.url) req.headers['Range'] = 'bytes=%s-%s' % (start, end) f = urllib2.urlopen(req) offset = start buffer = 1024 while 1: block = f.read(buffer) if not block: break with lock: self.file.seek(offset) self.file.write(block) offset = offset + len(block) def download(self): filename = self.getFilename() self.file = open(filename, 'wb') thread_list = [] n = 1 for ran in self.get_range(): start, end = ran print 'starting:%d thread '% n n += 1 thread = threading.Thread(target=self.downloadThread,args=(start,end)) thread.start() thread_list.append(thread) for i in thread_list: i.join() print 'Download %s Success!'%(self.file) self.file.close()Laufergebnis:
Datei (*.py) konvertieren Schreiben eines Tools für (*.exe) ausführbare Dateien
, wie lässt man dieses Tool von Leuten nutzen, die Python nicht installiert haben? Dies erfordert die Konvertierung der .py-Datei in eine .exe-Datei.
Das py2exe-Modul von Python wird hier zum ersten Mal verwendet, daher werde ich es vorstellen: py2exe ist eine ausführbare Datei, die ein Python-Skript in eine unabhängig ausführbare Datei konvertiert Datei unter Windows (*.exe)-Tool, damit Sie dieses ausführbare Programm unter Windows ausführen können, ohne Python zu installieren. Als nächstes erstellen Sie die Datei mysetup.py im selben Verzeichnis wie multiThreadDownload.py und schreiben:from distutils.core import setup import py2exe setup(console=["multiThreadDownload.py"])Führen Sie dann den Befehl aus : Python mysetup.py py2exe generiert den dist-Ordner, die Datei multiTjhreadDownload.exe befindet sich darin. Klicken Sie zum Ausführen:
Demo-Download-Adresse: HttpFileDownload_jb51.rar
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er zum Lernen aller beiträgt, und ich hoffe auch, dass jeder ihn unterstützt Chinesische PHP-Website.