首页 > 文章列表 > 如何使用PHP和Selenium快速构建自己的网络爬虫系统

如何使用PHP和Selenium快速构建自己的网络爬虫系统

php Selenium 爬虫系统
155 2023-06-22

近年来,随着互联网的普及,网络爬虫逐渐成为了信息采集的主要手段之一,然而,常规的爬虫技术不稳定、难以维护,市面上的纯Web网页爬虫也只能在静态页面上进行操作。而PHP结合Selenium可达到动态爬虫的效果,具有稳定性高、数据采集全面等优点,被广泛应用于爬虫开发中。本文将介绍如何使用PHP和Selenium快速构建自己的网络爬虫系统。

一、Selenium和ChromeDriver的安装

Selenium是一个自动化测试工具,可以对Web应用程序进行自动化测试,其中将浏览器与操作系统分离式地处理,无强制插入代码实现页面渲染。ChromeDriver则是Selenium中调用Chrome浏览器的驱动程序,可以使Selenium直接操作Chrome,从而实现动态页面的爬取。

首先需要在本地安装Chrome浏览器和PHP环境。接着,我们需要安装相应版本的Selenium和ChromeDriver,在命令行中输入以下代码即可安装:

composer require facebook/webdriver

然后将ChromeDriver二进制文件(根据自己的本地Chrome版本下载相应版本的ChromeDrive)置于系统Path变量环境中,代码如下:

$webdriver = FacebookWebDriverRemoteRemoteWebDriver::create(
    'http://localhost:9515', FacebookWebDriverChromeChromeOptions::class
);

二、构建Selenium和ChromeDriver的封装类

Selenium封装类主要用来维护Selenium和ChromeDriver,避免重复创建、销毁,代码如下:

class Selenium
{
    private static $driver;
    private static $selenium;

    public static function getInstance()
    {
        if (null === self::$selenium) {
            $options = new ChromeOptions();
            $options->addArguments(['--no-sandbox','--disable-extensions','--headless','--disable-gpu']);
            self::$driver = RemoteWebDriver::create(
                'http://localhost:9515',
                DesiredCapabilities::chrome()->setCapability(
                    ChromeOptions::CAPABILITY,
                    $options
                )
            );
            self::$selenium = new self();
        }

        return self::$selenium;
    }

    public function __destruct()
    {
        self::$driver->quit();
        self::$selenium = null;
    }

    public function getDriver()
    {
        return self::$driver;
    }
}

注意,参数中的ChromeOptions主要是为了在无GUI(图形化界面)下仍能稳定运行,--no-sandbox参数是为了防止在linux系统下运行时报错。

三、创建网页源码解析类

爬虫系统的核心在于解析非静态页面,这里需要创建源码解析类,使用正则表达式或XPath表达式来定位和获取目标节点信息。

class PageParser
{
    private $pageSource;

    public function __construct(string $pageSource)
    {
        $this->pageSource = $pageSource;
    }

    public function parse(string $expression, $list = false)
    {
        if ($list) {
            return $this->parseList($expression);
        }
        return $this->parseSingle($expression);
    }

    private function parseList(string $expression)
    {
        $domXpath = new DOMXPath(@DOMDocument::loadHTML($this->pageSource));
        $items = $domXpath->query($expression);
        $result = [];
        foreach ($items as $item) {
            array_push($result,trim($item->nodeValue));
        }
        return $result;
    }

    private function parseSingle(string $expression)
    {
        $domXpath = new DOMXPath(@DOMDocument::loadHTML($this->pageSource));
        $item = $domXpath->query($expression)->item(0);
        if ($item) {
            return trim($item->nodeValue);
        }
        return '';
    }
}

这里主要用到了DOMXPath类和DOMDocument类来解析页面中的HTML节点,分别通过parseList和parseSingle方法来定位和获取多个和一个目标节点的内容。

四、创建爬虫类

最后,我们需要构建一个专门爬取页面内容的爬虫类,代码如下:

class Spider
{
    private $selenium;
    private $url;

    public function __construct($url)
    {
        $this->selenium = Selenium::getInstance();
        $this->url = $url;
        $this->selenium->getDriver()->get($url);
        sleep(1);
    }

    public function __destruct()
    {
        $this->selenium->getDriver()->close();
        $this->selenium = null;
    }

    public function getContent($expression, $list = false)
    {
        $pageSource = $this->selenium->getDriver()->getPageSource();
        $parser = new PageParser($pageSource);
        return $parser->parse($expression, $list);
    }
}

该类的getContent方法接收两个参数,一个是目标节点的XPath表达式,另一个是是否获取多个内容。 getModelContent函数请求URL并解析节点来获取所需内容,该函数获取结束后关闭浏览器进程。

五、使用示例

最后,我们使用实际例子来说明如何使用这个爬虫类。假设我们需要从一个拥有多个a标签的网页上,爬取a标签中的href属性和文本信息。我们可以通过以下代码来实现:

$spider = new Spider('https://www.example.com');
$aTags = $spider->getContent('//a', true);
foreach ($aTags as $a) {
    $href = $a->getAttribute('href');
    $text = $a->nodeValue;
    echo "$href -> $text
";
}

在以上代码中,首先使用Spider类获取页面源码,然后通过XPath表达式获取多个a标签的节点信息,最后通过getAttribute和nodeValue方法获取每个a标签的href属性和文本。

六、总结

综上所述,本文通过介绍如何使用PHP和Selenium构建网页爬虫系统,并通过实际示例说明如何获取页面中的节点信息,该爬虫具有稳定性高、数据采集全面等优点,具有一定的应用价值。但同时需要注意的是,爬取数据时需要注意合法性和道德性,并遵守相关法律法规。