In diesem Tutorial lernen Sie Folgendes:
- Definition und Funktionsweise eines Python Proxy-Servers.
- Die erforderlichen Schritte zum Erstellen eines HTTP-Proxy-Servers in Python.
- Die Vor- und Nachteile dieses Ansatzes.
Legen wir also los!
Was ist ein Python Proxy-Server?
Ein Python Proxy-Server ist eine Python-Anwendung, die als Vermittler zwischen Clients und dem Internet fungiert. Er fängt Anfragen von Clients ab, leitet sie an die Zielserver weiter und sendet die Antwort zurück an den Client. Dadurch wird die Identität des Clients gegenüber den Zielservern maskiert.
Lesen Sie unseren Artikel, um zu erfahren, was ein Proxy-Server ist und wie er funktioniert.
Die Socket-Programmierfunktionen von Python erleichtern die Implementierung eines einfachen Proxy-Servers, sodass Benutzer den Netzwerkverkehr überprüfen, ändern oder umleiten können. Proxy-Server eignen sich hervorragend zum Caching, zur Verbesserung der Leistung sowie zur Erhöhung der Sicherheit beim Web-Scraping.
Wie implementiert man einen HTTP-Proxy-Server in Python?
Folgen Sie den nachstehenden Anweisungen und lernen Sie, ein Python-Proxy-Server-Skript zu erstellen.
Schritt 1: Initialisieren Sie Ihr Python-Projekt
Stellen Sie zunächst sicher, dass Python 3+ auf Ihrem Computer installiert ist. Laden Sie ansonsten das Installationsprogramm herunter, führen Sie es aus und folgen Sie den Anweisungen des Installationsassistenten.
Verwenden Sie als Nächstes die folgenden Befehle, um einen python-http-proxy-server-Ordner zu erstellen und ein Python-Projekt mit einer darin enthaltenen virtuellen Umgebung zu initialisieren:
mkdir python-http-proxy-server
cd python-http-proxy-server
python -m venv env
Öffnen Sie den Ordner python-http-proxy-server in Ihrer Python-IDE und erstellen Sie eine leere Datei namens proxy_server.py.
Großartig! Nun haben Sie alles, was Sie benötigen, um einen HTTP-Proxy-Server in Python zu erstellen.
Schritt 2: Einen eingehenden Socket initialisieren
Dazu müssen Sie zuerst einen Websocket-Server für die Annahme eingehender Anfragen erstellen. Falls Ihnen dieses Konzept nicht bekannt ist – ein Socket ist eine Programmierabstraktion auf niedriger Ebene, die einen bidirektionalen Datenfluss zwischen einem Client und einem Server ermöglicht. Im Kontext eines Webservers wird ein Server-Socket verwendet, um auf eingehende Verbindungen von Clients zu warten.
Verwenden Sie die folgenden Zeilen, um einen Socket-basierten Web-Server in Python zu erstellen:
port = 8888
# bind the proxy server to a specific address and port
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# accept up to 10 simultaneous connections
server.bind(('127.0.0.1', port))
server.listen(10)
Damit wird ein eingehender Socket-Server initialisiert und an die lokale Adresse http://127.0.0.1:8888 gebunden. Dann ermöglicht dies dem Server, Verbindungen mit der Methode listen() anzunehmen.
Hinweis: Sie können die Nummer des Ports ändern, auf den der Web-Proxy hören soll. Zudem können Sie das Skript auch so ändern, dass es diese Informationen von der Befehlszeile liest, um maximale Flexibilität zu erzielen.
Socket stammt aus der Python Standard-Bibliothek. Sie werden also den folgenden Import zusätzlich zu Ihrem Skript haben:
import socket
Um zu überwachen, ob der Python Proxy-Server wie erforderlich gestartet wurde, protokollieren Sie diese Nachricht:
print(f"Proxy server listening on port {port}...")
Schritt 3: Client-Anfragen annehmen
Wenn ein Client eine Verbindung zum Proxy-Server herstellt, muss dieser einen neuen Socket erstellen, um die Kommunikation mit diesem bestimmten Client abzuwickeln. So können Sie dies in Python tun:
# listen for incoming requests
while True:
client_socket, addr = server.accept()
print(f"Accepted connection from {addr[0]}:{addr[1]}")
# create a thread to handle the client request
client_handler = threading.Thread(target=handle_client_request, args=(client_socket,))
client_handler.start()
Um mehrere Client-Anfragen gleichzeitig zu bearbeiten, sollten Sie Multithreading wie oben beschrieben verwenden. Denken Sie daran, Threading aus der Python-Standard-Bibliothek zu importieren:
import threading
Wie Sie sehen können, verarbeitet der Proxy-Server eingehende Anfragen über die benutzerdefinierte Funktion handle_client_request(). In den nächsten Schritten sehen Sie, wie dies definiert wird.
Schritt 4: Bearbeitung der eingehenden Anfragen
Sobald der Client-Socket erstellt wurde, müssen Sie ihn verwenden, um:
- die Daten der eingehenden Anfragen zu lesen.
- den Host und den Port des Zielservers aus diesen Daten zu extrahieren.
- die Client-Anfrage an den Zielserver weiterzuleiten.
- die Antwort zu erhalten und diese an den ursprünglichen Kunden weiterzuleiten.
In diesem Abschnitt konzentrieren wir uns auf die ersten beiden Schritte. Definieren Sie die Funktion handle_client_request() und verwenden Sie sie, um die Daten aus der eingehenden Anfrage zu lesen:
def handle_client_request(client_socket):
print("Received request:\n")
# read the data sent by the client in the request
request = b''
client_socket.setblocking(False)
while True:
try:
# receive data from web server
data = client_socket.recv(1024)
request = request + data
# Receive data from the original destination server
print(f"{data.decode('utf-8')}")
except:
break
setblocking(False) versetzt den Client-Socket in den nicht blockierenden Modus. Verwenden Sie dann recv(), um die eingehenden Daten zu lesen und sie im Byte-Format an die Anfrage anzuhängen. Da Sie die Größe der eingehenden Anforderungsdaten nicht kennen, müssen Sie sie Block für Block lesen. In diesem Fall wurde ein Block von 1024 Byte angegeben. Wenn recv() im nicht blockierenden Modus keine Daten findet, wird eine Fehlerausnahme ausgelöst. Somit markiert die Anweisung except das Ende des Vorgangs.
Notieren Sie sich die protokollierten Nachrichten, um zu verfolgen, was der Python Proxy-Server tut.
Nachdem Sie die eingehende Anfrage abgerufen haben, müssen Sie den Host und den Port des Zielservers daraus extrahieren:
host, port = extract_host_port_from_request(request)
In particular, this is what the extract_host_port_from_request() function looks like:
def extract_host_port_from_request(request):
# get the value after the "Host:" string
host_string_start = request.find(b'Host: ') + len(b'Host: ')
host_string_end = request.find(b'\r\n', host_string_start)
host_string = request[host_string_start:host_string_end].decode('utf-8')
webserver_pos = host_string.find("/")
if webserver_pos == -1:
webserver_pos = len(host_string)
# if there is a specific port
port_pos = host_string.find(":")
# no port specified
if port_pos == -1 or webserver_pos < port_pos:
# default port
port = 80
host = host_string[:webserver_pos]
else:
# extract the specific port from the host string
port = int((host_string[(port_pos + 1):])[:webserver_pos - port_pos - 1])
host = host_string[:port_pos]
return host, port
To better understand what it does, consider the example below. This is what the encoded string of an incoming request usually contains:
GET http://example.com/your-page HTTP/1.1
Host: example.com
User-Agent: curl/8.4.0
Accept: */*
Proxy-Connection: Keep-Alive
extract_host_port_from_request() extrahiert den Host und den Port des Webservers aus dem Feld „Host:“. In diesem Fall ist der Host example.com und der Port ist 80 (da kein bestimmter Port angegeben wurde).
Schritt 5: Client-Anfrage weiterleiten und Antwort bearbeiten
Angesichts des Zielhosts und -ports müssen Sie jetzt die Client-Anfrage an den Zielserver weiterleiten. Erstellen Sie in handle_client_request() einen neuen Web-Socket und verwenden Sie ihn, um die ursprüngliche Anfrage an das gewünschte Ziel zu senden:
# create a socket to connect to the original destination server
destination_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect to the destination server
destination_socket.connect((host, port))
# send the original request
destination_socket.sendall(request)
Then, get ready to receive the server response and propagate it to the original client:
# read the data received from the server
# once chunk at a time and send it to the client
print("Received response:\n")
while True:
# receive data from web server
data = destination_socket.recv(1024)
# Receive data from the original destination server
print(f"{data.decode('utf-8')}")
# no more data to send
if len(data) > 0:
# send back to the client
client_socket.sendall(data)
else:
break
Auch hier müssen Sie einen Block nach dem anderen bearbeiten, da Sie die Größe der Antwort nicht kennen. Sobald das Datenfeld leer ist, müssen keine weiteren Daten empfangen werden und Sie können den Vorgang beenden.
Vergessen Sie nicht, die beiden in der Funktion definierten Sockets zu schließen:
# close the sockets
destination_socket.close()
client_socket.close()
Fantastisch! Sie haben gerade einen HTTP-Proxy-Server in Python erstellt. Nun ist es an der Zeit, den gesamten Code einzusehen, ihn zu starten und zu überprüfen, ob er wie erwartet funktioniert!
Schritt 6: Alles zusammenfügen
Dies ist der endgültige Code Ihres Python Proxy-Server-Skripts:
import socket
import threading
def handle_client_request(client_socket):
print("Received request:\n")
# read the data sent by the client in the request
request = b''
client_socket.setblocking(False)
while True:
try:
# receive data from web server
data = client_socket.recv(1024)
request = request + data
# Receive data from the original destination server
print(f"{data.decode('utf-8')}")
except:
break
# extract the webserver's host and port from the request
host, port = extract_host_port_from_request(request)
# create a socket to connect to the original destination server
destination_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect to the destination server
destination_socket.connect((host, port))
# send the original request
destination_socket.sendall(request)
# read the data received from the server
# once chunk at a time and send it to the client
print("Received response:\n")
while True:
# receive data from web server
data = destination_socket.recv(1024)
# Receive data from the original destination server
print(f"{data.decode('utf-8')}")
# no more data to send
if len(data) > 0:
# send back to the client
client_socket.sendall(data)
else:
break
# close the sockets
destination_socket.close()
client_socket.close()
def extract_host_port_from_request(request):
# get the value after the "Host:" string
host_string_start = request.find(b'Host: ') + len(b'Host: ')
host_string_end = request.find(b'\r\n', host_string_start)
host_string = request[host_string_start:host_string_end].decode('utf-8')
webserver_pos = host_string.find("/")
if webserver_pos == -1:
webserver_pos = len(host_string)
# if there is a specific port
port_pos = host_string.find(":")
# no port specified
if port_pos == -1 or webserver_pos < port_pos:
# default port
port = 80
host = host_string[:webserver_pos]
else:
# extract the specific port from the host string
port = int((host_string[(port_pos + 1):])[:webserver_pos - port_pos - 1])
host = host_string[:port_pos]
return host, port
def start_proxy_server():
port = 8888
# bind the proxy server to a specific address and port
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('127.0.0.1', port))
# accept up to 10 simultaneous connections
server.listen(10)
print(f"Proxy server listening on port {port}...")
# listen for incoming requests
while True:
client_socket, addr = server.accept()
print(f"Accepted connection from {addr[0]}:{addr[1]}")
# create a thread to handle the client request
client_handler = threading.Thread(target=handle_client_request, args=(client_socket,))
client_handler.start()
if __name__ == "__main__":
start_proxy_server()
Launch it with this command:
python proxy_server.py
Sie sollten die folgende Meldung im Terminal sehen:
Proxy server listening on port 8888...
Um sicherzustellen, dass der Server funktioniert, führen Sie eine Proxy-Anfrage mit cURL aus. Lesen Sie unseren Leitfaden, um mehr darüber zu erfahren, wie cURL mit einem Proxy verwendet wird.
Neues Terminal öffnen und ausführen:
curl --proxy "http://127.0.0.1:8888" "http://httpbin.org/ip"
Dies würde eine GET-Anfrage an das Ziel http://httpbin.org/ip über den Proxy-Server http://127.0.0.1:8888 stellen.
Sie sollten etwas erhalten wie:
{
"origin": "45.12.80.183"
}
Dies ist die IP des Proxy-Servers. Warum? Weil der /ip-Endpunkt des HttpBin-Projekts die IP zurücksendet, von welcher die Anfrage stammt. Wenn Sie den Server lokal betreiben, entspricht „origin“ Ihrer IP.
Hinweis: Der hier erstellte Python Proxy-Server funktioniert nur mit HTTP-Zielen. Es ist ziemlich schwierig, diesen derart zu erweitern, dass er HTTPS-Verbindungen handhaben kann.
Erkunden Sie nun das Protokoll, das von der Python-Anwendung Ihres Proxy-Servers geschrieben wurde. Es sollte Folgendes enthalten:
Received request:
GET http://httpbin.org/ip HTTP/1.1
Host: httpbin.org
User-Agent: curl/8.4.0
Accept: */*
Proxy-Connection: Keep-Alive
Received response:
HTTP/1.1 200 OK
Date: Thu, 14 Dec 2023 14:02:08 GMT
Content-Type: application/json
Content-Length: 31
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
{
"origin": "45.12.80.183"
}
Daran können Sie erkennen, dass der Proxy-Server die Anfrage in dem vom HTTP-Protokoll angegebenen Format erhalten hat. Anschließend hat er sie an den Zielserver weitergeleitet, die Antwortdaten protokolliert und die Antwort an den Client zurückgesendet. Warum sind wir uns dessen sicher? Weil die IPs in „origin“ dieselben sind!
Herzlichen Glückwunsch! Sie haben gerade gelernt, wie man einen HTTP-Proxy-Server in Python baut!
Vor- und Nachteile der Verwendung eines benutzerdefinierten Python Proxy-Servers
Nun, da Sie wissen, wie Sie einen Proxy-Server in Python implementieren, sind Sie bereit, die Vorteile und Einschränkungen dieses Ansatzes zu erkennen.
Vorteile:
- Totale Kontrolle: Mit einem benutzerdefinierten Python-Skript wie diesem haben Sie die volle Kontrolle darüber, was Ihr Proxy-Server tut. Da gibt es keine zwielichtigen Aktivitäten oder Datenlecks!
- Anpassung: Der Proxy-Server kann um nützliche Funktionen wie etwa das Protokollieren und Zwischenspeichern von Anfragen erweitert werden, um die Leistung zu verbessern.
Nachteile:
- Infrastrukturkosten: Die Einrichtung einer Proxy-Server-Architektur ist nicht einfach und erfordert eine hohe Investition für Hardware oder VPS-Dienste.
- Schwer zu warten: Sie sind für die Wartung der Proxy-Architektur verantwortlich, insbesondere für die Skalierbarkeit und Verfügbarkeit des Proxys. Dies ist eine Aufgabe, die nur erfahrene Systemadministratoren bewältigen können.
- Unzuverlässig: Das Hauptproblem bei dieser Lösung ist, dass sich die Ausgangs-IP des Proxy-Servers nie ändert. Infolgedessen können Anti-Bot-Technologien die IP blockieren und verhindern, dass der Server auf die gewünschten Anfragen zugreift. Dies bedeutet, dass der Proxy irgendwann nicht mehr funktionieren wird.
Diese Einschränkungen und Nachteile sind zu gravierend, um einen benutzerdefinierten Python Proxy-Server in einem Produktionsszenario zu verwenden. Die Lösung? Ein zuverlässiger Proxy-Anbieter wie Bright Data! Erstellen Sie ein Konto, bestätigen Sie Ihre Identität, holen Sie sich einen kostenlosen Proxy und verwenden Sie ihn in Ihrer bevorzugten Programmiersprache. Integrieren Sie beispielsweise einen Proxy in Ihr Python-Skript mit Anfragen.
Unser riesiges Proxy-Netzwerk umfasst Millionen von schnellen, zuverlässigen und sicheren Proxy-Servern weltweit. Finden Sie heraus, warum wir der beste Proxy-Server-Anbieter sind.
Fazit
In diesem Leitfaden haben Sie erfahren, was ein Proxy-Server ist und wie er in Python funktioniert. Sie haben Schritt für Schritt gelernt, wie Sie einen Proxy mithilfe von Web-Sockets von Grund auf neu erstellen können. Somit sind Sie nun ein Proxy-Meister in Python geworden. Das Hauptproblem bei diesem Ansatz ist, dass die statische Ausgangs-IP Ihres Proxy-Servers Sie irgendwann blockieren wird. Dies können Sie mit den rotierenden Proxys von Bright Data verhindern!
Bright Data steuert die besten Proxy-Server der Welt und bedient Fortune-500-Unternehmen sowie über 20.000 Kunden. Das Angebot umfasst eine Vielzahl von Proxy-Arten:
- Rechenzentrum-Proxys — Über 770.000 Rechenzentrum-IPs.
- Proxys für Privatkunden — Über 72 Millionen IPs für Privatkunden in mehr als 195 Ländern.
- ISP-Proxys — Über 700.000 ISP-IPs.
- Mobile Proxys — Über 7 Millionen mobile IPs.
Dieses zuverlässige, schnelle und globale Proxy-Netzwerk ist auch die Grundlage für diverse Web-Scraping-Dienste, mit denen mühelos Daten von jeder Website abgerufen werden können.
Keine Kreditkarte erforderlich