我们使用联盟链接。它们让我们能够维持运营,而您无需承担任何费用。

Cheerio Web Scraping:如何使用 Node.js 抓取静态页面的教程 

有兴趣从静态网页收集数据吗?Cheerio 和 Axios 库非常适合这项工作。了解开始网页抓取项目所需的一切。

Cheerio 网页抓取

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 来获取页面。

书籍-toscrape-main
books.toscrape.com 主页

硬件需求

  • 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。 现在,我们需要确定数据点的位置。让我们抓取四个元素:书名、价格、评分和可用性。右键单击页面上的任意位置,然后按 检查。您可以看到它们都属于一个名为 产品吊舱:

Bookstoscrape 检查元素

步骤 3。 我们可以提取整个类:

				
					$('.product_pod').map((i, element) => {

				
			
productpod 印刷

但是得到的数据会比较混乱,所以还是具体一点吧。

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()
				
			
bookstoscrape 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 进行网页抓取的分步指南。

Adam Dubois 的图片
亚当·杜波依斯
代理极客和开发人员。