Из этого руководства вы узнаете:
- Что такое прокси-сервер Python и как он работает.
- Шаги, необходимые для создания прокси-сервера HTTP на Python.
- Преимущества и недостатки этого подхода.
Давайте узнаем подробности!
Что такое прокси-сервер Python?
Прокси-сервер Python — это приложение Python, выполняющее роль посредника между клиентами и Интернетом. Он перехватывает запросы клиентов, пересылает их на целевые серверы и отправляет ответ обратно клиенту. Таким образом, он скрывает личность клиента от целевых серверов.
Прочитайте нашу статью, чтобы узнать, что такое прокси-сервер и как он работает.
Возможности программирования сокетов Python позволяют легко реализовать базовый прокси-сервер, позволяющий пользователям анализировать, изменять или перенаправлять сетевой трафик. Прокси-серверы отлично подходят для кэширования, повышения производительности и безопасности при очистке веб-страниц.
Как реализовать прокси-сервер HTTP на Python
Выполните следующие шаги и узнайте, как создать скрипт прокси-сервера Python.
Шаг 1. Инициализация проекта Python
Перед началом работы убедитесь, что на вашем компьютере установлен Python 3+. В противном случае загрузите инсталлятор, запустите его и следуйте указаниям мастера установки.
Затем используйте следующие команды для создания папки python-http-proxy-server и инициализации проекта Python с виртуальной средой внутри него:
mkdir python-http-proxy-server
cd python-http-proxy-server
python -m venv env
Откройте папку python-http-proxy-server в Python IDE и создайте пустой файл proxy_server.py.
Отлично! У вас есть все необходимое для создания прокси-сервера HTTP на Python.
Шаг 2. Инициализация входящего сокета
Во-первых, вам нужно создать сервер веб-сокетов для приема входящих запросов. Если вы не знакомы с этой концепцией, то сокет — это низкоуровневая программная абстракция, которая обеспечивает двунаправленный обмен данными между клиентом и сервером. В контексте веб-сервера серверный сокет используется для «прослушивания» входящих подключений от клиентов.
Используйте следующие строки для создания веб-сервера на основе сокетов на Python:
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)
Это инициализирует сервер входящих сокетов и привязывает его к локальному адресу http://127.0.0.1:8888. Затем это позволяет серверу принимать соединения с помощью способа прослушивания () .
Примечание: вы можете изменить номер порта, который должен прослушивать веб-прокси. Можно также изменить сценарий для считывания этой информации из командной строки для обеспечения максимальной гибкости.
Сокет берется из стандартной библиотеки Python. Итак, поверх скрипта будут добавлены следующие импортированные данные:
import socket
Чтобы убедиться, что прокси-сервер Python запущен надлежащим образом, зарегистрируйте следующее сообщение:
print(f"Proxy server listening on port {port}...")
Шаг 3. Прием запросов клиентов
Когда клиент подключается к прокси-серверу, ему необходимо создать новый сокет для связи с этим конкретным клиентом. Вот как это можно сделать в Python:
# 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()
для одновременной обработки нескольких клиентских запросов следует использовать многопоточность, как указано выше. Не забудьте импортировать функцию многопоточности из стандартной библиотеки Python:
import threading
Как вы можете видеть, прокси-сервер обрабатывает входящие запросы с помощью специальной функции handle_client_request (). Порядок определения данной функции описан в следующих шагах.
Шаг 4. Обработка входящих запросов
После создания клиентского сокета вам необходимо использовать его для:
- Считывания данных из входящих запросов.
- Извлечения хоста и порта целевого сервера из этих данных.
- Использования его для пересылки клиентского запроса на целевой сервер.
- Получения ответа и отправки его исходному клиенту.
В этом разделе давайте сосредоточимся на первых двух шагах. Определите функцию handle_client_request () и используйте ее для чтения данных из входящего запроса:
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 (ложь) переводит клиентский сокет в неблокирующий режим. Затем используйте recv () для чтения входящих данных и добавления их в запрос в байтовом формате. Поскольку вы не знаете размер данных входящего запроса, вам потребуется считывать их по частям за раз. В данном случае указан фрагмент размером 1024 байта. В неблокирующем режиме, если recv () не найдет никаких данных, возникнет исключение из-за ошибки. Таким образом, инструкция except («исключение») обозначает завершение операции.
Обратите внимание на зарегистрированные сообщения, чтобы отслеживать, что делает прокси-сервер Python.
После получения входящего запроса вам необходимо извлечь из него хост и порт целевого сервера:
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 () извлекает хост и порт веб-сервера из поля «Host:» («Хост:»). В данном случае хостом является example.com, а порт — 80 (поскольку конкретный порт не указан).
Шаг 5. Пересылка запроса клиента и обработка ответа
Зная целевой хост и порт, теперь вам нужно переслать запрос клиента на целевой сервер. В handle_client_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)
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
Опять же, вам нужно работать по одному фрагменту за раз, так как вы не знаете размер ответа. Если данные пусты, их больше не нужно принимать и операцию можно прервать.
Не забудьте закрыть два сокета, которые вы определили в функции:
# close the sockets
destination_socket.close()
client_socket.close()
Потрясающе! Вы только что создали прокси-сервер HTTP на Python. Пора посмотреть весь код, запустить его и убедиться, что он работает должным образом!
Шаг 6. Соберите все воедино
Это окончательный код скрипта вашего прокси-сервера на Python:
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
В терминале должно появиться следующее сообщение:
Proxy server listening on port 8888...
Чтобы убедиться, что сервер работает, выполните прокси-запрос с помощью cURL. Прочтите наше руководство, чтобы узнать больше о том, как использовать cURL с прокси-сервером.
Откройте новый терминал и запустите:
curl --proxy "http://127.0.0.1:8888" "http://httpbin.org/ip"
Это позволит отправить запрос GET к адресату http://httpbin.org/ip через прокси-сервер http://127.0.0.1:8888.
У вас должно получиться что-то вроде:
{
"origin": "45.12.80.183"
}
Это IP-адрес прокси-сервера. Почему? Поскольку конечная точка /ip проекта HttpBin возвращает IP-адрес, с которого поступил запрос. Если вы запускаете сервер локально, «origin» будет соответствовать вашему IP-адресу.
Примечание: созданный здесь прокси-сервер на Python работает только с адресатами HTTP. Расширить его для обработки HTTPS-подключений довольно сложно.
Теперь изучите журнал, записанный вашим приложением прокси-сервере на Python. Он должен содержать:
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"
}
Это говорит о том, что прокси-сервер получил запрос в формате, указанном протоколом HTTP. Затем он переслал его на целевой сервер, зарегистрировал данные ответа и отправил ответ обратно клиенту. Почему мы в этом уверены? Потому что IP-адреса в «origin» одинаковы!
Поздравляем! Вы только что научились создавать прокси-сервер HTTP на Python!
Плюсы и минусы использования собственного прокси-сервера на Python
Теперь, когда вы знаете, как реализовать прокси-сервер на Python, вы готовы узнать преимущества и недостатки этого подхода.
Преимущества:
- Полный контроль. С помощью такого настраиваемого скрипта Python вы полностью контролируете работу вашего прокси-сервера. Не будет никакой теневой активности или утечки данных!
- Настройка. Прокси-сервер можно расширить, включив в него полезные функции, такие как ведение журнала и кэширование запросов, для повышения производительности.
Недостатки:
- Стоимость инфраструктуры. Настроить архитектуру прокси-сервера непросто и стоит больших денег с точки зрения оборудования или услуг VPS.
- Сложное обслуживание. Вы несете ответственность за сохранение архитектуры прокси-сервера, особенно за его масштабируемость и доступность. С этой задачей могут справиться только опытные системные администраторы.
- Ненадежность. Основная проблема этого решения заключается в том, что выходной IP-адрес прокси-сервера никогда не меняется. В результате технологии защиты от ботов смогут блокировать IP-адрес и препятствовать доступу сервера к нужным запросам. Другими словами, прокси-сервер в конечном итоге перестанет работать.
Эти ограничения и недостатки слишком опасны для использования собственного прокси-сервера Python в производственном сценарии. Решение? Надежный поставщик услуг прокси-серверов, такой как Bright Data! Создайте аккаунт, подтвердите свою личность, получите бесплатный прокси-сервер и используйте его на своем любимом языке программирования. Например, интегрируйте прокси-сервер в свой скрипт Python с помощью запросов.
Наша огромная сеть включает миллионы быстрых, надежных и безопасных прокси-серверов по всему миру. Узнайте, почему мы являемся лучшим поставщиком прокси-серверов.
Заключение
Из этого руководства вы узнали, что такое прокси-сервер и как он работает в Python. В частности, вы узнали, как создать его с нуля с помощью веб-сокетов. Теперь вы стали мастером в созданию прокси-серверов на Python. Основная проблема этого подхода заключается в том, что статический выходной IP-адрес вашего прокси-сервера в конечном итоге приведет к тому, что вас заблокируют. Избегайте этого с помощью ротируемых прокси-серверов Bright Data!
Bright Data контролирует лучшие прокси-серверы в мире, обслуживая компании из списка Fortune 500 и более 20 000 клиентов. Предложение компании включает в себя широкий ассортиментов прокси-серверов различных типов:
- Прокси-серверы для центров обработки данных — более 770 000 IP-адресов центров обработки данных.
- Резидентные прокси-серверы — более 72 млн резидентных IP-адресов в более чем 195 странах.
- Прокси-серверы интернет-провайдеров — более 700 000 IP-адресов интернет-провайдеров.
- Мобильные прокси — более 7 млн мобильных IP-адресов.
Эта надежная, быстрая и глобальная прокси-сеть также является основой ряда сервисов скрейпинга веб-страниц, позволяющих легко извлекать данные с любого сайта.
Кредитная карта не требуется