Guzzle的使用

Guzzle是一个PHP的HTTP客户端,用来轻而易举地发送请求

拦截Guzzle的异常

在laravel框架中,很多时候,我们会这样去拦截异常,但是这样你未必能拦截到Guzzle的各种异常

use Exception;

try {
    $response = $client->request('GET', $api);
} catch (Exception $e) {
    //code...
}

摘抄一份官方文档的说明

请求传输过程中出现的错误Guzzle将会抛出异常。

  • 在发送网络错误(连接超时、DNS错误等)时,将会抛出 GuzzleHttp\Exception\RequestException 异常。 该异常继承自 GuzzleHttp\Exception\TransferException ,捕获这个异常可以在传输请求过程中抛出异常。
use GuzzleHttp\Exception\RequestException;

try {
    $client->request('GET', 'https://github.com/_abc_123_404');
} catch (RequestException $e) {
    echo $e->getRequest();
    if ($e->hasResponse()) {
        echo $e->getResponse();
    }
}
  • GuzzleHttp\Exception\ConnectException 异常发生在网络错误时, 该异常继承自 GuzzleHttp\Exception\RequestException 。
  • 如果 http_errors 请求参数设置成true,在400级别的错误的时候将会抛出 GuzzleHttp\Exception\ClientException 异常, 该异常继承自 GuzzleHttp\Exception\BadResponseException GuzzleHttp\Exception\BadResponseException 继承自 GuzzleHttp\Exception\RequestException 。
use GuzzleHttp\Exception\ClientException;

try {
    $client->request('GET', 'https://github.com/_abc_123_404');
} catch (ClientException $e) {
    echo $e->getRequest();
    echo $e->getResponse();
}
  • 如果 http_errors 请求参数设置成true,在500级别的错误的时候将会抛出 GuzzleHttp\Exception\ServerException 异常。 该异常继承自 GuzzleHttp\Exception\BadResponseException 。
  • GuzzleHttp\Exception\TooManyRedirectsException 异常发生在重定向次数过多时, 该异常继承自 GuzzleHttp\Exception\RequestException 。

  • 上述所有异常均继承自 GuzzleHttp\Exception\TransferException 。

小伙伴这里看到了吧.所有类都集成自TransferException 所以,我们只需要这样做

use GuzzleHttp\Exception\TransferException;

try {
    $response = $client->request('GET', $api);
} catch (TransferException $e) {
    //code...
}

设置不抛出异常

很多时候,guzzle抛出异常并不是特别好,特别在api的时候,我们可以通过参数取消异常抛出

http_errors 改为false即可

$response = $http->request('get', $url, [
     //.....
    'http_errors' => false
]);

模拟登陆

如果对方设置了csrf_token的话,目前无法破..目测就只能登录好然后提取出cookie来登录了

自动登录,并储存cookie,下次自动登录[推荐]

if (Redis::exists('ailuoy_cookies')) {
    $client = new Client();
    //取出cookie
    $cookieJar = unserialize(Redis::get('ailuoy_cookies'));
    $response = $client->request('GET', "https://iluoy.com/articles/237/edit", [
        'cookies' => $cookieJar
    ]);
    //获取结果
    dd($response->getBody()->getContents());
}else{
    //实例化一个空的cookie对象
    $jar = new \GuzzleHttp\Cookie\CookieJar;
    // ['cookies' => true]
    $client = new Client();
    $api = 'https://iluoy.com/login';
    // 登录账号
    $login = $client->request('POST', $api, [
        'form_params' => ['name' => 'ailuoy', 'password' => '111111'],
        'cookies'     => $jar
    ]);
    //当登录成功之后 $jar 就是登录成功后,服务端给我们的cookie了
    //把捕获到的cookie存到redis,下次就不用登陆了,直接用redis的cookie即可
    Redis::set('ailuoy_cookies', serialize($jar));
    dd(unserialize(Redis::get('ailuoy_cookies')));
}

自定义cookie携带

 $client = new Client();
//自定义cookie
$cookieJar = CookieJar::fromArray([
    'PHPSESSID' => 'b68212de1826c64d77b69dc514c2a9cb'
], 'iluoy.com');

$response = $client->request('GET', "https://iluoy.com/articles/237/edit", [
    'cookies' => $cookieJar
]);
//获取结果
dd($response->getBody()->getContents());

每次都执行登录,并自动使用cookie

不太建议,登录太频繁了..

// 设置 cookies 为true
$client = new Client(['cookies' => true]);
$api = 'https://iluoy.com/login';
// 登录账号
$login = $client->request('POST', $api, [
    'form_params' => ['name' => 'ailuoy', 'password' => '111111'],
]);
$response = $client->request('GET', "https://iluoy.com/articles/236/edit");
dd($response->getBody()->getContents());

guzzle并发爬数据

很多时候,我们需要去向一个api请求分页数据,如果循环的请求的话,速度那贼慢...

$client = $this->client;
$results = [];
// 设置发送的进程数量
$totalPageCount = (int)$count / 10;
$headers = [
    'Content-Type' => 'application/x-www-form-urlencoded',
    'user-agent'   => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.3'
];
$requests = function ($total) use ($client, $songId, $totalPageCount, $headers) {
    for ($page = 1; $page <= $totalPageCount; $page++) {
        $api = 'https://www.xiami.com/commentlist/turnpage/id/' . $songId . '/page/' . $page . '/ajax/1';
        yield function () use ($client, $api, $headers) {
            return $client->postAsync($api, [
                'headers'     => $headers,
                'config'      => $this->getConfig(),
                'form_params' => ['type' => 4]
            ]);
        };
    }
};
$pool = new Pool($client, $requests($totalPageCount), [
    'concurrency' => $totalPageCount,
    'fulfilled'   => function ($response, $index) use(&$result){
        //如果你要在外面拿到$result要引用传值
        //成功的情况
        $comments = $response->getBody()->getContents();
        $this->musicComments = array_merge($this->musicComments,$this->filterComments($comments));
        $results[] = $this->musicComments;
    },
    'rejected'    => function ($reason, $index) {
        //失败的情况
    },
]);
$promise = $pool->promise();
$promise->wait();
$comments = array_slice($this->musicComments, 0, $count);

设置cookie

use GuzzleHttp\Cookie\CookieJar;

$cookieJar = CookieJar::fromArray([
    'cookie_name' => 'cookie_value'
], 'example.com');

$client->request('GET', '/get', ['cookies' => $cookieJar]);

获得http响应异常的body

$client = new Client();
try {
    $response = $client->post('xxxxx');
} catch (\GuzzleHttp\Exception\ClientException $e) {
    dd($e->getResponse()->getBody()->getContents());
}

设置统一的发送方法

统一发送方法

 private function sendAuthRequest(Request $request, Account $account)
{

}

参考文献