Was ist ein Python-Proxyserver

Python-Proxyserver ermöglicht das Routing von HTTP/S-Anfragen durch ein riesiges IP-Netzwerk über Python-Code. Es unterstützt Funktionen wie IP-Rotation, Sitzungspersistenz und Geolokalisierungs-Targeting.
12 min lesen
Python Proxy Server illustration with laptop and servers.

In diesem Tutorial lernen Sie:

  • Was ein Python-Proxyserver ist und wie er funktioniert
  • Die Schritte zum Erstellen eines HTTP-Proxyservers in Python.
  • Die Vor- und Nachteile dieses Ansatzes.

Legen wir los!

Was ist ein Python-Proxyserver?

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 verschleiert er die Identität des Clients gegenüber den Zielservern. 

Lesen Sie unseren Artikel, um zu erfahren, was ein Proxyserver ist und wie er funktioniert. 

Die Socket-Programmierungsfunktionen von Python machen es einfach, einen einfachen Proxyserver zu implementieren, mit dem Benutzer Netzwerkverkehr überprüfen, ändern oder umleiten können. Proxyserver eignen sich hervorragend zum Caching, zur Leistungsverbesserung und zur Erhöhung der Sicherheit beim Web-Scraping.

Wie man einen HTTP-Proxyserver in Python implementiert

Folgen Sie den nachstehenden Schritten und lernen Sie, wie man ein Python-Proxyserver-Skript erstellt.

Schritt 1: Initialisieren Sie Ihr Python-Projekt

Stellen Sie vor dem Start sicher, dass Python 3+ auf Ihrem Rechner installiert ist. Andernfalls laden Sie das Installationsprogramm herunter, führen Sie es aus und folgen Sie dem Installationsassistenten.

Verwenden Sie dann die folgenden Befehle, um einen python-http-proxy-server-Ordner zu erstellen und darin ein Python-Projekt mit einer 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 proxy_server.py.

Großartig! Sie haben alles, was Sie brauchen, um einen HTTP-Proxyserver in Python zu erstellen.

Schritt 2: Initialisieren Sie einen eingehenden Socket

Zuerst müssen Sie einen Web-Socket-Server erstellen, um eingehende Anfragen zu akzeptieren. Falls Ihnen dieses Konzept nicht vertraut ist: Ein Socket ist eine Low-Level-Programmierabstraktion, 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 Webserver 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)

Dies initialisiert einen eingehenden Socket-Server und bindet ihn an die lokale Adresse http://127.0.0.1:8888. Anschließend ermöglicht es dem Server, Verbindungen mit der Methode listen() zu akzeptieren.

Hinweis: Sie können die Portnummer, auf der der Web-Proxy lauschen soll, beliebig ändern. Sie können das Skript auch so anpassen, dass diese Information zur maximalen Flexibilität aus der Befehlszeile gelesen wird. 

socket stammt aus der Python Standard Library. Sie benötigen also den folgenden Import am Anfang Ihres Skripts:

import socket

Um zu überwachen, dass der Python-Proxyserver wie erwartet gestartet wurde, protokollieren Sie diese Meldung:

 print(f"Proxy server listening on port {port}...")

Schritt 3: Client-Anfragen akzeptieren

Wenn sich ein Client mit dem Proxyserver verbindet, muss dieser einen neuen Socket erstellen, um die Kommunikation mit diesem bestimmten Client zu übernehmen. So können Sie das 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 verarbeiten, sollten Sie, wie oben gezeigt, Multithreading verwenden. Vergessen Sie nicht, threading aus der Python Standard Library zu importieren:

import threading

Wie Sie sehen können, verarbeitet der Proxyserver eingehende Anfragen über die benutzerdefinierte Funktion handle_client_request(). Sehen Sie, wie sie in den nächsten Schritten definiert wird.

Schritt 4: Verarbeitung der eingehenden Anfragen

Sobald der Client-Socket erstellt wurde, müssen Sie ihn verwenden, um:

  1. Die Daten aus den eingehenden Anfragen zu lesen.
  2. Host und Port des Zielservers aus diesen Daten zu extrahieren.
  3. Diese zu verwenden, um die Client-Anfrage an den Zielserver weiterzuleiten.
  4. Die Antwort zu erhalten und an den ursprünglichen Client 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) setzt den Client-Socket in den nicht blockierenden Modus. Verwenden Sie dann recv(), um die eingehenden Daten zu lesen und sie im Byte-Format an request anzuhängen. Da Sie die Größe der eingehenden Anfragedaten nicht kennen, müssen Sie sie Stück für Stück lesen. In diesem Fall wurde ein Chunk von 1024 Bytes festgelegt. Im nicht blockierenden Modus löst recv() eine Fehlerausnahme aus, wenn es keine Daten findet. Daher markiert die except-Anweisung das Ende der Operation.

Beachten Sie die protokollierten Meldungen, um zu verfolgen, was der Python-Proxyserver tut.

Nach dem Abrufen der eingehenden Anfrage müssen Sie Host und 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'rn', 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 Port des Webservers aus dem Feld “Host:”. In diesem Fall ist host example.com und port 80 (da kein bestimmter Port angegeben wurde). 

Schritt 5: Die Client-Anfrage weiterleiten und die Antwort verarbeiten

Mit Host und Port des Ziels müssen Sie nun 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 Stück für Stück arbeiten, da Sie die Größe der Antwort nicht kennen. Wenn data leer ist, gibt es keine weiteren Daten zu empfangen und Sie können die Operation beenden.

Vergessen Sie nicht, die beiden in der Funktion definierten Sockets zu schließen:

# close the sockets

destination_socket.close()

client_socket.close()

Ausgezeichnet! Sie haben gerade einen HTTP-Proxyserver in Python erstellt. Zeit, sich den gesamten Code anzusehen, 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-Proxyserver-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'rn', 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 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 man cURL mit einem Proxy verwendet.

Öffnen Sie ein neues Terminal und führen Sie aus:

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 Proxyserver http://127.0.0.1:8888 stellen.

Sie sollten etwa Folgendes erhalten:

{

  "origin": "45.12.80.183"

}

Das ist die IP des Proxyservers. Warum? Weil der /ip-Endpunkt des HTTPBin-Projekts die IP zurückgibt, von der die Anfrage kommt. Wenn Sie den Server lokal ausführen, entspricht “origin” Ihrer eigenen IP. 

Hinweis: Der hier erstellte Python-Proxyserver funktioniert nur mit HTTP-Zielen. Ihn so zu erweitern, dass er HTTPS-Verbindungen unterstützt, ist ziemlich kompliziert.

Untersuchen Sie nun das von Ihrer Proxyserver-Python-Anwendung geschriebene Protokoll. 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"

}

Dies zeigt Ihnen, dass der Proxyserver die Anfrage im vom HTTP-Protokoll vorgegebenen Format erhalten hat. Anschließend leitete er sie an den Zielserver weiter, protokollierte die Antwortdaten und sendete die Antwort zurück an den Client. Warum sind wir uns dessen sicher? Weil die IPs in “origin” identisch sind!

Glückwunsch! Sie haben gerade gelernt, wie man einen HTTP-Proxyserver in Python erstellt!

Vor- und Nachteile der Verwendung eines benutzerdefinierten Python-Proxyservers

Nachdem Sie nun wissen, wie man einen Proxyserver in Python implementiert, sind Sie bereit, die Vorteile und Einschränkungen dieses Ansatzes kennenzulernen.

Vorteile:

  • Volle Kontrolle: Mit einem benutzerdefinierten Python-Skript wie diesem haben Sie die volle Kontrolle darüber, was Ihr Proxyserver tut. Keine fragwürdigen Aktivitäten oder Datenlecks!
  • Anpassbarkeit: Der Proxyserver kann um nützliche Funktionen wie Protokollierung und Caching von Anfragen erweitert werden, um die Leistung zu verbessern.

Nachteile:

  • Infrastrukturkosten: Der Aufbau einer Proxyserver-Architektur ist nicht einfach und kostet viel Geld für Hardware oder VPS-Dienste.
  • Schwer zu warten: Sie sind für die Wartung der Proxy-Architektur verantwortlich, insbesondere für deren Skalierbarkeit und Verfügbarkeit. 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 Proxyservers nie ändert. Dadurch können Anti-Bot-Technologien die IP blockieren und den Server daran hindern, auf die gewünschten Anfragen zuzugreifen. Mit anderen Worten: Der Proxy wird irgendwann nicht mehr funktionieren.

Diese Einschränkungen und Nachteile sind zu gravierend, um einen benutzerdefinierten Python-Proxyserver in einem Produktionsszenario zu verwenden. Die Lösung? Ein zuverlässiger Proxy-Anbieter wie Bright Data! Erstellen Sie ein Konto, verifizieren Sie Ihre Identität, holen Sie sich einen Proxy und verwenden Sie ihn in Ihrer bevorzugten Programmiersprache. Zum Beispiel können Sie einen Proxy mit requests in Ihr Python-Skript integrieren.

Unser riesiges Proxy-Netzwerk umfasst Millionen schneller, zuverlässiger und sicherer Proxyserver auf der ganzen Welt. Finden Sie heraus, warum wir der beste Proxyserver-Anbieter sind.

Fazit

In diesem Leitfaden haben Sie erfahren, was ein Proxyserver ist und wie er in Python funktioniert. Im Detail haben Sie gelernt, wie man einen solchen von Grund auf mit Web-Sockets erstellt. Sie sind nun ein Meister der Proxys in Python geworden. Das Hauptproblem bei diesem Ansatz ist, dass die statische Ausgangs-IP Ihres Proxyservers irgendwann zu einer Blockierung führen wird. Vermeiden Sie dies mit den rotierenden Proxys von Bright Data!

Bright Data kontrolliert die besten Proxyserver der Welt und bedient Fortune-500-Unternehmen und 50,000+ Kunden. Das Angebot umfasst eine breite Palette von Proxy-Typen:

Dieses zuverlässige, schnelle und globale Proxy-Netzwerk ist auch die Grundlage für eine Reihe von Web-Scraping-Diensten, um mühelos Daten von jeder Website abzurufen.