PHP 提供了构建网络爬虫所需的各种构建块,尽管它很快就会成为一项日益复杂的任务。方便的是,许多开源库可以使使用 PHP 进行网页抓取变得更容易。
这篇文章将指导您逐步编写各种 PHP 网络抓取例程,您可以使用这些例程从静态和动态网页中提取公共数据。
让我们开始吧!
PHP 可以用于网页抓取吗?
简而言之,是的,它当然可以,并且本文的其余部分将详细介绍网页抓取过程应该是什么样子。然而,询问它作为网络抓取语言是否是一个好的选择是一个完全不同的问题,因为存在许多编程语言替代方案。
请注意,PHP 已经很旧了。它自 90 年代以来就已经存在,并达到了重要的版本 8。然而,这是有利的,因为它使 PHP 成为一种相当易于使用的语言,并且已经解决了数十年的问题/错误。然而,简单性也是有代价的。当涉及复杂的动态网站时,PHP 的性能优于 Python 和 Javascript,但如果您的要求是从简单页面中抓取数据,那么 PHP 是一个不错的选择。
安装前提条件
首先,请保您已安装 PHP 和 Composer。
这里就不在此说明环境了。可以使用各种集成环境,如宝塔,PHPstudy或者其他
下一步是安装所需的库。
发出 HTTP GET 请求
PHP 网页抓取的第一步是加载页面。
在本教程中,我们将使用 books.toscrape.com。该网站是一个用于练习网络抓取的虚拟书店。
当在浏览器中查看网站时,浏览器首先会向 Web 服务器发送 HTTP GET 请求。 要使用 PHP 发送 HTTP GET 请求,可以使用内置函数file_get_contents 。
此函数可以采用文件路径或 URL 并以字符串形式返回内容。
创建一个新文件并将其另存为 native.php 。在代码编辑器(例如Visual Studio Code)中打开此文件。输入以下代码行来加载 HTML 页面并在终端中打印 HTML:
<?php $html = file_get_contents('https://books.toscrape.com/'); echo $html;
从终端执行此代码,如下所示:
php native.php
执行此命令后,将打印页面的整个 HTML。
到目前为止,很难在 HTML 中定位和提取特定信息。
这就是各种开源第三方库发挥作用的地方。
使用 Goutte 在 PHP 中进行网页抓取
有多种库可用于使用 PHP 进行网页抓取。在本教程中,将使用 Goutte,因为它易于访问、文档齐全且不断更新。尝试最流行的解决方案总是一个好主意。通常,支持内容和预先存在的建议都很丰富。
Goutte 可以处理大多数静态网站。对于动态站点,我们使用 Symfony Panther。
Goutte,发音为goot ,是 Symfony 组件的包装器,例如BrowserKit 、 CssSelector 、 DomCrawler和HTTPClient 。
Symfony 是一组可重用的 PHP 组件。Goutte使用的组件可以直接使用。然而,Goutte 使编写代码变得更容易。
要安装 Goutte,请创建一个要保存源代码的目录。导航到该目录并输入以下命令:
composer init --no-interaction --require="php >=7.1" composer require fabpot/goutte composer update
第一个命令将创建composer.json文件。第二个命令将添加 Goutte 条目以及下载和安装所需的文件。它还会创建composer.lock 文件。
Composer update命令将确保依赖项的所有文件都是最新的。
使用 Goutte 发送 HTTP 请求
使用 Goutte 进行 PHP 网页抓取的最重要的类是充当浏览器的客户端。第一步是创建此类的对象:
$client = new Client();
然后可以使用该对象发送请求。发送请求的方法称为request 。它需要两个参数——HTTP 方法和目标 URL,并返回 DOM 爬虫对象的实例:
$crawler = $client->request('GET', 'https://books.toscrape.com');
这会将 GET 请求发送到 HTML 页面。要打印页面的整个 HTML,我们可以调用html() 方法。
将我们迄今为止构建的所有内容放在一起,代码文件如下所示:
<?php require 'vendor/autoload.php'; use Goutte\Client; $client = new Client(); $crawler = $client->request('GET', 'https://books.toscrape.com'); echo $crawler->html();
将这个新的 PHP 文件保存为books.php 并从终端运行它。这将打印整个 HTML:
php books.php
接下来,我们需要一种从页面中定位特定元素的方法。
通过 CSS 选择器定位 HTML 元素
Goutte 使用 Symfony 组件CssSelector 。它有助于使用 CSS 选择器来定位 HTML 元素。
CSS 选择器可以提供给过滤器方法。例如,要打印页面标题,请在我们正在使用的books.php文件中输入以下行:
echo $crawler ->过滤器( '标题' ) ->文本();
请注意,title是 从 HTML 中选择<title>节点的 CSS 选择器。
请记住,在这种特殊情况下,text() 返回 HTML 元素中包含的文本。在前面的示例中,我们使用html() 返回所选元素的整个 HTML。
如果您更喜欢使用 XPath,请改用filterXPath() 方法。以下代码行产生相同的输出:
echo $crawler -> filterXPath ( '//title' ) -> text ();
现在,让我们继续提取书名和价格。
提取元素
打开在 Chrome 中 https://books.toscrape.com ,右键单击一本书并选择“检查”。在编写网页抓取代码之前,我们需要首先分析页面的 HTML。
这些书位于 <article> 标签中
通过检查目标网页的 HTML,我们可以看到每本书都包含在一个article 标签中,该标签有一个product_pod 类。在这里,CSS 选择器是.product_pod 。
在每个文章标签中,完整的书名作为alt属性值位于缩略图中 。书名的 CSS 选择器是.image_container img 。
最后,图书价格的 CSS 选择器是.price_color 。
要从此页面获取所有标题和价格,首先,我们需要找到容器,然后运行each循环 。
在此循环中,匿名函数将提取并打印标题和价格,如下所示:
function scrapePage($url, $client){ $crawler = $client->request('GET', $url); $crawler->filter('.product_pod')->each(function ($node) { $title = $node->filter('.image_container img')->attr('alt'); $price = $node->filter('.price_color')->text(); echo $title . "-" . $price . PHP_EOL; }); }
Web 数据提取的功能被隔离在一个函数中。相同的功能可用于从不同网站提取数据。
处理分页
此时,您的 PHP 网络抓取工具仅从单个 URL 执行数据提取。在现实生活中的网络抓取场景中,会涉及多个页面。
在此特定站点中,分页由“下一个 ”链接(按钮)控制。Next链接的 CSS 选择器 是.next > a 。
在我们之前创建的函数scrapePage中 ,添加以下行:
try { $next_page = $crawler->filter('.next > a')->attr('href'); } catch (InvalidArgumentException) { // 没找到下一页 return null; } return "https://books.toscrape.com/catalogue/" . $next_page;
此代码使用 CSS 选择器来定位“下一步” 按钮并提取href属性的值,返回后续页面的相对 URL。在最后一页上,这行代码将引发InvalidArgumentException 。
如果找到下一页,该函数将返回其 URL。否则,它将返回null 。
从现在开始,您将使用不同的 URL 启动每个抓取周期。这将使从相对 URL 到绝对 URL 的转换变得更容易。
最后,您可以使用while 循环来调用此函数:
$client = new Client(); $nextUrl = "https://books.toscrape.com/catalogue/page-1.html"; while ($nextUrl) { $nextUrl = scrapePage($nextUrl, $client); } scrapePage($url, $client);
网页抓取代码已基本完成。
将数据写入 CSV 文件
PHP 网络抓取过程的最后一步是将数据导出到存储。PHP 的内置fputcsv 函数可用于将数据导出到 CSV 文件。
首先,以写入或追加模式打开 CSV 文件,并将文件句柄存储在变量中。
接下来,将变量发送到scrapePage 函数。然后,为每本书调用fputcsv 函数,将标题和价格写在一行中。
最后,在while循环之后,通过调用fclose 关闭文件。
最终的代码文件如下:
function scrapePage($url, $client, $file) { $crawler = $client->request('GET', $url); $crawler->filter('.product_pod')->each(function ($node) use ($file) { $title = $node->filter('.image_container img')->attr('alt'); $price = $node->filter('.price_color')->text(); fputcsv($file, [$title, $price]); }); try { $next_page = $crawler->filter('.next > a')->attr('href'); } catch (InvalidArgumentException) { //Next page not found return null; } return "https://books.toscrape.com/catalogue/" . $next_page; } $client = new Client(); $file = fopen("books.csv", "a"); $nextUrl = "https://books.toscrape.com/catalogue/page-1.html"; while ($nextUrl) { echo "<h2>" . $nextUrl . "</h2>" . PHP_EOL; $nextUrl = scrapePage($nextUrl, $client, $file); } fclose($file);
从终端运行此文件,也可以直接浏览器环境访问:
php books.php
这将创建一个 包含 1,000 行数据的books.csv文件
使用 Guzzle、XML 和 XPath 进行网页抓取
Guzzle 是一个 PHP 库,它向网页发送 HTTP 请求以获得响应。换句话说,Guzzle 是一个可用于抓取数据的 PHP HTTP 客户端。请注意,在使用网页之前,您需要了解另外两个概念:XML 和 XPath。
XML 代表可扩展标记语言。它将用于创建用于存储结构化数据的文件。然后可以传输这些文件并构建数据。
存在读取 XML 文件的问题,这就是 XPath 发挥作用的地方。
XPath 代表 XML Path,用于导航和选择 XML 节点。
HTML 文件与 XML 文件非常相似。在某些情况下,您可能需要解析器来调整细微差别并使 HTML 至少在一定程度上符合 XML 文件标准。有些解析器甚至可以读取格式很差的 XML。
无论如何,解析器都会进行必要的 HTML 修改,以便您可以使用 XPath 来查询和导航 HTML。
设置 Guzzle 项目
要安装 Guzzle,请创建一个要保存源代码的目录。导航到该目录并输入以下命令:
composer init --no-interaction --require="php >=7.1" composer require guzzlehttp/guzzle
除了 Guzzle 之外,我们还可以使用一个解析 HTML 代码的库。有许多可用的 PHP 库,例如简单的 HTML dom 解析器和 Symphony DOMCrawler。
在本教程中,选择 Symphony DOMCrawler。它的语法与 Goutte 非常相似,您将能够应用本节中已经了解的内容。
DomCrawler 优于简单 HTML dom 解析器的另一点是,它很好地支持处理无效的 HTML 代码。那么,让我们开始吧。
使用以下命令安装 DOMCrawler:
composer require symfony/dom-crawler
这些命令将下载所有必需的文件。下一步是创建一个新文件并将其另存为scraper.php 。
使用 Guzzle 发送 HTTP 请求
与 Goutte 类似,Guzzle 最重要的类是 Client。首先创建一个新文件 scraper.php 并输入以下 PHP 代码行:
<?php require 'vendor/autoload.php'; use GuzzleHttp\Client; use Symfony\Component\DomCrawler\Crawler;
现在我们准备创建 Client 类的对象:
$client = new Client();
然后您可以使用客户端对象发送请求。发送请求的方法方便地称为请求。它需要两个参数——HTTP 方法和目标 URL,并返回响应:
$response = $client->request('GET', 'https://books.toscrape.com&');
从这个响应中,我们可以提取网页的 HTML,如下所示:
$html = $response->getBody()->getContents(); echo $html
请注意,在此示例中,响应包含 HTML 代码。如果您正在使用返回 JSON 的网页,则可以将 JSON 保存到文件并停止脚本。仅当响应包含 HTML 或 XML 数据时,下一部分才适用。
接下来,DomCrawler 将用于从此网页中提取特定元素。
通过 XPath 定位 HTML 元素
导入 Crawler 类并创建 Crawler 类的实例,如以下 PHP 代码片段所示:
use Symfony\Component\DomCrawler\Crawler;
我们可以创建一个爬虫类的实例,如下所示:
$crawler = new Crawler($html);
现在我们可以使用filterXPath 方法来提取任何XML 节点。例如,以下行仅打印页面标题:
echo $crawler->filterXPath('//title')->text();
关于 XML 节点的简要说明:在 XML 中,一切都是节点——元素是节点,属性是节点,文本也是节点。filterXPath方法返回一个 节点。因此,要从元素中提取文本,即使您使用XPath 中的text() 函数,您仍然必须调用 text() 方法将文本提取为字符串。
换句话说,以下两行代码将返回相同的值:
echo $crawler->filterXPath('//title')->text(); echo $crawler->filterXPath('//title/text()')->text();
现在,让我们继续提取书名和价格。
提取元素
在编写网页抓取代码之前,让我们首先分析页面的 HTML。
打开网页在 Chrome 中 https://books.toscrape.com ,右键单击一本书并选择Inspect 。
这些书籍位于 <article> 元素中,其 class 属性设置为product_pod。选择这些节点的 XPath 如下:
// [@class="product_pod"]
在每个文章标签中,完整的书名作为 alt 属性值位于缩略图中。书名和书价的 XPath 如下:
//[@class="image_container"]/a/img/@alt //[@class="price_color"]/text()
要从此页面获取所有标题和价格,您首先需要找到容器,然后使用循环获取包含所需数据的每个元素。
在此循环中,匿名函数将提取并打印标题和价格,如以下 PHP 代码片段所示:
$crawler->filterXpath('//[@class="product_pod"]')->each(function ($node) { $title = $node->filterXpath('.//[@class="image_container"]/a/img/@alt')->text(); $price = $node->filterXPath('.//[@class="price_color"]/text()')->text(); echo $title . "-" . $price . PHP_EOL; });
这是如何使用 Guzzle 或 DOMCrawler 解析器从任何页面抓取数据的简单演示。请注意,此方法不适用于动态网站。这些网站使用 DOMCrawler 无法处理的 JavaScript 代码。在这种情况下,您需要使用 Symphony Panther。
提取数据后的下一步是保存它。
将提取的数据保存到文件中
要存储提取的数据,您可以更改脚本以使用内置 PHP 并创建 CSV 文件。
将以下 PHP 代码片段编写如下:
$file = fopen("books.csv", "a"); $crawler->filterXpath('//[@class="product_pod"]')->each(function ($node) use ($file) { $title = $node->filterXpath('.//[@class="image_container"]/a/img/@alt')->text(); $price = $node->filterXPath('.//*[@class="price_color"]/text()')->text(); fputcsv($file, [$title, $price]); }); fclose($file);
此代码片段在运行时会将所有数据保存到books.csv文件中。
使用 Symfony Panther 进行网页抓取
动态网站使用 JavaScript 来呈现内容。对于此类网站,Goutte 不是合适的选择。
对于这些网站,解决方案是使用浏览器来呈现页面。它可以使用 Symfony 的另一个组件 – Panther来完成。Panther 是一个独立的 PHP 库,用于使用真实浏览器进行网页抓取。
在本节中,我们从Quotes.toscrape.com中抓取引用和作者。这是一个用于学习抓取动态网页基础知识的虚拟网站。
安装 Panther 及其依赖项
要安装 Panther,请打开终端,导航到将存储源代码的目录,然后运行以下命令:
composer init --no-interaction --require="php >=7.1" composer require symfony/panther composer update
这些命令将创建一个新的composer.json文件并安装Symfony/Panther。
另外两个依赖项是浏览器和驱动程序。常见的浏览器选择是 Chrome 和 Firefox。您很可能已经安装了这些浏览器之一。
可以使用任何包管理器下载浏览器的驱动程序。
在 Windows 上,运行:
choco install chromedriver
在 macOS 上,运行:
brew install chromedriver
使用 Panther 发送 HTTP 请求
Panther 使用Client 类公开get() 方法。此方法可用于加载 URL,或者换句话说,发送 HTTP 请求。
第一步是创建 Chrome客户端。创建一个新的 PHP 文件并输入以下代码行:
<?php require 'vendor/autoload.php'; use \Symfony\Component\Panther\Client; $client = Client::createChromeClient();
然后可以使用$client对象 加载网页:
$client->get('https://quotes.toscrape.com/js/&#39;);
此行将在无头 Chrome 浏览器中加载页面。
通过 CSS 选择器定位 HTML 元素
要定位元素,首先,您需要获取 爬虫 对象的引用。获取对象的最佳方法是使用waitFor()方法等待页面上的特定元素 。它将 CSS 选择器作为参数:
$crawler = $client->waitFor('.quote');
该代码行等待带有此选择器的元素变得可用,然后返回爬虫的实例。
其余代码与 Goutte 类似,因为两者都使用 Symfony 的相同CssSelector 组件。
引用的容器 HTML 元素
首先, CSS 选择器提供 过滤方法来获取所有引用元素。然后,为每个引用提供匿名函数以提取作者和文本:
$crawler->filter('.quote')->each(function ($node) { $author = $node->filter('.author')->text(); $quote = $node->filter('.text')->text(); echo $autor." - ".$quote });
处理分页
要从本网站的所有后续页面中抓取数据,您只需单击“下一步” 按钮即可。要单击链接, 可以使用clickLink()方法。此方法直接作用于链接文本。
文章来源地址https://www.toymoban.com/article/485.html
在最后一页上,链接不会出现,调用此方法将引发异常。这可以通过使用 try-catch 块来处理:
while (true) { $crawler = $client->waitFor('.quote'); … try { $client->clickLink('Next'); } catch (Exception) { break; } }
将数据写入 CSV 文件
使用 PHP 的fputcsv()函数将数据写入 CSV 非常简单 。在while循环之前打开 CSV 文件,使用fputcsv()函数 写入每一行 ,并在循环之后关闭文件。
这是最终的代码:
$file = fopen("quotes.csv", "a"); while (true) { $crawler = $client->waitFor('.quote'); $crawler->filter('.quote')->each(function ($node) use ($file) { $author = $node->filter('.author')->text(); $quote = $node->filter('.text')->text(); fputcsv($file, [$author, $quote]); }); try { $client->clickLink('Next'); } catch (Exception) { break; } } fclose($file);
执行此 PHP 脚本中包含的网络抓取工具后,您将获得一个quotes.csv 文件,其中包含所有引言和作者,可供进一步分析。
结论
在使用 Goutte 处理大多数静态网页时,您不应该遇到重大问题,因为这个流行的库提供了足够的功能和广泛的文档。然而,如果典型的 HTML 提取方法无法胜任动态元素发挥作用时的任务,那么 Symfony Panther 是处理更复杂负载的正确方法。
如果您正在使用使用 Laravel、Code Igniter 或纯 PHP 开发的网站,那么直接用 PHP 编写网页抓取部分可能非常有用,例如,在创建您自己的 WordPress 插件时。由于 PHP 也是一种脚本语言,因此即使不打算将其部署到网站,您也可以编写 Web 抓取代码。文章来源:https://www.toymoban.com/article/485.html
到此这篇关于如何使用PHP进行网页抓取 | 终极教程的文章就介绍到这了,更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!