Компонент BrowserKit
Дата обновления перевода 2024-07-03
Компонент BrowserKit
Компонент BrowserKit симулирует поведение веб-браузера, позволяя вам программно делать запросы, нажимать на ссылки и отправлять формы.
Установка
1
$ composer require symfony/browser-kit
Note
Если вы устанавливаете этот компонент вне приложения Symfony, вам нужно
подключить файл vendor/autoload.php
в вашем коде для включения механизма
автозагрузки классов, предоставляемых Composer. Детальнее читайте в
этой статье.
Базовое применение
See also
Эта статья объясняет как использовать функции BrowserKit как независимый компонент в любом PHP-приложении. Прочитайте статью Функциональные тесты Symfony для того, чтобы понять как использовать его в приложениях Symfony.
Создание клиента
Компонент предоставляет только абстрактного клиента, и не предоставляет готового
к использованию бэк-энда для уровня HTTP. Чтобы создать вашего собственного клиента, вам
нужно расширить класс AbstractBrowser
и реализовать метод
doRequest(). Этот метод принимает запрос и
должен вернуть ответ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
namespace Acme;
use Symfony\Component\BrowserKit\AbstractBrowser;
use Symfony\Component\BrowserKit\Response;
class Client extends AbstractBrowser
{
protected function doRequest($request): Response
{
// ... преобразовать запрос в ответ
return new Response($content, $status, $headers);
}
}
Для простой реализации браузера, основанного на слое HTTP, посмотрите на
HttpBrowser, предоставленный
этим компонентом . Для реализации,
основанной на HttpKernelInterface
, посмотрите на HttpClientKernel,
предоставленный компонентом HttpKernel.
Как делать запросы
Используйте метод request(), чтобы делать HTTP запросы. Первые два аргумента - HTTP метод и запрошенный URL:
1 2 3 4
use Acme\Client;
$client = new Client();
$crawler = $client->request('GET', '/');
Значение, возвращённое методом request()
- это экземпляр класса
Crawler, предоставленный
DomCrawler component, который разрешает
программный доступ и траверсирование HTML элементов.
Метод jsonRequest(),
который определяет те же аргументы, что и метод request()
, является ярлыком для
преобразования параметров запроса в JSON-строку и установки необходимых HTTP-заголовков:
1 2 3 4 5
use Acme\Client;
$client = new Client();
// это зашифровывает параметры как JSON, и устанавливает необходимые заголовки CONTENT_TYPE и HTTP_ACCEPT
$crawler = $client->jsonRequest('GET', '/', ['some_parameter' => 'some_value']);
Метод xmlHttpRequest(),
который определяет те же аргументы, что и метод request()
, является ярлыков для
создания AJAX-запросов:
1 2 3 4 5
use Acme\Client;
$client = new Client();
// необходимый заголовок HTTP_X_REQUESTED_WITH добавляется автоматически
$crawler = $client->xmlHttpRequest('GET', '/');
Нажатие ссылок
AbstractBrowser
способен симулировать нажатие на ссылки. Передайте содержимое
текста ссылки, а клиент выполнит необходимый запрос HTTP GET, чтобы симулировать
нажатие на ссылку:
1 2 3 4 5 6
use Acme\Client;
$client = new Client();
$client->request('GET', '/product/123');
$crawler = $client->clickLink('Go elsewhere...');
Если вам нужен объект Link, который предоставляет
доступ к свойствам ссылки (например, $link->getMethod()
, $link->getUri()
), используйте
этот другой метод:
1 2 3 4
// ...
$crawler = $client->request('GET', '/product/123');
$link = $crawler->selectLink('Go elsewhere...')->link();
$client->click($link);
Методы click() и
clickLink() могут
принимать опциональный аргумент serverParameters
. Этот параметр позволяет
вам отправлять дополнительную информацию вроде заголовков при нажатии на ссылку:
1 2 3 4 5 6 7 8 9 10 11
use Acme\Client;
$client = new Client();
$client->request('GET', '/product/123');
// работает как с `click()`...
$link = $crawler->selectLink('Go elsewhere...')->link();
$client->click($link, ['X-Custom-Header' => 'Some data']);
// ... так и с `clickLink()`
$crawler = $client->clickLink('Go elsewhere...', ['X-Custom-Header' => 'Some data']);
Отправка форм
AbstractBrowser
также способен отправлять формы. Для начала, выберите
форму, используя любую ее кнопку, а затем переопределите любое из ее свойств
(метод, значение поля и др.), до ее отправки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
use Acme\Client;
$client = new Client();
$crawler = $client->request('GET', 'https://github.com/login');
// найти форму с кнопкой 'Log in' и отправить ее
// 'Log in' может быть текстовым содержанием, id, значением или именем <button> или <input type="submit">
$client->submitForm('Log in');
// второй необязательный аргумент позволяет вам переопределять значения полей формы по умолчанию
$client->submitForm('Log in', [
'login' => 'my_user',
'password' => 'my_pass',
// чтобы загрузить файл, значение должно быть абсолютным путем файла
'file' => __FILE__,
]);
// вы можете также переопределить другие опции формы
$client->submitForm(
'Log in',
['login' => 'my_user', 'password' => 'my_pass'],
// переопределить HTTP-метод формы по умолчанию
'PUT',
// переопределить некоторые параметры $_SERVER (например, HTTP-заголовки)
['HTTP_ACCEPT_LANGUAGE' => 'es']
);
Если вам нужен объект Form, который
предоставляет доступ к свойствам формы (например, $form->getUri()
,
$form->getValues()
, $form->getFields()
), используйте этот другой метод:
1 2 3 4 5 6 7 8 9
// ...
// выбрать форму и заполнить какие-то значения
$form = $crawler->selectButton('Log in')->form();
$form['login'] = 'symfonyfan';
$form['password'] = 'anypass';
// отправить эту форму
$crawler = $client->submit($form);
Обработка пользовательских заголовков
Необязательные HTTP-заголовки, переданные методу request()
, следуют формату запросу
FastCGI (верхний регистр, нижние подчеркивания вместо дефисов и префикс HTTP_
).
До сохранения этих заголовков в запрос, они переводятся в нижний регистр, HTTP_
убирается, а нижние подчеркивания преобразуются в дефисы.
Если вы делаете запрос к приложению, которое имеет специальные правила о регистре
или пунктуации заголовков, переопределите метод getHeaders()
, который должен возвращать
ассоциированный массив заголовков:
1 2 3 4 5 6 7 8 9
protected function getHeaders(Request $request): array
{
$headers = parent::getHeaders($request);
if (isset($request->getServer()['api_key'])) {
$headers['api_key'] = $request->getServer()['api_key'];
}
return $headers;
}
Куки
Извлечение куки
Реализация AbstractBrowser
отображает cookie (если они есть) через класс
CookieJar, который позволяет вам
хранить и извлекать любой cookie во время выполнения запросов с клиентом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
use Acme\Client;
// Сделать запрос
$client = new Client();
$crawler = $client->request('GET', '/');
// Получить cookie Jar
$cookieJar = $client->getCookieJar();
// Получить куки по имени
$cookie = $cookieJar->get('name_of_the_cookie');
// Получить данные куки
$name = $cookie->getName();
$value = $cookie->getValue();
$rawValue = $cookie->getRawValue();
$isSecure = $cookie->isSecure();
$isHttpOnly = $cookie->isHttpOnly();
$isExpired = $cookie->isExpired();
$expires = $cookie->getExpiresTime();
$path = $cookie->getPath();
$domain = $cookie->getDomain();
$sameSite = $cookie->getSameSite();
Note
Эти методы возвращают только cookie, срок действия которых не истёк.
Закольцовывание через куки
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
use Acme\Client;
// Сделать запрос
$client = new Client();
$crawler = $client->request('GET', '/');
// Получить cookie Jar
$cookieJar = $client->getCookieJar();
// Получить массив со всеми куки
$cookies = $cookieJar->all();
foreach ($cookies as $cookie) {
// ...
}
// Получить все значения
$values = $cookieJar->allValues('http://symfony.com');
foreach ($values as $value) {
// ...
}
// Получить все сырые значения
$rawValues = $cookieJar->allRawValues('http://symfony.com');
foreach ($rawValues as $rawValue) {
// ...
}
Установка куки
Вы также можете создавать куки и добавлять их в cookie jar, которая может быть внедрена в конструктор клиента:
1 2 3 4 5 6 7 8 9 10
use Acme\Client;
// создайте куки и добавьте в cookie jar
$cookie = new Cookie('flavor', 'chocolate', strtotime('+1 day'));
$cookieJar = new CookieJar();
$cookieJar->set($cookie);
// создайте клиента и установите куки
$client = new Client(array(), null, $cookieJar);
// ...
Отправка куки
Запросы могут содержать куки. Чтобы сделать это, используйте аргумент serverParameters
метода request(), чтобы
установить значение заголовка Cookie
:
1 2 3 4 5 6
$client->request('GET', '/', [], [], [
'HTTP_COOKIE' => new Cookie('flavor', 'chocolate', strtotime('+1 day')),
// вы также можете передать содержание куки в виде строки
'HTTP_COOKIE' => 'flavor=chocolate; expires=Sat, 11 Feb 2023 12:18:13 GMT; Max-Age=86400; path=/'
]);
Note
Все HTTP-заголовки, установленные с аргументом serverParameters
, должны
иметь префикс HTTP_
.
История
Клиент хранит все ваши запросы, позволяя вам перемещаться по вашей истории вперёд и назад:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
use Acme\Client;
$client = new Client();
$client->request('GET', '/');
// выберите и нажмите на ссылку
$link = $crawler->selectLink('Documentation')->link();
$client->click($link);
// перейдите назад к домашней странице
$crawler = $client->back();
// перейдите вперёд к странице документации
$crawler = $client->forward();
Вы можете удалять историю клиента методом restart()
. Это также удалит
все cookie:
1 2 3 4 5 6 7
use Acme\Client;
$client = new Client();
$client->request('GET', '/');
// перезапустите клиента (история и куки также очищаются)
$client->restart();
Внешние HTTP-запросы
До сих пор, все примеры в этой статье предполагали, что вы делаете внутренние запросы к вашему собственному приложению. Однако, вы можете выполнить точно такие же примеры во время HTTP-запросов ко внешним веб-сайтам и приложениям.
Для начала, установите и сконфигурируйте компонент HttpClient. Затем, используйте HttpBrowser, чтобы создать клиента, который будет делать внешние HTTP-запросы:
1 2 3 4
use Symfony\Component\BrowserKit\HttpBrowser;
use Symfony\Component\HttpClient\HttpClient;
$browser = new HttpBrowser(HttpClient::create());
Теперь вы можете использовать любой из методов, показанных в этой статье, чтобы извлекать информацию, нажимать на ссылки, отправлять формы и т.д. Это означает, что вам больше не нужно использовать соответствующий веб-краулер или скрейпер, вроде Goutte:
1 2 3 4 5 6 7 8
$browser = new HttpBrowser(HttpClient::create());
$browser->request('GET', 'https://github.com');
$browser->clickLink('Sign in');
$browser->submitForm('Sign in', ['login' => '...', 'password' => '...']);
$openPullRequests = trim($browser->clickLink('Pull requests')->filter(
'.table-list-header-toggle a:nth-child(1)'
)->text());
Tip
Вы также можете использовать опции HTTP-клиента вроде ciphers
, auth_basic
и query
. Они должны быть переданы как аргумент опции по умолчанию клиенту, который
используется HTTP-браузером.
Работа с HTTP-ответами
При использовании компонента BrowserKit, вам может понадобиться работать с ответами запросов,
которые вы сделали. Чтобы сделать это, вызовите метод getResponse()
объекта HttpBrowser
.
Этот метод возвращает последний ответ, полученный браузером:
1 2 3 4
$browser = new HttpBrowser(HttpClient::create());
$browser->request('GET', 'https://foo.com');
$response = $browser->getResponse();
Если вы делаете запросы, которые приводят к JSON-ответу, вы можете использовать метод
toArray()
, чтобы превратить документ JSON в массив PHP, без необходимости ясного
вызова json_decode()
:
1 2 3 4 5
$browser = new HttpBrowser(HttpClient::create());
$browser->request('GET', 'https://api.foo.com');
$response = $browser->getResponse()->toArray();
// $response - это PHP-массив расшифрованного содержания JSON