Guzzle中如何设置代理
当您尝试从网站上抓取信息时,您的 IP 地址可能已被屏蔽。很烦人吧?
幸运的是,您可以使用代理隐藏您的 IP,并像某人一样访问该网站。Guzzle(流行的 PHP HTTP 客户端)使这一切变得简单。
因此,让我们深入了解如何通过 Guzzle 使用代理。
什么是 Guzzle 代理
使用 Guzzle 时,代理是位于客户端和目标服务器之间的服务器。它将您的请求发送到目标服务器并向您的客户端提供响应。
此外,代理还可以绕过防止网页抓取或限制网站访问、缓存响应和限制目标服务器请求的 IP 禁令。
让我们看看正确使用 Guzzle 代理需要什么。
先决条件
在继续之前,请确保您已安装PHP >= v7.2.5和Composer。此外,如果您了解PHP 中网页抓取的基础知识,那么学习本教程将会更容易。
创建一个 demo 目录并在其中安装Guzzle :
composer require guzzlehttp/guzzle
然后,在刚刚创建的目录中创建一个演示 PHP 文件,并需要 Composer 的自动加载器:
<?php # composer's autoloader require 'vendor/autoload.php';
现在,让我们设置代理。
如何通过 Guzzle 使用代理
在本部分中,您将学习如何使用代理通过 Guzzle 发送请求以及对代理进行身份验证。首先,您需要一些代理,因此请从免费代理列表中获取一些。
确保您选择具有良好正常运行时间的有效代理,并且代理 URL 采用以下格式:
<PROXY_PROTOCOL>://<PROXY_IP_ADDRESS>:<PROXY_PORT>
现在需要了解的重要一点是,您可以通过 Guzzle或中间件使用代理request-options
。
总的来说,如果您需要简单且静态的代理配置,使用request-options
是一个不错的选择。同时,使用中间件可以提供更大的灵活性和对代理行为的控制,但需要更多的设置。
我们来探讨一下这两种方法。
方法 A:使用请求选项设置 Guzzle 代理
要使用 设置代理request-options
,首先导入 GuzzleClient
和RequestOptions
类:
use GuzzleHttpClient; use GuzzleHttpRequestOptions;
然后,定义您的目标 URL 以及您将使用的所有代理的关联数组:
# make request to $targetUrl = 'https://httpbin.org/ip'; # proxies $proxies = [ 'http' => 'http://190.43.92.130:999', 'https' => 'http://5.78.76.237:8080', ];
上面定义的目标 URL 是HTTPBinGET
,它返回向其发出请求的任何客户端的 IP 地址。Guzzle 将通过上面定义的 HTTP 和 HTTPS 代理处理 HTTP 和 HTTPS 流量。
免费代理仅在有限的时间内有效。上面列出的那些可能不适合您,因此请用新的替换它们。除了 HTTP 和 HTTPS 之外,Guzzle 还支持其他代理协议,包括 SOCKS5。
现在,让我们创建一个 Guzzle 客户端并传递我们定义为 Guzzle 选项值的代理proxy
:
$client = new Client([ RequestOptions::PROXY => $proxies, RequestOptions::VERIFY => false, # disable SSL certificate validation RequestOptions::TIMEOUT => 30, # timeout of 30 seconds ]);
由于代理服务器在 SSL 验证期间无法正常工作,因此verify
此处的选项将其禁用。该timeout
选项将每个请求的超时限制为三十秒。
然后,让我们发出请求并打印响应:
try { $body = $client->get($targetUrl)->getBody(); echo $body->getContents(); } catch (Exception $e) { echo $e->getMessage(); }
此时,您的 PHP 脚本应如下所示:
<?php # composer's autoloader require 'vendor/autoload.php'; use GuzzleHttpClient; use GuzzleHttpRequestOptions; # make request to $targetUrl = 'https://httpbin.org/ip'; # proxies $proxies = [ 'http' => 'http://190.43.92.130:999', 'https' => 'http://5.78.76.237:8080', ]; $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(); }
使用 运行脚本php <filename>.php
,您将获得类似于以下内容的输出:
{ "origin": "5.78.76.237" }
键的值origin
是向 HTTPBin 发出请求的客户端的 IP 地址。在这种情况下,这应该是您定义的代理。
如果您收到错误,请从列表中选择新代理并重试。
方法B:使用中间件
使用中间件设置 Guzzle HTTP 代理与第一种方法类似。唯一的区别是我们将创建代理中间件并将其添加到默认处理程序堆栈中。
首先,像这样更新您的导入:
# ... use PsrHttpMessageRequestInterface; use GuzzleHttpHandlerStack; # ...
接下来,通过在数组后面添加以下代码来创建代理中间件,$proxies
以拦截每个请求并设置代理。
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); }; }; }
现在,我们可以将中间件添加到默认处理程序堆栈中,并使用该堆栈更新我们的 Guzzle 客户端:
$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 ]);
您的 PHP 脚本应如下所示:
<?php # composer's autoloader require 'vendor/autoload.php'; use GuzzleHttpClient; use GuzzleHttpRequestOptions; use PsrHttpMessageRequestInterface; use GuzzleHttpHandlerStack; # make request to $targetUrl = 'https://httpbin.org/ip'; # proxies $proxies = [ 'http' => 'http://username:[email protected]:999', 'https' => 'http://username:[email protected]:8080', ]; 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(); }
再次运行 PHP 脚本,您将得到与其他方法类似的结果。
使用 Guzzle 进行代理身份验证
某些代理服务器在授予访问权限之前需要进行客户端身份验证,这在使用高级代理或商业解决方案时很常见。如果是这种情况,请将身份验证选项(通常是用户名和密码)添加到代理字符串中。
Guzzle 代理字符串的语法将如下所示:
<PROXY_PROTOCOL>://<USERNAME>:<PASSWORD>@<PROXY_IP_ADDRESS>:<PROXY_PORT>
这是一个例子:
# ... # proxies $proxies = [ 'http' => 'http://username:[email protected]:999', 'https' => 'http://username:[email protected]:8080', ]; # ...
如果未提供有效凭据,将返回状态代码407(需要代理身份验证)的 HTTP 错误,因此请始终确保传递正确的凭据。
将旋转代理与 Guzzle 结合使用
轮换代理是定期在不同IP地址之间切换的代理服务器。它可以帮助防止 IP 阻塞,因为每个请求都是从不同的 IP 发送的,从而使网站更难识别来自同一来源的机器人。
让我们用 Guzzle 实现一个旋转代理,首先使用免费解决方案,然后使用专业解决方案。
使用免费解决方案轮换 IP
我们将从一个使用 Guzzle 代理请求的抓取工具开始,并重试设定的最大尝试次数,直到使用免费代理列表成功为止。
首先,编写一个返回随机代理的函数:
function get_random_proxies(): array { $http_proxies = array( 'http://190.43.92.130:999', 'http://201.182.251.142:999', # ... 'http://200.123.15.250:999' ); $https_proxies = array( 'http://5.78.76.237:8080', 'http://8.218.239.205:8888', # ... 'http://169.55.89.6:80' ); $http_proxy = $http_proxies[array_rand($http_proxies)]; $https_proxy = $https_proxies[array_rand($https_proxies)]; # proxies $proxies = [ 'http' => $http_proxy, 'https' => $https_proxy, ]; return $proxies; }
从免费代理列表或我们的最佳代理列表中获取新代理,并分别更新$http_proxies
和$https_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://httpbin.org/ip'); // $response = rotating_proxy_request('get', 'https://www.g2.com/products/zenrows/reviews'); # 403 echo $response;
这是完整的 PHP 脚本:
<?php # composer's autoloader require 'vendor/autoload.php'; use GuzzleHttpClient; use GuzzleHttpRequestOptions; function get_random_proxies(): array { $http_proxies = array( 'http://190.43.92.130:999', 'http://201.182.251.142:999', # ... 'http://200.123.15.250:999' ); $https_proxies = array( 'http://5.78.76.237:8080', 'http://8.218.239.205:8888', # ... 'http://169.55.89.6:80' ); $http_proxy = $http_proxies[array_rand($http_proxies)]; $https_proxy = $https_proxies[array_rand($https_proxies)]; # proxies $proxies = [ 'http' => $http_proxy, 'https' => $https_proxy, ]; 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://httpbin.org/ip'); // $response = rotating_proxy_request('get', 'https://www.g2.com/products/zenrows/reviews'); # 403 echo $response;
如果运行该脚本,您将获得与上一节类似的结果,但如果不成功,请求将重试最多 3 次。
查看我们的深入教程,了解有关代理轮换的更多信息。
然而,免费代理并不可靠,并且可能会失败。让我们通过向 发出请求来测试一下G2.com
。
使用以下代码更新脚本:
# ... $response = rotating_proxy_request('get', 'https://www.g2.com/products/zenrows/reviews'); echo $response;
运行它,你会得到类似这样的结果:
我们收到状态代码为403(禁止)的错误,因为轮换代理可能被识别为机器人。
更好的解决方案是使用高级代理。我们接下来看看。
高级代理以避免被阻止
使用高级代理是避免被阻止的最佳方法。拥有帐户后,从代理 URL 复制 ZenRows API 密钥。另外,激活高级代理旋转器,加上反机器人和 JavaScript 渲染,以便做好更好的准备。
像这样更新你的 PHP 脚本:
<?php # composer's autoloader require 'vendor/autoload.php'; use GuzzleHttpClient; use GuzzleHttpRequestOptions; # make request to $targetUrl = 'https://www.g2.com/products/zenrows/reviews'; $proxy = 'http://<YOUR_ZENROWS_API_KEY>:[email protected]:8001'; # proxies $proxies = [ 'http' => $proxy, 'https' => $proxy, ]; $client = new Client([ RequestOptions::PROXY => $proxies, RequestOptions::VERIFY => false, # disable SSL certificate validation ]); try { $body = $client->get($targetUrl)->getBody(); echo $body->getContents(); } catch (Exception $e) { echo $e->getMessage(); }
替换<YOUR_ZENROWS_API_KEY>
为您之前复制的 ZenRows API 密钥。运行它,你会看到输出:
替换<YOUR_ZENROWS_API_KEY>
为您之前复制的 ZenRows API 密钥。运行它,你会看到输出:
您的高级 Guzzle 代理脚本已准备好使用!
ZenRows 为您提供所需的所有工具,例如反机器人和 JS 渲染。您可以探索 ZenRows 仪表板上提供的所有选项。
结论
本教程展示了在 Guzzle 中使用代理所需的步骤。现在你知道了:
- 通过 Guzzle 使用代理的基础知识。
- 如何实现旋转代理。
- 为什么高级代理更好以及如何使用它们。
由于免费代理不可靠并且只能用于测试,因此请考虑使用高级提供商。