Cheerio Web Scraping:如何使用 Node.js 抓取静态页面的教程
有兴趣从静态网页收集数据吗?Cheerio 和 Axios 库非常适合这项工作。了解开始网页抓取项目所需的一切。
Node.js 是用于网页抓取的出色运行时。它最出名的是其用于动态网站的强大无头浏览器库。但您也可以从静态网页收集数据并清理以供进一步使用。一个非常流行的 Node.js 库是 Cheerio。
在本指南中,您将了解什么是使用 Cheerio 进行网页抓取,以及它可以为您的网页抓取项目带来哪些优势。我们还将解释成功从静态网页收集数据所需的其他工具,以及如何使用 Cheerio 和 Axios 构建网页抓取工具。所有信息都将包含在一个真实的示例中,以便您可以练习您的技能。
什么是使用 Cheerio 进行网页抓取?
网页抓取 使用 Cheerio 涉及几个步骤。
Cheerio 不是一个独立的库:它只能 解析或构建网页内容。您首先需要选择一个 HTTP 客户端(例如 Axios),它将从目标网页获取 HTML。
获得 HTML 内容后,您可以将其加载到 Cheerio 中。然后,该库将允许您使用 jQuery 语法来遍历和操作 HTML 结构。Cheerio 允许选择页面元素并使用 CSS 选择器提取数据。这可以是文本、链接、图像或任何其他信息。 您还可以根据属性或值过滤元素。
有些网站需要你处理分页或抓取嵌套在 JavaScript 中的数据。Cheerio 无法执行 JavaScript;如果是这种情况,你需要一个无头浏览器库,例如 剧作家或木偶戏演员.
使用 Cheerio 进行网页抓取的优势
如果您熟悉 jQuery,那么使用 Cheerio 进行网页抓取非常简单,因为它具有类似的语法。
Cheerio 是一款非常灵活的工具。它基于 parse5(用于解析 HTML)和 htmlparser2(用于解析 XML 文档)构建而成。它结合了两者的功能;例如,parse5 确保符合 HTML 标准。实际上,它可以解析任何 HTML 和 XML 文档。此外,该库还允许您遍历 DOM 结构,以便您可以选择和操作特定元素。
它还支持一系列 CSS 选择器,因此您可以轻松地定位文档中的元素。
与大多数解析库一样,Cheerio 占用的资源很少。该工具在服务器端运行,不需要完整的浏览器环境,因此您可以处理复杂的页面。
使用 Node.js 库 Axios 和 Cheerio 抓取静态页面
在本分步教程中,我们将从 books.toscrape.com 抓取书籍列表(书名、价格、评分、库存和 URL)。尽管 Node.js 有一个集成的请求库,但它并不易于使用,因此很少有人选择它来获取数据。因此,我们将使用 Axios 来获取页面。
硬件需求
- Node.js。 确保你的系统上安装了最新的 Node.js 版本。你可以从 官方网站.
- Axios。 您可以通过运行来添加它 npm 安装 axios 在您的操作系统终端中。
- 啦啦队。 您可以通过运行来添加它 npm 安装 Cheerio.
导入库
步骤 1。 首先,我们导入必要的库
1)导入Node.js HTTP 客户端 axios。
import axios from 'axios'
2)导入Node.js解析器Cheerio。
import { load } from 'cheerio'
3)导入内置的Node.js文件系统模块,将结果写入CSV文件。
import fs from 'fs'
下载页面
步骤 1。 让我们下载目标页面。
const start_url = "http://books.toscrape.com/"
步骤 2。 创建一个列表来存储数据。
const books_list = []
步骤 3。 定义 刮() 功能。
async function scrape(url) {
步骤 4。 发出 HTTP 请求并等待响应。
let resp = await axios.get(url)
步骤 5。 从响应中提取 HTML。
let resp_html = resp.data
提取数据点
步骤 1。 将 HTML 加载到 Cheerio 中 $ 目的。
const $ = load(resp_html)
步骤 2。 将 Cheerio 实例传递给 解析() 功能。
parse($)
步骤 3。 找到下一页选择器和 HREF 属性来抓取下一页。
try {
let next_href = $('.next > a').attr("href")
// In case the '/catalogue/' part of the URL is not found within
// the href attribute value, add it to the href
if (!next_href.includes('catalogue')){
next_href = `catalogue/${next_href}`
}
步骤 4。 格式化我们要抓取的下一页的绝对 URL。
let next_url = start_url + next_href
console.log('Scrape: ' + next_url)
步骤 5。 调用 刮() 再次运行并传递 URL。
const book_price = $(element).find('.price_color').text().replace('£', '')
解析 HTML
步骤 1。 定义解析函数。
function parse($){
步骤 2。 现在,我们需要确定数据点的位置。让我们抓取四个元素:书名、价格、评分和可用性。右键单击页面上的任意位置,然后按 检查。您可以看到它们都属于一个名为 产品吊舱:
步骤 3。 我们可以提取整个类:
$('.product_pod').map((i, element) => {
但是得到的数据会比较混乱,所以还是具体一点吧。
1)通过查找元素内的 H3 标签来提取书名。
const book_title = $(element).find('h3').text()
2)然后,通过去掉英镑符号来提取书价。
const book_price = $(element).find('.price_color').text().replace('£', '')
3)现在,从 p 标记为 班级之星 评级和 序号 (书的评级)。这部分稍微复杂一些,因为评级在包含两个单词的名称中,而我们只需要一个。
因此,您首先需要找到具有该类的元素并获取其值 程 属性,返回字符串。可以使用空格作为分隔符将此字符串拆分为单词列表,然后获取第二个单词。
const book_rating = $(element).find('p.star-rating').attr("class")
.split(' ')[1]
4)通过查找元素来提取图书库存信息 股票 对不必要的空格进行分类并修剪。
const book_stock = $(element).find('.instock').text().trim()
5)通过查找 a 标签内 产品吊舱 元素并获取其 HREF 您需要将其附加到 起始网址。
const book_url = start_url + $(element).find('a').attr("href")
步骤 4。 现在,让我们将数据点附加到列表中:
books_list.push({
"title": book_title,
"price": book_price,
"rating": book_rating,
"stock": book_stock,
"url": book_url
})
步骤 5。 结束迭代。
})
//console.log(books)
}
将输出保存到 CSV 文件
步骤 1。 现在,让我们通过将所有数据写入 CSV 文件来构造它。
function write_to_csv(){
步骤 2。 从书籍对象中获取键,这将成为 csv 文件的第一行
var csv = Object.keys(books_list[0]).join(', ') + '\n'
步骤 3。 遍历每个书籍词典元素。
books_list.forEach(function(book) {
步骤 4。 在 CSV 变量末尾带有换行符。
csv += `"${book['title']}", ${book['price']}, ${book['rating']}, ${book['stock']}, ${book['url']},\n`
})
//console.log(csv)
步骤 5。 将输出写入 CSV 文件。
fs.writeFile('output.csv', csv, (err) => {
if (err)
console.log(err)
else {
console.log("Output written successfully")
}
})
}
步骤 6。 然后,将 URL 传递给 scrape 函数并告诉 Node.js 等待它,以便在我们继续写入输出之前完成所有抓取。
await scrape(start_url)
步骤 7。 调用函数来写入输出。
write_to_csv()
这是完整的代码:
import axios from 'axios'
import { load } from 'cheerio'
// For writing into the output file
import fs from 'fs'
const start_url = "http://books.toscrape.com/"
const books_list = []
// Requesting the page with the help of Axios and waiting for the response
let resp = await axios.get(url)
let resp_html = resp.data
// Loading the html into Cheerio. $ - Cheerio object
const $ = load(resp_html)
// Passing the Cheerio instance to the parse() function
parse($)
try {
// Try finding the next page selector and
// extract the href attribute for scraping the next page
let next_href = $('.next > a').attr("href")
// In case the '/catalogue/' part of the URL is not found within
// the href attribute value, add it to the href
if (!next_href.includes('catalogue')){
next_href = `catalogue/${next_href}`
}
// Formatting the absolute URL of the next page we are going to scrape
let next_url = start_url + next_href
console.log('Scrape: ' + next_url)
// Calling the scrape() function again and passing it the URL
await scrape(next_url)
} catch {
// Next page selector not found, end job
return
}
}
// Function for parsing the html of the page.
function parse($){
// The selector for each distinct book element on the page is an article
// tag with the class of "product_pod". This line finds all such elements
// and begins iterating through them.
$('.product_pod').map((i, element) => {
// To get the title, we find the h3 tag within the element and
// extract its text.
const book_title = $(element).find('h3').text()
// Price is also simple, we just get rid of the pound sign
const book_price = $(element).find('.price_color').text().replace('£', '')
// The book ratings are easily scraped from the p tag with the classes
// "star rating" and "Num" where "Num" is the rating the book has
// received. To extract the rating, we first find the element with that
// class, get the value of the "class" attribute which returns a string:
// e.g. "star-rating One", split that string by whitespaces and assign
// the second element of the resulting list to our variable.
const book_rating = $(element).find('p.star-rating').attr("class")
.split(' ')[1]
// Simply finding the element by the "instock" class, extracting the
// text and trimming the resulting string to strip away unnecessary
// whitespaces.
const book_stock = $(element).find('.instock').text().trim()
// To extract the url of the book, we find the a tag within the
// product_pod element and get its "href" attribute which we append to
// the start_url
const book_url = start_url + $(element).find('a').attr("href")
// Appending the results dictionary to the books_list
books_list.push({
"title": book_title,
"price": book_price,
"rating": book_rating,
"stock": book_stock,
"url": book_url
})
})
//console.log(books)
}
function write_to_csv(){
// Getting the keys from the books object, this will become the first line of the csv file
var csv = Object.keys(books_list[0]).join(', ') + '\n'
// Iterating through each book dictionary element
books_list.forEach(function(book) {
// Adding a new line to the csv variable with the line break at the end
csv += `"${book['title']}", ${book['price']}, ${book['rating']}, ${book['stock']}, ${book['url']},\n`
})
//console.log(csv)
// Writing the output to a output.csv file
fs.writeFile('output.csv', csv, (err) => {
if (err)
console.log(err)
else {
console.log("Output written successfully")
}
})
}
// Script starts here, we pass the URL we are going to start our scrape on to
// the scrape function and tell node for it to be awaited so that all of the
// scrapes finish before we move on to writing the output
await scrape(start_url)
// Calling the function to write the output
write_to_csv()
使用 Node.js 和 Puppeteer 抓取动态网页
如果您想抓取动态页面,我们还准备了一个使用无头 Node.js 浏览器库 Puppeteer 的分步教程。该指南将引导您从 quotes.toscrape.com 中提取数据,特别是文本、引文、作者和标签数据点。我们还将向您展示如何处理延迟渲染,以及在哪里 整合代理 在你的脚本中。
这是使用 Node.js 库 Puppeteer 进行网页抓取的分步指南。