Quét web cho phép bạn thu thập dữ liệu từ các trang web trên internet. Nó còn được gọi là thu thập dữ liệu web hoặc trích xuất dữ liệu web.
PHP là ngôn ngữ kịch bản phụ trợ được sử dụng rộng rãi để tạo các trang web và ứng dụng web động. Và bạn có thể triển khai trình quét web bằng mã PHP đơn giản.
Nhưng vì chúng tôi không muốn phát minh lại bánh xe, nên chúng tôi có thể tận dụng một số thư viện quét web PHP nguồn mở sẵn có để giúp chúng tôi thu thập dữ liệu của mình.
Trong hướng dẫn này, chúng ta sẽ thảo luận về các công cụ và dịch vụ khác nhau mà bạn có thể sử dụng với PHP để loại bỏ một trang web. Các công cụ mà chúng ta sẽ thảo luận là Guzzle, Goutte, Simple HTML DOM và trình duyệt không đầu Symfony Panther.
Lưu ý: trước khi bạn cạo một trang web, bạn nên đọc kỹ Điều khoản dịch vụ của họ để đảm bảo rằng họ đồng ý với việc cạo. Cạo dữ liệu – ngay cả khi dữ liệu đó có thể truy cập công khai – có khả năng làm quá tải máy chủ của trang web. (Biết đâu – nếu bạn hỏi một cách lịch sự, họ thậm chí có thể cung cấp cho bạn khóa API để bạn không cần phải tìm kiếm. 😉)
Cách thiết lập dự án
Trước khi chúng tôi bắt đầu, nếu bạn muốn làm theo và dùng thử mã, đây là một số điều kiện tiên quyết cho môi trường phát triển của bạn:
- Đảm bảo bạn đã cài đặt phiên bản PHP mới nhất.
- Truy cập liên kết này Trình soạn thảo để thiết lập một trình soạn thảo mà chúng tôi sẽ sử dụng để cài đặt các phụ thuộc PHP khác nhau cho các thư viện quét web.
- Một biên tập viên của sự lựa chọn của bạn.
Khi bạn đã hoàn thành tất cả những điều đó, hãy tạo một thư mục dự án và điều hướng vào thư mục:
mkdir php_scraper
cd php_scraper
Chạy hai lệnh sau trong thiết bị đầu cuối của bạn để khởi tạo nhà soạn nhạc.json tập tin:
composer init — require=”php >=7.4" — no-interaction
composer update
Bắt đầu nào.
Quét web bằng PHP sử dụng Guzzle, XML và XPath
Guzzle là một ứng dụng khách HTTP PHP cho phép bạn gửi các yêu cầu HTTP một cách nhanh chóng và dễ dàng. Nó có một giao diện đơn giản để xây dựng các chuỗi truy vấn.
XML là ngôn ngữ đánh dấu mã hóa tài liệu để con người và máy có thể đọc được.
Và XPath là ngôn ngữ truy vấn điều hướng và chọn các nút XML.
Hãy xem cách chúng ta có thể sử dụng ba công cụ này cùng nhau để quét một trang web.
Bắt đầu bằng cách cài đặt Guzzle qua trình soạn thảo bằng cách thực hiện lệnh sau trong thiết bị đầu cuối của bạn:
composer require guzzlehttp/guzzle
Khi bạn đã cài đặt Guzzle, hãy tạo một tệp PHP mới mà chúng tôi sẽ thêm mã vào. Chúng tôi sẽ gọi nó guzzle_requests.php.
Đối với phần trình diễn này, chúng tôi sẽ cạo trang web Books to Scrape. Bạn sẽ có thể làm theo các bước giống như chúng tôi xác định ở đây để xóa bất kỳ trang web nào bạn chọn.
Trang web Books to Scrape trông như thế này:

Chúng tôi muốn trích xuất tên sách và hiển thị chúng trên thiết bị đầu cuối.
Bước đầu tiên trong việc cạo một trang web là hiểu bố cục HTML của nó. Trong trường hợp này, bạn có thể xem bố cục HTML của trang này bằng cách nhấp chuột phải vào trang, ngay phía trên sản phẩm đầu tiên trong danh sách và chọn Quan sát.
Đây là ảnh chụp màn hình hiển thị một đoạn nguồn của trang:

Bạn có thể thấy rằng danh sách được chứa bên trong
- thành phần. Con trực tiếp tiếp theo là
thành phần.
- Thực thi mã JavaScript trên các trang web
- Hỗ trợ kiểm tra trình duyệt từ xa
- Hỗ trợ tải các phần tử không đồng bộ bằng cách đợi các phần tử khác tải trước khi thực thi một dòng mã
- Hỗ trợ tất cả các triển khai Chrome của Firefox
- Có thể chụp ảnh màn hình
- Cho phép chạy mã JS tùy chỉnh hoặc truy vấn XPath trong ngữ cảnh của trang được tải.
Những gì chúng tôi muốn là tiêu đề cuốn sách. Nó ở bên trong lần lượt nằm trong
đó là bên trong mà cuối cùng là bên trong thành phần.
Để khởi tạo Guzzle, XML và Xpath, hãy thêm đoạn mã sau vào guzzle_requests.php tập tin:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = new \GuzzleHttp\Client();
$response = $httpClient->get('https://books.toscrape.com/');
$htmlString = (string) $response->getBody();
//add this line to suppress any warnings
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML($htmlString);
$xpath = new DOMXPath($doc);
Đoạn mã trên sẽ tải trang web thành một chuỗi. Sau đó, chúng tôi phân tích cú pháp chuỗi bằng XML và gán nó cho $xpath Biến đổi.
Điều tiếp theo bạn muốn là nhắm mục tiêu nội dung văn bản bên trong nhãn. Thêm đoạn mã sau vào tệp:
$titles = $xpath->evaluate('//ol[@class="row"]//li//article//h3/a');
$extractedTitles = [];
foreach ($titles as $title) {
$extractedTitles[] = $title->textContent.PHP_EOL;
echo $title->textContent.PHP_EOL;
}
Trong đoạn mã trên, //ol[@class=”row”] được toàn bộ danh sách.
Mỗi mục trong danh sách có một thẻ mà chúng tôi đang nhắm mục tiêu để trích xuất tiêu đề thực của cuốn sách. Chúng tôi chỉ có một thẻ
chứa , giúp dễ dàng nhắm mục tiêu trực tiếp hơn.
chúng tôi sử dụng cho mỗi vòng lặp để trích xuất nội dung văn bản và lặp lại chúng đến thiết bị đầu cuối.
Ở bước này, bạn có thể chọn thực hiện điều gì đó với dữ liệu được trích xuất của mình, có thể gán dữ liệu cho một biến mảng, ghi vào tệp hoặc lưu trữ trong cơ sở dữ liệu.
Bạn có thể thực thi tệp bằng PHP trên thiết bị đầu cuối bằng cách chạy lệnh bên dưới. Hãy nhớ rằng, phần được đánh dấu là cách chúng tôi đặt tên cho tệp của mình:
php guzzle_requests.php
Điều này sẽ hiển thị một cái gì đó như thế này:

Cũng đã đi.
Bây giờ, nếu chúng ta cũng muốn lấy giá của cuốn sách thì sao?

Giá xảy ra là bên trong
thẻ, bên trong thẻ
. Như bạn thấy có nhiều hơn một thẻ
và nhiều hơn một thẻ
.
Để tìm đúng mục tiêu, chúng tôi sẽ sử dụng các bộ chọn lớp CSS, thật may mắn cho chúng tôi, là duy nhất cho mỗi thẻ. Đây là đoạn mã để lấy thẻ giá và nối nó với chuỗi tiêu đề:
$titles = $xpath->evaluate('//ol[@class="row"]//li//article//h3/a');
$prices = $xpath->evaluate('//ol[@class="row"]//li//article//div[@class="product_price"]//p[@class="price_color"]');
foreach ($titles as $key => $title) {
echo $title->textContent . ' @ '. $prices[$key]->textContent.PHP_EOL;
}
Nếu bạn thực thi mã trên thiết bị đầu cuối của mình, bạn sẽ thấy một cái gì đó như thế này:

Toàn bộ mã của bạn sẽ trông như thế này:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = new \GuzzleHttp\Client();
$response = $httpClient->get('https://books.toscrape.com/');
$htmlString = (string) $response->getBody();
//add this line to suppress any warnings
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML($htmlString);
$xpath = new DOMXPath($doc);
$titles = $xpath->evaluate('//ol[@class="row"]//li//article//h3/a');
$prices = $xpath->evaluate('//ol[@class="row"]//li//article//div[@class="product_price"]//p[@class="price_color"]');
foreach ($titles as $key => $title) {
echo $title->textContent . ' @ '. $prices[$key]->textContent.PHP_EOL;
}
Tất nhiên, đây là một công cụ quét web cơ bản và bạn chắc chắn có thể làm cho nó tốt hơn. Hãy chuyển sang thư viện tiếp theo.
Quét web bằng PHP với Goutte
Goutte là một ứng dụng khách HTTP tuyệt vời khác dành cho PHP được tạo riêng cho việc quét web. Nó được phát triển bởi người tạo ra Symfony Framework và cung cấp một API tuyệt vời để thu thập dữ liệu từ các phản hồi HTML/XML của các trang web.
Dưới đây là một số thành phần mà nó bao gồm để giúp việc thu thập dữ liệu web trở nên đơn giản:
Cài đặt Goutte thông qua trình soạn thảo bằng cách thực hiện lệnh sau trên thiết bị đầu cuối của bạn:
composer require fabpot/goutte
Khi bạn đã cài đặt gói Goutte, hãy tạo một tệp PHP mới cho mã của chúng tôi – hãy gọi nó là goutte_requests.php.
Trong phần này, chúng ta sẽ thảo luận về những gì chúng ta đã làm với thư viện Guzzle trong phần đầu tiên.
Chúng tôi sẽ cạo tên sách từ trang web Books to Scrape bằng cách sử dụng Goutte. Sau đó, chúng ta sẽ xem cách bạn có thể thêm giá vào một biến mảng và sử dụng biến đó trong mã.
Thêm mã sau vào tệp goutte_requests.php:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = new \Goutte\Client();
$response = $httpClient->request('GET', 'https://books.toscrape.com/');
$titles = $response->evaluate('//ol[@class="row"]//li//article//h3/a');
$prices = $response->evaluate('//ol[@class="row"]//li//article//div[@class="product_price"]//p[@class="price_color"]');
// we can store the prices into an array
$priceArray = [];
foreach ($prices as $key => $price) {
$priceArray[] = $price->textContent;
}
// we extract the titles and display to the terminal together with the prices
foreach ($titles as $key => $title) {
echo $title->textContent . ' @ '. $priceArray[$key] . PHP_EOL;
}
Thực thi mã bằng cách chạy lệnh sau trong thiết bị đầu cuối:
php goutte_requests.php
Đây là đầu ra:

Đây là một cách quét web với Goutte.
Hãy thảo luận về một phương pháp khác bằng cách sử dụng Bộ chọn CSS thành phần đi kèm với Goutte. Bộ chọn CSS đơn giản hơn so với sử dụng XPath được hiển thị trong các phương pháp trước đó.
Tạo một tệp PHP khác, hãy gọi nó là goutte_css_requests.php. Thêm đoạn mã sau vào tệp:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = new \Goutte\Client();
$response = $httpClient->request('GET', 'https://books.toscrape.com/');
// get prices into an array
$prices = [];
$response->filter('.row li article div.product_price p.price_color')->each(function ($node) use (&$prices) {
$prices[] = $node->text();
});
// echo titles and prices
$priceIndex = 0;
$response->filter('.row li article h3 a')->each(function ($node) use ($prices, &$priceIndex) {
echo $node->text() . ' @ ' . $prices[$priceIndex] .PHP_EOL;
$priceIndex++;
});
Như bạn có thể thấy, việc sử dụng thành phần Bộ chọn CSS dẫn đến mã sạch hơn và dễ đọc hơn.
Bạn có thể nhận thấy rằng chúng tôi đã sử dụng &
nhà điều hành. Điều này đảm bảo rằng chúng tôi đưa tham chiếu của biến vào “mỗi” vòng lặp, và không chỉ giá trị của biến. Nếu &$prices
được sửa đổi trong vòng lặp, giá trị thực bên ngoài vòng lặp cũng được sửa đổi.
Bạn có thể đọc thêm về bài tập bằng cách tham khảo từ các tài liệu PHP chính thức.
Thực thi tệp trong thiết bị đầu cuối của bạn bằng cách chạy lệnh:
php goutte_css_requests.php
Bạn sẽ thấy kết quả tương tự như kết quả trong ảnh chụp màn hình trước:

Cho đến nay, trình quét web của chúng tôi với PHP và Goutte đang hoạt động tốt. Hãy đi sâu hơn một chút và xem liệu chúng ta có thể nhấp vào một liên kết và điều hướng đến một trang khác không.
Trên trang web demo của chúng tôi, Books to Scrape, nếu bạn nhấp vào tiêu đề của một cuốn sách, một trang sẽ hiển thị thông tin chi tiết về cuốn sách, chẳng hạn như:

Chúng tôi muốn xem bạn có hay không, chúng tôi nhấp vào liên kết từ danh sách sách, điều hướng đến trang chi tiết sách và trích xuất mô tả. Kiểm tra trang để xem những gì chúng tôi sẽ nhắm mục tiêu:

Luồng mục tiêu của chúng tôi sẽ từ
phần tử, sau đó
sau đó thẻ chỉ xuất hiện một lần và cuối cùng là
nhãn.
chúng tôi có một số
thẻ – thẻ có mô tả là thẻ thứ tư bên trong
cha mẹ. Vì các mảng bắt đầu từ 0, nên chúng ta sẽ nhận được nút tại lần thứ 3 mục lục.
Bây giờ chúng ta đã biết những gì chúng ta đang nhắm mục tiêu, hãy viết mã.
Trước tiên, hãy thêm gói soạn thảo sau để trợ giúp phân tích cú pháp HTML5:
composer require masterminds/html5
Tiếp theo, sửa đổi goutte_css_requests.php tập tin như sau:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = new \Goutte\Client();
$response = $httpClient->request('GET', 'https://books.toscrape.com/');
// get prices into an array
$prices = [];
$response->filter('.row li article div.product_price p.price_color')
->each(function ($node) use (&$prices) {
$prices[] = $node->text();
});
// echo title, price, and description
$priceIndex = 0;
$response->filter('.row li article h3 a')
->each(function ($node) use ($prices, &$priceIndex, $httpClient) {
$title = $node->text();
$price = $prices[$priceIndex];
//getting the description
$description = $httpClient->click($node->link())
->filter('.content #content_inner article p')->eq(3)->text();
// display the result
echo "{$title} @ {$price} : {$description}\n\n";
$priceIndex++;
});
Nếu bạn thực thi tệp trong thiết bị đầu cuối của mình, bạn sẽ thấy tiêu đề, giá và mô tả được hiển thị:

Sử dụng Goute Bộ chọn CSS và tùy chọn nhấp vào một trang, bạn có thể dễ dàng thu thập dữ liệu toàn bộ trang web có nhiều trang và trích xuất bao nhiêu dữ liệu tùy ý.
Quét web bằng PHP với DOM HTML đơn giản
DOM HTML đơn giản là một thư viện quét web PHP tối giản khác mà bạn có thể sử dụng để thu thập dữ liệu trang web. Hãy thảo luận về cách bạn có thể sử dụng thư viện này để cạo một trang web. Giống như trong các ví dụ trước, chúng tôi sẽ cạo trang web Books to Scrape.
Trước khi bạn có thể cài đặt gói, hãy sửa đổi tệp composer.json của bạn và thêm các dòng mã sau ngay bên dưới require:{}
block để tránh bị lỗi phiên bản:
"minimum-stability": "dev",
"prefer-stable": true
Bây giờ, bạn có thể cài đặt thư viện bằng lệnh sau:
composer require simplehtmldom/simplehtmldom
Khi thư viện được cài đặt, hãy tạo một tệp PHP mới có tên simplehtmldom_requests.php.
Chúng tôi đã thảo luận về bố cục của trang web mà chúng tôi đang tìm kiếm trong các phần trước. Vì vậy, chúng tôi sẽ đi thẳng vào mã. Thêm đoạn mã sau vào simplehtmldom_requests.php tập tin:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = new \simplehtmldom\HtmlWeb();
$response = $httpClient->load('https://books.toscrape.com/');
// echo the title
echo $response->find('title', 0)->plaintext . PHP_EOL . PHP_EOL;
// get the prices into an array
$prices = [];
foreach ($response->find('.row li article div.product_price p.price_color') as $price) {
$prices[] = $price->plaintext;
}
// echo titles and prices
foreach ($response->find('.row li article h3 a') as $key => $title) {
echo "{$title->plaintext} @ {$prices[$key]} \n";
}
Nếu bạn thực thi mã trong thiết bị đầu cuối của mình, nó sẽ hiển thị kết quả:

Bạn có thể tìm thêm các phương pháp để thu thập dữ liệu trang web bằng thư viện DOM HTML đơn giản từ các tài liệu API chính thức.
Quét web trong PHP bằng Trình duyệt không đầu (Symfony Panther)
Trình duyệt không đầu là trình duyệt không có giao diện người dùng đồ họa. Trình duyệt không đầu cho phép bạn sử dụng thiết bị đầu cuối của mình để tải trang web trong môi trường tương tự như trình duyệt web. Điều này cho phép bạn viết mã để kiểm soát việc duyệt như chúng ta vừa thực hiện ở các bước trước.
Vậy tại sao điều này là cần thiết?
Trong quá trình phát triển web hiện đại, hầu hết các nhà phát triển đều sử dụng các khung web JavaScript. Các khung này tạo mã HTML bên trong trình duyệt. Trong các trường hợp khác, AJAX tự động tải nội dung.
Trong các ví dụ trước, chúng tôi đã sử dụng một trang HTML tĩnh để đầu ra nhất quán.
Trong các trường hợp động, khi bạn sử dụng JavaScript và AJAX để tạo HTML, đầu ra của cây DOM có thể khác rất nhiều. Điều này sẽ khiến máy cạo râu của chúng tôi bị hỏng. Các trình duyệt không đầu được sử dụng để xử lý các sự cố như vậy trong các trang web hiện đại.
Thư viện Symfony Panther PHP hoạt động tốt với các trình duyệt headless. Bạn có thể sử dụng thư viện để quét các trang web và chạy thử nghiệm bằng trình duyệt thực.
Ngoài ra, nó cung cấp các phương thức tương tự như thư viện Goutte nên bạn có thể sử dụng nó thay cho Goutte.
Không giống như các thư viện quét web trước đây mà chúng ta đã thảo luận trong hướng dẫn này, Panther có thể thực hiện những việc sau:
Chúng tôi đã thực hiện rất nhiều thao tác cạo, vì vậy hãy thử một cái gì đó khác biệt. Chúng tôi sẽ tải một trang HTML và chụp ảnh màn hình của trang.
Cài đặt Symfony Panther bằng lệnh sau:
composer require symfony/panther
Tạo một tệp php mới, hãy gọi nó là panther_requests.php. Thêm đoạn mã sau vào tệp:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = \Symfony\Component\Panther\Client::createChromeClient();
// for a Firefox client use the line below instead
//$httpClient = \Symfony\Component\Panther\Client::createFirefoxClient();
// get response
$response = $httpClient->get('https://books.toscrape.com/');
// take screenshot and store in current directory
$response->takeScreenshot($saveAs="books_scrape_homepage.jpg");
// let's display some book titles
$response->getCrawler()->filter('.row li article h3 a')
->each(function ($node) {
echo $node->text() . PHP_EOL;
});
Để mã này chạy trên hệ thống của bạn, bạn phải cài đặt trình điều khiển cho Chrome hoặc Firefox, tùy thuộc vào ứng dụng khách bạn đã sử dụng trong mã của mình.
May mắn thay, Composer có thể tự động làm điều này cho bạn. Thực hiện lệnh sau trong thiết bị đầu cuối của bạn để cài đặt và phát hiện trình điều khiển:
composer require - dev dbrekelmans/bdi && vendor/bin/bdi detect drivers
Bây giờ bạn có thể thực thi tệp PHP trong thiết bị đầu cuối của mình và nó sẽ chụp ảnh màn hình của trang web và lưu trữ nó trong thư mục hiện tại. Sau đó nó sẽ hiển thị một danh sách các tiêu đề từ trang web.

Phần kết luận
Trong hướng dẫn này, chúng tôi đã thảo luận về các thư viện mã nguồn mở PHP khác nhau mà bạn có thể sử dụng để quét một trang web.
Nếu bạn làm theo hướng dẫn, bạn sẽ có thể tạo một công cụ quét cơ bản để thu thập dữ liệu một hoặc hai trang.
Mặc dù đây là bài viết giới thiệu, nhưng chúng tôi đã đề cập đến hầu hết các phương pháp mà bạn có thể sử dụng với các thư viện. Bạn có thể chọn xây dựng dựa trên kiến thức này và tạo các trình quét web phức tạp có thể thu thập dữ liệu hàng nghìn trang. Mã cho hướng dẫn này có sẵn từ kho lưu trữ GitHub này.
Vui lòng liên hệ nếu bạn có bất kỳ câu hỏi nào.
Bạn có thể xem một số bài viết khác về quét web bằng Nodejs và quét web bằng Python nếu bạn quan tâm.
php guzzle_requests.php


và nhiều hơn một thẻ
Để tìm đúng mục tiêu, chúng tôi sẽ sử dụng các bộ chọn lớp CSS, thật may mắn cho chúng tôi, là duy nhất cho mỗi thẻ. Đây là đoạn mã để lấy thẻ giá và nối nó với chuỗi tiêu đề:
$titles = $xpath->evaluate('//ol[@class="row"]//li//article//h3/a');
$prices = $xpath->evaluate('//ol[@class="row"]//li//article//div[@class="product_price"]//p[@class="price_color"]');
foreach ($titles as $key => $title) {
echo $title->textContent . ' @ '. $prices[$key]->textContent.PHP_EOL;
}
Nếu bạn thực thi mã trên thiết bị đầu cuối của mình, bạn sẽ thấy một cái gì đó như thế này:

Toàn bộ mã của bạn sẽ trông như thế này:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = new \GuzzleHttp\Client();
$response = $httpClient->get('https://books.toscrape.com/');
$htmlString = (string) $response->getBody();
//add this line to suppress any warnings
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML($htmlString);
$xpath = new DOMXPath($doc);
$titles = $xpath->evaluate('//ol[@class="row"]//li//article//h3/a');
$prices = $xpath->evaluate('//ol[@class="row"]//li//article//div[@class="product_price"]//p[@class="price_color"]');
foreach ($titles as $key => $title) {
echo $title->textContent . ' @ '. $prices[$key]->textContent.PHP_EOL;
}
Tất nhiên, đây là một công cụ quét web cơ bản và bạn chắc chắn có thể làm cho nó tốt hơn. Hãy chuyển sang thư viện tiếp theo.
Quét web bằng PHP với Goutte
Goutte là một ứng dụng khách HTTP tuyệt vời khác dành cho PHP được tạo riêng cho việc quét web. Nó được phát triển bởi người tạo ra Symfony Framework và cung cấp một API tuyệt vời để thu thập dữ liệu từ các phản hồi HTML/XML của các trang web.
Dưới đây là một số thành phần mà nó bao gồm để giúp việc thu thập dữ liệu web trở nên đơn giản:
Cài đặt Goutte thông qua trình soạn thảo bằng cách thực hiện lệnh sau trên thiết bị đầu cuối của bạn:
composer require fabpot/goutte
Khi bạn đã cài đặt gói Goutte, hãy tạo một tệp PHP mới cho mã của chúng tôi – hãy gọi nó là goutte_requests.php.
Trong phần này, chúng ta sẽ thảo luận về những gì chúng ta đã làm với thư viện Guzzle trong phần đầu tiên.
Chúng tôi sẽ cạo tên sách từ trang web Books to Scrape bằng cách sử dụng Goutte. Sau đó, chúng ta sẽ xem cách bạn có thể thêm giá vào một biến mảng và sử dụng biến đó trong mã.
Thêm mã sau vào tệp goutte_requests.php:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = new \Goutte\Client();
$response = $httpClient->request('GET', 'https://books.toscrape.com/');
$titles = $response->evaluate('//ol[@class="row"]//li//article//h3/a');
$prices = $response->evaluate('//ol[@class="row"]//li//article//div[@class="product_price"]//p[@class="price_color"]');
// we can store the prices into an array
$priceArray = [];
foreach ($prices as $key => $price) {
$priceArray[] = $price->textContent;
}
// we extract the titles and display to the terminal together with the prices
foreach ($titles as $key => $title) {
echo $title->textContent . ' @ '. $priceArray[$key] . PHP_EOL;
}
Thực thi mã bằng cách chạy lệnh sau trong thiết bị đầu cuối:
php goutte_requests.php
Đây là đầu ra:

Đây là một cách quét web với Goutte.
Hãy thảo luận về một phương pháp khác bằng cách sử dụng Bộ chọn CSS thành phần đi kèm với Goutte. Bộ chọn CSS đơn giản hơn so với sử dụng XPath được hiển thị trong các phương pháp trước đó.
Tạo một tệp PHP khác, hãy gọi nó là goutte_css_requests.php. Thêm đoạn mã sau vào tệp:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = new \Goutte\Client();
$response = $httpClient->request('GET', 'https://books.toscrape.com/');
// get prices into an array
$prices = [];
$response->filter('.row li article div.product_price p.price_color')->each(function ($node) use (&$prices) {
$prices[] = $node->text();
});
// echo titles and prices
$priceIndex = 0;
$response->filter('.row li article h3 a')->each(function ($node) use ($prices, &$priceIndex) {
echo $node->text() . ' @ ' . $prices[$priceIndex] .PHP_EOL;
$priceIndex++;
});
Như bạn có thể thấy, việc sử dụng thành phần Bộ chọn CSS dẫn đến mã sạch hơn và dễ đọc hơn.
Bạn có thể nhận thấy rằng chúng tôi đã sử dụng &
nhà điều hành. Điều này đảm bảo rằng chúng tôi đưa tham chiếu của biến vào “mỗi” vòng lặp, và không chỉ giá trị của biến. Nếu &$prices
được sửa đổi trong vòng lặp, giá trị thực bên ngoài vòng lặp cũng được sửa đổi.
Bạn có thể đọc thêm về bài tập bằng cách tham khảo từ các tài liệu PHP chính thức.
Thực thi tệp trong thiết bị đầu cuối của bạn bằng cách chạy lệnh:
php goutte_css_requests.php
Bạn sẽ thấy kết quả tương tự như kết quả trong ảnh chụp màn hình trước:

Cho đến nay, trình quét web của chúng tôi với PHP và Goutte đang hoạt động tốt. Hãy đi sâu hơn một chút và xem liệu chúng ta có thể nhấp vào một liên kết và điều hướng đến một trang khác không.
Trên trang web demo của chúng tôi, Books to Scrape, nếu bạn nhấp vào tiêu đề của một cuốn sách, một trang sẽ hiển thị thông tin chi tiết về cuốn sách, chẳng hạn như:

Chúng tôi muốn xem bạn có hay không, chúng tôi nhấp vào liên kết từ danh sách sách, điều hướng đến trang chi tiết sách và trích xuất mô tả. Kiểm tra trang để xem những gì chúng tôi sẽ nhắm mục tiêu:

Luồng mục tiêu của chúng tôi sẽ từ
nhãn.
chúng tôi có một số
thẻ – thẻ có mô tả là thẻ thứ tư bên trong
Bây giờ chúng ta đã biết những gì chúng ta đang nhắm mục tiêu, hãy viết mã.
Trước tiên, hãy thêm gói soạn thảo sau để trợ giúp phân tích cú pháp HTML5:
composer require masterminds/html5
Tiếp theo, sửa đổi goutte_css_requests.php tập tin như sau:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = new \Goutte\Client();
$response = $httpClient->request('GET', 'https://books.toscrape.com/');
// get prices into an array
$prices = [];
$response->filter('.row li article div.product_price p.price_color')
->each(function ($node) use (&$prices) {
$prices[] = $node->text();
});
// echo title, price, and description
$priceIndex = 0;
$response->filter('.row li article h3 a')
->each(function ($node) use ($prices, &$priceIndex, $httpClient) {
$title = $node->text();
$price = $prices[$priceIndex];
//getting the description
$description = $httpClient->click($node->link())
->filter('.content #content_inner article p')->eq(3)->text();
// display the result
echo "{$title} @ {$price} : {$description}\n\n";
$priceIndex++;
});
Nếu bạn thực thi tệp trong thiết bị đầu cuối của mình, bạn sẽ thấy tiêu đề, giá và mô tả được hiển thị:

Sử dụng Goute Bộ chọn CSS và tùy chọn nhấp vào một trang, bạn có thể dễ dàng thu thập dữ liệu toàn bộ trang web có nhiều trang và trích xuất bao nhiêu dữ liệu tùy ý.
Quét web bằng PHP với DOM HTML đơn giản
DOM HTML đơn giản là một thư viện quét web PHP tối giản khác mà bạn có thể sử dụng để thu thập dữ liệu trang web. Hãy thảo luận về cách bạn có thể sử dụng thư viện này để cạo một trang web. Giống như trong các ví dụ trước, chúng tôi sẽ cạo trang web Books to Scrape.
Trước khi bạn có thể cài đặt gói, hãy sửa đổi tệp composer.json của bạn và thêm các dòng mã sau ngay bên dưới require:{}
block để tránh bị lỗi phiên bản:
"minimum-stability": "dev",
"prefer-stable": true
Bây giờ, bạn có thể cài đặt thư viện bằng lệnh sau:
composer require simplehtmldom/simplehtmldom
Khi thư viện được cài đặt, hãy tạo một tệp PHP mới có tên simplehtmldom_requests.php.
Chúng tôi đã thảo luận về bố cục của trang web mà chúng tôi đang tìm kiếm trong các phần trước. Vì vậy, chúng tôi sẽ đi thẳng vào mã. Thêm đoạn mã sau vào simplehtmldom_requests.php tập tin:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = new \simplehtmldom\HtmlWeb();
$response = $httpClient->load('https://books.toscrape.com/');
// echo the title
echo $response->find('title', 0)->plaintext . PHP_EOL . PHP_EOL;
// get the prices into an array
$prices = [];
foreach ($response->find('.row li article div.product_price p.price_color') as $price) {
$prices[] = $price->plaintext;
}
// echo titles and prices
foreach ($response->find('.row li article h3 a') as $key => $title) {
echo "{$title->plaintext} @ {$prices[$key]} \n";
}
Nếu bạn thực thi mã trong thiết bị đầu cuối của mình, nó sẽ hiển thị kết quả:

Bạn có thể tìm thêm các phương pháp để thu thập dữ liệu trang web bằng thư viện DOM HTML đơn giản từ các tài liệu API chính thức.
Quét web trong PHP bằng Trình duyệt không đầu (Symfony Panther)
Trình duyệt không đầu là trình duyệt không có giao diện người dùng đồ họa. Trình duyệt không đầu cho phép bạn sử dụng thiết bị đầu cuối của mình để tải trang web trong môi trường tương tự như trình duyệt web. Điều này cho phép bạn viết mã để kiểm soát việc duyệt như chúng ta vừa thực hiện ở các bước trước.
Vậy tại sao điều này là cần thiết?
Trong quá trình phát triển web hiện đại, hầu hết các nhà phát triển đều sử dụng các khung web JavaScript. Các khung này tạo mã HTML bên trong trình duyệt. Trong các trường hợp khác, AJAX tự động tải nội dung.
Trong các ví dụ trước, chúng tôi đã sử dụng một trang HTML tĩnh để đầu ra nhất quán.
Trong các trường hợp động, khi bạn sử dụng JavaScript và AJAX để tạo HTML, đầu ra của cây DOM có thể khác rất nhiều. Điều này sẽ khiến máy cạo râu của chúng tôi bị hỏng. Các trình duyệt không đầu được sử dụng để xử lý các sự cố như vậy trong các trang web hiện đại.
Thư viện Symfony Panther PHP hoạt động tốt với các trình duyệt headless. Bạn có thể sử dụng thư viện để quét các trang web và chạy thử nghiệm bằng trình duyệt thực.
Ngoài ra, nó cung cấp các phương thức tương tự như thư viện Goutte nên bạn có thể sử dụng nó thay cho Goutte.
Không giống như các thư viện quét web trước đây mà chúng ta đã thảo luận trong hướng dẫn này, Panther có thể thực hiện những việc sau:
Chúng tôi đã thực hiện rất nhiều thao tác cạo, vì vậy hãy thử một cái gì đó khác biệt. Chúng tôi sẽ tải một trang HTML và chụp ảnh màn hình của trang.
Cài đặt Symfony Panther bằng lệnh sau:
composer require symfony/panther
Tạo một tệp php mới, hãy gọi nó là panther_requests.php. Thêm đoạn mã sau vào tệp:
<?php
# scraping books to scrape: https://books.toscrape.com/
require 'vendor/autoload.php';
$httpClient = \Symfony\Component\Panther\Client::createChromeClient();
// for a Firefox client use the line below instead
//$httpClient = \Symfony\Component\Panther\Client::createFirefoxClient();
// get response
$response = $httpClient->get('https://books.toscrape.com/');
// take screenshot and store in current directory
$response->takeScreenshot($saveAs="books_scrape_homepage.jpg");
// let's display some book titles
$response->getCrawler()->filter('.row li article h3 a')
->each(function ($node) {
echo $node->text() . PHP_EOL;
});
Để mã này chạy trên hệ thống của bạn, bạn phải cài đặt trình điều khiển cho Chrome hoặc Firefox, tùy thuộc vào ứng dụng khách bạn đã sử dụng trong mã của mình.
May mắn thay, Composer có thể tự động làm điều này cho bạn. Thực hiện lệnh sau trong thiết bị đầu cuối của bạn để cài đặt và phát hiện trình điều khiển:
composer require - dev dbrekelmans/bdi && vendor/bin/bdi detect drivers
Bây giờ bạn có thể thực thi tệp PHP trong thiết bị đầu cuối của mình và nó sẽ chụp ảnh màn hình của trang web và lưu trữ nó trong thư mục hiện tại. Sau đó nó sẽ hiển thị một danh sách các tiêu đề từ trang web.

Phần kết luận
Trong hướng dẫn này, chúng tôi đã thảo luận về các thư viện mã nguồn mở PHP khác nhau mà bạn có thể sử dụng để quét một trang web.
Nếu bạn làm theo hướng dẫn, bạn sẽ có thể tạo một công cụ quét cơ bản để thu thập dữ liệu một hoặc hai trang.
Mặc dù đây là bài viết giới thiệu, nhưng chúng tôi đã đề cập đến hầu hết các phương pháp mà bạn có thể sử dụng với các thư viện. Bạn có thể chọn xây dựng dựa trên kiến thức này và tạo các trình quét web phức tạp có thể thu thập dữ liệu hàng nghìn trang. Mã cho hướng dẫn này có sẵn từ kho lưu trữ GitHub này.
Vui lòng liên hệ nếu bạn có bất kỳ câu hỏi nào.
Bạn có thể xem một số bài viết khác về quét web bằng Nodejs và quét web bằng Python nếu bạn quan tâm.