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

简单的 Puppeteer 网页抓取教程

这是使用 Node.js 库 Puppeteer 进行网页抓取的分步指南。

Puppeteer 网络抓取

多年来,网站发生了很大变化。网页抓取现代网站或单页应用程序需要渲染整个页面。它们依赖于延迟加载和无限滚动等元素,因此 传统文字 没什么帮助。无头浏览器库(如 Puppeteer)在网页抓取动态网站方面发挥着关键作用。

在本分步指南中,您将了解为什么 Puppeteer 是用于网页抓取的如此流行的 Node.js 库。您还将找到一个如何抓取动态页面的真实示例。 

什么是 Puppeteer 抓取?

网页抓取 使用 Puppeteer 的过程是控制 无头 Chrome 浏览器从目标网站提取数据。它是 Google 团队于 2018 年创建的一个广泛使用的 Node.js 库。尽管 Puppeteer 相对较新,但该库是抓取依赖 JavaScript 的网站的热门选择。 

Puppeteer 可以自动执行大多数浏览器交互,例如填写表格、移动鼠标​​、等待页面加载、截屏等操作。  

该库由 Chrome 浏览器自动化开发人员维护,因此您将拥有最新的浏览器版本和功能。但是,它仅正确支持 Chrome 和 Chromium;对 Firefox 和 Microsoft Edge 的支持仍处于试验阶段。

使用 Puppeteer 进行网页抓取的优势

木偶戏 比其他无头浏览器库快得多 和 Selenium 类似。主要原因是它使用了 Chromium 内置的 DevTools 协议,可以直接控制浏览器。而且占用资源少,所以执行时间相对较快。 

图书馆 有很棒的插件 喜欢 puppeteer-extra-plugin-stealth or puppeteer-extra-plugin-匿名化-ua 您可以使用这些方法来伪造浏览器指纹。例如,您可以旋转标头或用户代理。此外,您还可以 将代理与 Puppeteer 集成。

Puppeteer 相对容易使用。 例如,它没有内置的集成开发环境 (IDE)(如 Selenium)来编写脚本,因此您可以使用自己选择的 IDE。对您来说,这意味着编写更少的代码。此外,安装库不会花费太多时间 - 添加 npm 或 yarn 包管理器并下载包即可。

在所有功能中,Puppeteer 有精心制作的文档 以及庞大的用户社区。因此,如果您在使用该工具时遇到任何困难,很快就能找到答案。 

Node.js 和 Puppeteer Web 抓取:分步教程

在本分步教程中,我们将使用 Puppeteer 抓取引言网站 quotes.toscrape.com。我们将从两个 URL 中提取文本、引言、作者和标签数据点:

两个链接都包含动态元素。有什么区别?第二个页面用于处理延迟渲染。当页面需要时间加载,或者您需要等待特定条件满足才能提取数据时,这很有用。

待抓取的引文

硬件需求

  • Node.js。 确保你的系统上安装了最新的 Node.js 版本。你可以从 官方网站.
  • 木偶。 由于我们将使用 Puppeteer,因此你还需要安装它。请参阅 官方网站 了解如何在您的系统上安装它。

导入库

步骤 1。 首先,让我们导入必要的元素。

1)导入Puppeteer库。

				
					import puppeteer from 'puppeteer'

				
			

2) 由于我们将使用内置的 Node.js 文件系统模块,因此您也需要导入它。

				
					import fs from 'fs'

				
			

3)然后,导入 URL,以便您可以抓取它们。

				
					const start_url = 'http://quotes.toscrape.com/js/'
//const start_url = 'http://quotes.toscrape.com/js-delayed/'
				
			

设置CSS选择器

步骤 1。 通过右键单击页面上的任意位置并按“检查”来检查 quotes.toscrape.com/js 的页面源代码。

引文-引文-html
检查网页。

步骤 2。 您需要选择所有引用类对象,并在其中找到以下类的文本:文本、引用、作者和标签。

				
					const quote_elem_selector = '.quote'
const quote_text_selector = '.text'
const quote_author_selector = '.author'
const quote_tag_selector = '.tag'
const next_page_selector = '.next > a'
				
			

步骤 3。 设置一个列表,用于写下所抓取的引文。

				
					var quotes_list = []

				
			

准备刮擦

步骤 1。 我们将使用 headful 模式,这样您就可以看到正在发生的事情。 

				
					async function prepare_browser() {
    const browser = await puppeteer.launch({
        headless: false,
    })
    return browser
}
				
			

注意: 如果您想添加 puppeteer-extra-plugin-stealth 来隐藏您的数字指纹或设置代理以避免基于 IP 的限制,这里就是您要找的地方。如果您不知道如何使用 Puppeteer 设置代理,我们准备了一个分步教程。

了解如何使用 Puppeteer 设置代理服务器。

步骤 2。 然后,写下 主() 功能。

				
					async function main() {

				
			

1)调用setup_browser函数获取浏览器对象。

				
					    var browser = await prepare_browser()
    var page = await browser.newPage()
				
			

2)现在,让我们开始使用start_url字符串进行抓取。

				
					    await get_page(page, start_url)

				
			

3)抓取完成后关闭浏览器。

				
					    await browser.close()

				
			

4)在终端窗口打印出JSON输出。

				
					    console.log(quotes_list)
}
				
			

5)当代码开始运行时,您需要调用main()函数。

				
					main()

				
			
编码输出

使用 Node.js 和 Puppeteer 抓取多个页面

步骤 1。 让我们使用 get_page() 函数转到 URL,获取 HTML 输出,并转到下一页。

				
					async function get_page(page, url) {
    await page.goto(url)
				
			

1) 现在,我们将使用 quote_selector 告诉 Puppeteer 等待内容出现。一旦出现带有 class=quote 的元素,它就会开始抓取。我们将超时值设置为 20 秒。

				
					    await page.waitForSelector(quote_elem_selector, {timeout: 20_000})

				
			

2)然后,调用scrape函数来解析HTML。

				
					    await scrape(page)

				
			

3)检查下一页选择器并提取 href 属性以进行抓取。

				
					    try {
        let next_href = await page.$eval(next_page_selector, el => el.getAttribute('href'))
        let next_url = `https://quotes.toscrape.com${next_href}`
        console.log(`Next URL to scrape: ${next_url}`)
				
			

4)再次调用get_page()函数并将new_url传递给scrape。

				
					        await get_page(page, next_url)
      } catch {
        // Next page button not found, end job
        return
      }
}
				
			

步骤 2。 现在,让我们进入解析部分。我们将使用 scrape() 函数。

				
					async function scrape(page) {

				
			

1)找到所有quote元素并把它们放入quote_elements列表中。

				
					    let quote_elements = await page.$$(quote_elem_selector)

				
			

2)然后,遍历列表以查找每个报价的所有值。

				
					    for (let quote_element of quote_elements) {

				
			

3)现在,让我们使用选择器找到我们需要的元素并提取它们的文本内容。

				
					        let quote_text =  await quote_element.$eval(quote_text_selector, el => el.innerText)
        let quote_author = await quote_element.$eval(quote_author_selector, el => el.innerText)
        let quote_tags = await quote_element.$$eval(quote_tag_selector, els => els.map(el => el.textContent))
        //console.log(quote_text)
        //console.log(quote_author)
        //console.log(quote_tags)
        // Putting the output into a dictionary
        var dict = {
            'author': quote_author,
            'text': quote_text,
            'tags': quote_tags,
        }
				
			

5)将字典推入quotes_list以获取输出。

				
					        quotes_list.push(dict)
    }
}
				
			

这是输出:

				
					PS C:\node-projects\scraping> node .\index.js
Next URL to scrape: https://quotes.toscrape.com/js/page/2/
Next URL to scrape: https://quotes.toscrape.com/js/page/3/
Next URL to scrape: https://quotes.toscrape.com/js/page/4/
Next URL to scrape: https://quotes.toscrape.com/js/page/5/
Next URL to scrape: https://quotes.toscrape.com/js/page/6/
Next URL to scrape: https://quotes.toscrape.com/js/page/7/
Next URL to scrape: https://quotes.toscrape.com/js/page/8/
Next URL to scrape: https://quotes.toscrape.com/js/page/9/
Next URL to scrape: https://quotes.toscrape.com/js/page/10/
[
{
author: 'Albert Einstein',
text: '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”',
tags: [ 'change', 'deep-thoughts', 'thinking', 'world' ]
},
{
author: 'J.K. Rowling',
text: '“It is our choices, Harry, that show what we truly are, far more than our abilities.”',
tags: [ 'abilities', 'choices' ]
},
{
author: 'Albert Einstein',
text: '“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”',
tags: [ 'inspirational', 'life', 'live', 'miracle', 'miracles' ]
},
				
			

将输出保存到 CSV 文件

步骤 1。 创建一个函数来将我们抓取并解析的输出写入 CSV:

				
					function write_to_csv(){

				
			

1) 从 quotes_list 对象获取键。这将是 csv 文件的第一行。

				
					    var csv = Object.keys(quotes_list[0]).join(', ') + '\n'

				
			

2)遍历每个引文字典元素。

				
					    quotes_list.forEach(function(quote) {

				
			

3)向 CSV 变量中添加新行,并在行末添加换行符。

				
					        csv += `${quote['author']}, ${quote['text']}, "${quote['tags']}"\n`
    })
				
			

4)将输出写入output.csv文件

				
					    fs.writeFile('output.csv', csv, (err) => {
        if (err) 
            console.log(err)
        else {
            console.log("Output written successfully")
        }
    })
}
				
			

步骤 2。 写 主() 功能。

				
					async function main() {

				
			

1)通过调用setup_browser函数初始化浏览器设置并获取浏览器对象。

				
					    var browser = await prepare_browser()
    var page = await browser.newPage()
				
			

2)开始刮擦。

				
					    await get_page(page, start_url)

				
			

3)抓取完成后关闭浏览器。

				
					    await browser.close()

				
			

4)在终端窗口打印出输出json。

				
					    console.log(quotes_list)

				
			

5)将输出写入 CSV。

				
					    write_to_csv()
}
				
			
引用以抓取 CSV
这是完整的代码:
				
					import puppeteer from 'puppeteer'
import fs from 'fs'

const start_url = 'http://quotes.toscrape.com/js/'
//const start_url = 'http://quotes.toscrape.com/js-delayed/'

const quote_elem_selector = '.quote'
const quote_text_selector = '.text'
const quote_author_selector = '.author'
const quote_tag_selector = '.tag'
const next_page_selector = '.next > a'

var quotes_list = []

async function prepare_browser() {
    const browser = await puppeteer.launch({
        headless: false,
    })
    return browser
}

async function get_page(page, url) {
    await page.goto(url)
    await page.waitForSelector(quote_elem_selector, {timeout: 20_000})
    await scrape(page)
    try {
        let next_href = await page.$eval(next_page_selector, el => el.getAttribute('href'))
        let next_url = `https://quotes.toscrape.com${next_href}`
        console.log(`Next URL to scrape: ${next_url}`)
        await get_page(page, next_url)
      } catch {
        return
      }
}

async function scrape(page) {
    let quote_elements = await page.$$(quote_elem_selector)
    for (let quote_element of quote_elements) {
        // Here we find the elements by using the selectors and extracting their text content
        let quote_text =  await quote_element.$eval(quote_text_selector, el => el.innerText)
        let quote_author = await quote_element.$eval(quote_author_selector, el => el.innerText)
        let quote_tags = await quote_element.$$eval(quote_tag_selector, els => els.map(el => el.textContent))
        //console.log(quote_text)
        //console.log(quote_author)
        //console.log(quote_tags)
        var dict = {
            'author': quote_author,
            'text': quote_text,
            'tags': quote_tags,
        }
        quotes_list.push(dict)
    }
}

function write_to_csv(){
    var csv = Object.keys(quotes_list[0]).join(', ') + '\n'
    quotes_list.forEach(function(quote) {
        csv += `${quote['author']}, ${quote['text']}, "${quote['tags']}"\n`
    })
    //console.log(csv)
    fs.writeFile('output.csv', csv, (err) => {
        if (err) 
            console.log(err)
        else {
            console.log("Output written successfully")
        }
    })
}

async function main() {
    var browser = await prepare_browser()
    var page = await browser.newPage()
    await get_page(page, start_url)
    await browser.close()
    console.log(quotes_list)
    write_to_csv()
}

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