Компонент BrowserKit
Дата обновления перевода 2025-07-25
Компонент BrowserKit
Компонент BrowserKit симулирует поведение веб-браузера, позволяя вам программно делать запросы, нажимать на ссылки и отправлять формы.
Установка
1
$ composer require symfony/browser-kitNote
Если вы устанавливаете этот компонент вне приложения 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