本文目录导读:

我将为您全面介绍PHP无头浏览器测试的相关知识。
什么是无头浏览器
无头浏览器(Headless Browser)是没有图形用户界面的浏览器,它在后台运行,能执行JavaScript、处理DOM、模拟用户交互,但不需要显示界面。
主流PHP无头浏览器方案
PHPWebDriver (Facebook WebDriver)
<?php
require_once 'vendor/autoload.php';
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Chrome\ChromeOptions;
// 配置无头Chrome
$options = new ChromeOptions();
$options->addArguments([
'--headless',
'--no-sandbox',
'--disable-dev-shm-usage',
'--window-size=1920,1080',
'--disable-gpu'
]);
$capabilities = DesiredCapabilities::chrome();
$capabilities->setCapability(ChromeOptions::CAPABILITY, $options);
$driver = RemoteWebDriver::create('http://localhost:9515', $capabilities);
// 访问页面
$driver->get('https://example.com');
// 执行测试
echo $driver->getTitle();
echo $driver->getCurrentURL();
// 查找元素
$element = $driver->findElement(
WebDriverBy::cssSelector('#main-content')
);
echo $element->getText();
$driver->quit();
?>
Puppeteer PHP 封装
<?php
use Nesk\Rialto\Data\JsFunction;
use Nesk\Puphpeteer\Puppeteer;
$puppeteer = new Puppeteer;
$browser = $puppeteer->launch([
'headless' => true,
'args' => ['--no-sandbox']
]);
$page = $browser->newPage();
$page->goto('https://example.com');
$page->screenshot(['path' => 'screenshot.png']);
$title = $page->title();
echo $title;
$content = $page->content();
// 执行DOM操作
$page->type('#search', 'PHP', ['delay' => 100]);
$page->click('#submit');
$browser->close();
?>
简单的cURL + DOMDocument方案
<?php
function getRenderedContent($url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
]);
$content = curl_exec($ch);
curl_close($ch);
return $content;
}
// 使用DOM解析
$content = getRenderedContent('https://example.com');
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML($content);
$finder = new DOMXPath($dom);
$nodes = $finder->query("//div[@class='main-content']");
?>
完整测试框架示例
PHPUnit + WebDriver 集成
<?php
use PHPUnit\Framework\TestCase;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverExpectedCondition;
class BrowserTest extends TestCase
{
private $driver;
protected function setUp(): void
{
$options = new ChromeOptions();
$options->addArguments([
'--headless',
'--no-sandbox',
'--disable-dev-shm-usage'
]);
$capabilities = DesiredCapabilities::chrome();
$capabilities->setCapability(ChromeOptions::CAPABILITY, $options);
$this->driver = RemoteWebDriver::create(
'http://localhost:9515',
$capabilities
);
}
public function testLoginFlow()
{
$this->driver->get('https://example.com/login');
$this->driver->findElement(WebDriverBy::name('username'))
->sendKeys('testuser');
$this->driver->findElement(WebDriverBy::name('password'))
->sendKeys('testpassword');
$this->driver->findElement(WebDriverBy::cssSelector('.login-btn'))
->click();
// 等待页面跳转
$this->driver->wait(10)->until(
WebDriverExpectedCondition::urlContains('/dashboard')
);
echo $this->driver->getCurrentURL();
echo $this->driver->getTitle();
}
public function testScreenshotAndDOM()
{
$this->driver->get('https://example.com');
// 截图
$this->driver->takeScreenshot('/tmp/screenshot.png');
// 获取完整DOM
$html = $this->driver->getPageSource();
// 验证元素
$this->assertNotEmpty(
$this->driver->findElement(
WebDriverBy::cssSelector('#main-header')
)
);
}
public function testJavaScriptExecution()
{
$this->driver->get('https://example.com');
// 执行自定义JavaScript
$result = $this->driver->executeScript(
"return document.title;"
);
echo $result;
// 模拟滚动
$this->driver->executeScript(
"window.scrollTo(0, document.body.scrollHeight);"
);
sleep(2);
}
protected function tearDown(): void
{
if ($this->driver) {
$this->driver->quit();
}
}
}
?>
实用工具函数
<?php
class HeadlessBrowserHelper
{
private $driver;
public function __construct($headless = true)
{
$options = new ChromeOptions();
if ($headless) {
$options->addArguments(['--headless', '--hide-scrollbars']);
}
$options->addArguments([
'--no-sandbox',
'--disable-dev-shm-usage',
'--no-default-browser-check',
'--start-maximized'
]);
$options->addExtensions([
'/path/to/extension.crx'
]);
$capabilities = DesiredCapabilities::chrome();
$capabilities->setCapability(ChromeOptions::CAPABILITY, $options);
$this->driver = RemoteWebDriver::create(
getenv('CHROME_DRIVER_URL') ?: 'http://localhost:9515',
$capabilities
);
}
public function getPageWithWait($url, $timeout = 10)
{
$this->driver->get($url);
$this->driver->wait($timeout)->until(
WebDriverExpectedCondition::documentReadyStateComplete()
);
return $this->driver->getPageSource();
}
public function extractData($html, $selector)
{
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML($html);
$finder = new DOMXPath($dom);
return $finder->query($selector);
}
public function handleAjax($callback)
{
$driver = $this->driver;
$callback($driver);
// 等待ajax完成
$driver->wait(10)->until(function($driver) {
return $driver->executeScript(
"return jQuery.active == 0"
);
});
}
public function getNetworkRequests()
{
$requests = $this->driver->executeScript(
"return window.performance.getEntriesByType('resource')"
);
return array_map(function($request) {
return [
'url' => $request->name,
'duration' => $request->duration,
'size' => $request->transferSize
];
}, $requests);
}
public function cleanup()
{
if ($this->driver) {
$this->driver->deleteAllCookies();
$this->driver->manage()->logs()->get('browser');
$this->driver->quit();
}
}
}
?>
环境配置示例
# Dockerfile
FROM php:8.2-cli
# 安装Chrome
RUN apt-get update && apt-get install -y \
google-chrome-stable \
chromium-driver
# 安装PHP WebDriver客户端
RUN composer require php-webdriver/webdriver
# 启动ChromeDriver
CMD ["chromedriver", "--port=9515"]
# docker-compose.yml
version: '3.8'
services:
chromedriver:
image: selenium/standalone-chrome:latest
ports:
- "9515:4444"
volumes:
- /dev/shm:/dev/shm
environment:
- CHROME_HEADLESS=true
php:
build: .
depends_on:
- chromedriver
environment:
- CHROME_DRIVER_URL=http://chromedriver:4444
volumes:
- .:/var/www/html
最佳实践
等待策略
// 显式等待
$driver->wait(10)->until(
WebDriverExpectedCondition::visibilityOfElementLocated(
WebDriverBy::id('dynamic-content')
)
);
// 自定义条件
$driver->wait(10)->until(function($driver) {
return $driver->executeScript(
"return document.readyState === 'complete'"
);
});
错误处理
try {
$driver->get('https://example.com');
} catch (WebDriverException $e) {
echo "测试失败: " . $e->getMessage();
$driver->takeScreenshot('/tmp/error.png');
} finally {
$driver->quit();
}
性能优化
// 启用缓存
$driver->executeScript("localStorage.setItem('key', 'value')");
// 禁用不必要的资源
$options->addArguments(['--blink-settings=imagesEnabled=false']);
// 设置用户代理
$options->setExperimentalOption('mobileEmulation', [
'deviceName' => 'iPhone X'
]);
CI/CD集成
# GitHub Actions
name: PHP Headless Tests
on: [push, pull_request]
jobs:
headless-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, xml, curl
- name: Start ChromeDriver
run: |
google-chrome --version
chromedriver --version
- name: Run tests
run: |
composer install
php vendor/bin/phpunit --group headless
通过这些工具和技术,您可以在PHP环境中高效地进行无头浏览器测试,记住要根据具体需求选择适当的工具,并注意测试环境的稳定性和可维护性。