Cómo configurar un proxy con Guzzle

Supera los retos del raspado web con Guzzle y proxies. Asegúrate de que PHP 7.2.5+ y Composer estén configurados y, a continuación, integra Guzzle para la configuración del proxy.
2 min read
Setting a proxy in Guzzle blog image

En el contexto del uso de Guzzle, un proxy actúa como un servidor intermediario que conecta tu aplicación cliente con el servidor web deseado. Facilita el reenvío de tus solicitudes al servidor deseado y devuelve la respuesta del servidor a tu cliente. Además, los proxies son fundamentales para eludir las restricciones basadas en IP que pueden bloquear las actividades de raspado web o limitar el acceso a ciertos sitios web, además de ofrecer ventajas como almacenar en caché las respuestas del servidor para reducir la cantidad de solicitudes directas al servidor de destino.

Esta introducción describe los aspectos fundamentales para utilizar un proxy de forma eficaz con Guzzle.

Requisitos para empezar: cómo integrar

Antes de continuar, asegúrate de tener la versión 7.2.5 o superior de PHP y Composer instaladas en tu sistema. Tener unos conocimientos básicos de raspado web con PHP también será beneficioso para seguir esta guía. Empieza por crear un nuevo directorio para tu proyecto y usa Composer para instalar Guzzle en él:

composer require guzzlehttp/guzzle

A continuación, crea un archivo PHP en el directorio recién establecido e incluye el cargador automático de Composer para continuar:

<?php
// Load Composer's autoloader
require 'vendor/autoload.php';

Una vez hecho esto, estamos listos para configurar los ajustes del proxy.

Utilización de un proxy con Guzzle

Este segmento muestra cómo emitir una solicitud a través de Guzzle utilizando un proxy y autenticarla. Inicialmente, consigue los proxies asegurándote de que estén activos y sigan el siguiente formato: ://:@:.

Información clave: Guzzle permite el uso de proxies mediante opciones de solicitud o middleware. Para configuraciones de proxy sencillas y sin cambios, las opciones de solicitud son adecuadas. Por el contrario, el middleware ofrece mayor flexibilidad y control, aunque con una mayor configuración inicial.

Profundizaremos en ambos enfoques empezando por las opciones de solicitud, que implican la importación de las clases Client y RequestOptions de Guzzle para su configuración.

Método A: configurar un proxy de Guzzle con opciones de solicitud

Para configurar un proxy con opciones de solicitud, empieza por importar las clases Client y RequestOptions de Guzzle:

use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;

A continuación, define tu URL de destino y una matriz asociativa de todos los proxies que usarás:

# make request to
$targetUrl = 'https://lumtest.com/myip.json';

# proxies
$proxies = [
    'http'  => 'http://USERNAME:[email protected]:22225',
    'https' => 'http://USERNAME:[email protected]:22225',
];

La URL de destino especificada, lumtest, está diseñada para devolver la dirección IP de cualquier cliente que le envíe una solicitud GET. Esta configuración permite a Guzzle gestionar el tráfico HTTP y HTTPS, enrutándolo a través de los proxies HTTP y HTTPS designados como corresponde.

A continuación, iniciaremos una instancia de cliente de Guzzle, incorporando los proxies previamente definidos asignándolos a la opción de proxy en la configuración de Guzzle.

$client = new Client([
RequestOptions::PROXY => $proxies,
RequestOptions::VERIFY => false, # disable SSL certificate validation
RequestOptions::TIMEOUT => 30, # timeout of 30 seconds
]);

Debido a que los servidores proxy suelen tener problemas con la verificación SSL, esta configuración opta por inhabilitar la verificación mediante la opción de verificar. Además, la configuración del tiempo de espera restringe la duración de cada solicitud a un máximo de treinta segundos. Tras esta configuración, ejecutaremos la solicitud y aparecerá la respuesta resultante.

try {
$body = $client->get($targetUrl)->getBody();
echo $body->getContents();
} catch (\Exception $e) {
echo $e->getMessage();
}

A estas alturas, tu secuencia de comandos en PHP debería parecerse a esto:

'http://USERNAME:[email protected]:22225', 'https' => 'http://USERNAME:[email protected]:22225', ]; $client = new Client([ RequestOptions::PROXY => $proxies, RequestOptions::VERIFY => false, # disable SSL certificate validation RequestOptions::TIMEOUT => 30, # timeout of 30 seconds ]); try { $body = $client->get($targetUrl)->getBody(); echo $body->getContents(); } catch (\Exception $e) { echo $e->getMessage(); } ?>

Ejecuta tu secuencia con el comando .php y recibirás un resultado similar al del ejemplo que se muestra a continuación:

{"ip":"212.80.220.187","country":"IE","asn":{"asnum":9009,"org_name":"M247 Europe SRL"},"geo":{"city":"Dublin","region":"L","region_name":"Leinster","postal_code":"D12","latitude":53.323,"longitude":-6.3159,"tz":"Europe/Dublin","lum_city":"dublin","lum_region":"l"}}

¡Excelente! El valor de la clave IP corresponde a la dirección IP del cliente que inicia la solicitud a lumtest. En este caso, debería reflejar los proxies que has configurado.

Enfoque B: utilización de middleware

El uso de middleware para configurar un proxy HTTP de Guzzle sigue un patrón similar al del primer método. La única diferencia radica en la creación e incorporación de middleware proxy en la pila de controladores predeterminada.

Para empezar, ajusta la importación de la siguiente manera:

# ...
use Psr\Http\Message\RequestInterface;
use GuzzleHttp\HandlerStack;
# ...

A continuación, establece un middleware de proxy insertando el siguiente código inmediatamente después de la matriz $proxies. Este middleware interceptará todas las solicitudes y configurará los proxies en consecuencia.

function proxy_middleware(array $proxies) 
{
    return function (callable $handler) use ($proxies) {
        return function (RequestInterface $request, array $options) use ($handler, $proxies) {
            # add proxy to request option
            $options[RequestOptions::PROXY] = $proxies; 
            return $handler($request, $options);
        };
    };
}

Ahora, podemos integrar el middleware en la pila de controladores predeterminada y actualizar nuestro cliente de Guzzle incorporando la pila:

$stack = HandlerStack::create();
$stack->push(proxy_middleware($proxies));

$client = new Client([
    'handler' => $stack,
    RequestOptions::VERIFY => false, # disable SSL certificate validation
    RequestOptions::TIMEOUT => 30, # timeout of 30 seconds
]);

Tu secuencia de comandos en PHP debería tener este aspecto:

<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\RequestInterface;
use GuzzleHttp\HandlerStack;
# make request to
$targetUrl = 'https://lumtest.com/myip.json';

# proxies
$proxies = [
    'http'  => 'http://USERNAME:[email protected]:22225',
    'https' => 'http://USERNAME:[email protected]:22225',
];
function proxy_middleware(array $proxies) 
{
    return function (callable $handler) use ($proxies) {
        return function (RequestInterface $request, array $options) use ($handler, $proxies) {
            # add proxy to request option
            $options[RequestOptions::PROXY] = $proxies; 
            return $handler($request, $options);
        };
    };
}

$stack = HandlerStack::create();
$stack->push(proxy_middleware($proxies));

$client = new Client([
    'handler' => $stack,
    RequestOptions::VERIFY => false, # disable SSL certificate validation
    RequestOptions::TIMEOUT => 30, # timeout of 30 seconds
]);

try {
    $body = $client->get($targetUrl)->getBody();
    echo $body->getContents();
} catch (\Exception $e) {
    echo $e->getMessage();
}

?>

Ejecuta la secuencia de comandos en PHP una vez más y obtendrás resultados similares a los del otro método.

La implementación de un proxy rotativo con Guzzle implica utilizar un servidor proxy que cambia las direcciones IP con frecuencia. Este enfoque ayuda a eludir el bloqueo de IP, ya que cada solicitud se origina en una IP distinta, lo que complica la identificación de los bots que proceden de una única fuente.

Empezaremos por implementar un proxy rotativo con Guzzle; esto es bastante sencillo cuando se utilizan los servicios de proxyde Bright Data, por ejemplo:

function get_random_proxies(): array {
    // Base proxy URL before the session identifier
    $baseProxyUrl = 'http://USERNAME-session-';

   
    $sessionSuffix = rand(1000, 9999); // Random integer between 1000 and 9999
    $proxyCredentials = ':[email protected]:22225';

    $httpProxy = $baseProxyUrl . $sessionSuffix . $proxyCredentials;
    $httpsProxy = $baseProxyUrl . $sessionSuffix . $proxyCredentials;


    $proxies = [
        'http'  => $httpProxy,
        'https' => $httpsProxy,
    ];

    return $proxies;
}

Ahora, añade la función deseada y llámala:

function rotating_proxy_request(string $http_method, string $targetUrl, int $max_attempts = 3): string
{
    $response = null;
    $attempts = 1;

    while ($attempts <= $max_attempts) {
        $proxies = get_random_proxies();
        echo "Using proxy: ".json_encode($proxies).PHP_EOL;
        $client = new Client([
            RequestOptions::PROXY => $proxies,
            RequestOptions::VERIFY => false, # disable SSL certificate validation
            RequestOptions::TIMEOUT => 30, # timeout of 30 seconds
        ]);
        try {
            $body = $client->request(strtoupper($http_method), $targetUrl)->getBody();
            $response = $body->getContents();
            break;
        } catch (\Exception $e) {
            echo $e->getMessage().PHP_EOL;
            echo "Attempt ".$attempts." failed!".PHP_EOL;
            if ($attempts < $max_attempts) {
                echo "Retrying with a new proxy".PHP_EOL;
            }
            $attempts += 1;
        }
    }
    return $response;
}

$response = rotating_proxy_request('get', 'https://lumtest.com/myip.json');

echo $response;

Esta es la secuencia de comandos en PHP completa:

<?php
# composer's autoloader
require 'vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;

function get_random_proxies(): array {
    // Base proxy URL before the session identifier
    $baseProxyUrl = 'http://USERNAME-session-';

    // Session ID suffix and proxy credentials
    $sessionSuffix = rand(1000, 9999); // Random integer between 1000 and 9999
    $proxyCredentials = ':[email protected]:22225';

    // Assemble the full proxy URLs with the randomized session ID
    $httpProxy = $baseProxyUrl . $sessionSuffix . $proxyCredentials;
    $httpsProxy = $baseProxyUrl . $sessionSuffix . $proxyCredentials;

    // Package and return the proxies
    $proxies = [
        'http'  => $httpProxy,
        'https' => $httpsProxy,
    ];

    return $proxies;
}


function rotating_proxy_request(string $http_method, string $targetUrl, int $max_attempts = 3): string
{
    $response = null;
    $attempts = 1;

    while ($attempts <= $max_attempts) {
        $proxies = get_random_proxies();
        echo "Using proxy: ".json_encode($proxies).PHP_EOL;
        $client = new Client([
            RequestOptions::PROXY => $proxies,
            RequestOptions::VERIFY => false, # disable SSL certificate validation
            RequestOptions::TIMEOUT => 30, # timeout of 30 seconds
        ]);
        try {
            $body = $client->request(strtoupper($http_method), $targetUrl)->getBody();
            $response = $body->getContents();
            break;
        } catch (\Exception $e) {
            echo $e->getMessage().PHP_EOL;
            echo "Attempt ".$attempts." failed!".PHP_EOL;
            if ($attempts < $max_attempts) {
                echo "Retrying with a new proxy".PHP_EOL;
            }
            $attempts += 1;
        }
    }
    return $response;
}

$response = rotating_proxy_request('get', 'https://lumtest.com/myip.json');

echo $response;

Conclusión

En esta guía, hemos explicado los pasos necesarios para integrar proxies con Guzzle. Has aprendido:

  • Los fundamentos del uso de un proxy cuando se trabaja con Guzzle.
  • Estrategias para implementar un sistema de proxy rotativo.

Bright Data ofrece un servicio de proxy rotativo fiable al que se puede acceder mediante llamadas a la API, junto con funciones sofisticadas diseñadas para eludir las medidas antibot y mejorar la eficiencia de tus operaciones de raspado web.