我用 crawlee 抓取了 9 月掘金所有面试相关文章

1,234 阅读10分钟

无头浏览器与爬虫

最近在研究爬虫,因为很多数据是需要做客户端渲染的, 所以需要一个无头浏览器来做渲染。 然后才能拿到最终的数据。

说到无头浏览器, 大家第一反应想到的大概率就是 Puppeteer, 但是我这里用到的不是 Puppeteer , 而是 crawlee.

PuppeteerCrawlee 都有各自的优势和适用场景。如果需要与页面进行交互、处理动态内容或模拟真实用户行为,Puppeteer 是一个强大的选择。而如果专注于高效的爬取任务,Crawlee 则提供了更简洁、高效的解决方案。根据具体的需求和项目特点,可以选择适合的工具来实现 Node.js 爬虫。

介绍一下 node 最强爬虫 - Crawlee

我愿称之为最强 Node 爬虫。可以说是 Crawlee 是专为爬虫而生的框架。 简单来看几个特性, 大家应该就能体会到它到底有多强了。

JavaScript 和 TypeScript 支持

我们认为,最好使用网站编写语言来抓取数据。Crawlee在 Node.js 上运行,并且内置了 TypeScript, 即使您自己不使用 TypeScript,也可以提高 IDE 中的代码完成度。Crawlee 同时支持 TypeScript 和 JavaScript 抓取。

HTTP 抓取

Crawlee 发出模仿浏览器标头和 TLS 指纹的 HTTP 请求。它还根据有关真实世界流量的数据自动轮换它们。其中包括流行的 HTML 解析器 Cheerio  和JSDOM 。

无头浏览器支持

只需 3 行代码即可将您的爬虫从 HTTP 切换到无头浏览器。Crawlee 建立在Puppeteer 和 Playwright之上,并添加了自己的防阻塞功能和类似人类的指纹。Chrome、Firefox 等。

自动扩展和代理管理

Crawlee 根据可用的系统资源自动管理并发,并 智能地轮换代理。经常超时、返回网络错误或错误 HTTP 代码(如 401 或 403)的代理将被丢弃。

队列和存储

您可以使用一行代码将文件、屏幕截图和 JSON 结果保存到磁盘,或为您的数据库插入适配器。您的 URL保存在一个队列中,以确保其唯一性,并且当出现故障时您不会丢失进度。

有用的实用程序和可配置性

Crawlee 包括提取社交账号或电话号码、无限滚动、屏蔽不需要的资产工具。它开箱即用,还提供了 丰富的配置选项

简单实践一下抓取掘金热榜

Crawlee 有三个主要的爬虫类:CheerioCrawlerPuppeteerCrawlerPlaywrightCrawler

CheerioCrawler这是一个普通的 HTTP 爬虫。它使用Cheerio 库解析 HTML ,并使用伪装成浏览器的专用got-scraping HTTP 客户端爬取网页。它非常快速高效,但无法处理 JavaScript 渲染。

PuppeteerCrawler: 此爬虫使用无头浏览器进行爬取,由Puppeteer库控制。它可以控制 Chromium 或 Chrome。Puppeteer 是无头浏览器自动化领域的事实上的标准。

playwrightcrawlerPlaywright是 Puppeteer 的更强大、功能更全面的继任者。它可以控制 Chromium、Chrome、Firefox、Webkit 和许多其他浏览器。如果您还不熟悉 Puppeteer,并且需要无头浏览器,请使用 Playwright。

我们这里将要使用的也就是 playwrightcrawler 爬虫方式;

安装依赖

依赖安装:npm install crawlee playwright

playwright未与 Crawlee 捆绑在一起,以减少安装大小并提供更大的灵活性。所以要使用 NPM 明确安装它。

上代码

import { PlaywrightCrawler } from "crawlee";

const crawler = new PlaywrightCrawler({
  // 是否开启 headless 
  // headless: false,
  requestHandler: async ({ page }) => {
    // 等待文章元素加载完成
    await page.waitForSelector(".article-item-link");
    
    // 执行 script 获取文章链接
    const categoryTexts = await page.$$eval(".article-item-link", (els) => {
      // 获取文章链接和文章名称
      return els.map((el) => {
        return {
          url: el.getAttribute("href"),
          name: el.querySelector(".article-detail")?.firstChild?.textContent,
        };
      });
    });
    categoryTexts.forEach((text, i) => {
      console.log(`文章${i + 1}: ${JSON.stringify(text, undefined, 2)}\n`);
    });
  },
});

// 前端热榜链接
crawler.run(["https://juejin.cn/hot/articles/6809637767543259144"]);

直接执行即可,执行结果如下

20241015005057_rec_.gif

代码详解

一、导入模块

import { PlaywrightCrawler } from "crawlee";

从“crawlee”库中导入“PlaywrightCrawler”类,这个类可以利用 Playwright 来进行网页爬取,能够处理包含动态内容的网页。

二、创建爬虫实例

const crawler = new PlaywrightCrawler({
  // headless: false,

创建一个PlaywrightCrawler的实例。注释部分表示可以设置是否以无头模式(即无界面模式)运行浏览器,这里没有启用非无头模式,可能默认以无头模式运行。

三、定义请求处理函数

requestHandler: async ({ page }) => {
  // 等待特定元素加载完成
  await page.waitForSelector(".article-item-link");

定义了一个异步的请求处理函数,当爬虫访问一个页面时,这个函数会被执行。这里首先等待页面中具有.article-item-link类名的元素加载完成。

const categoryTexts = await page.$$eval(".article-item-link", (els) => {
  // 获取文章链接和文章名称
  return els.map((el) => {
    return {
      url: el.getAttribute("href"),
      name: el.querySelector(".article-detail")?.firstChild?.textContent,
    };
  });
});

接着,使用page.$$eval方法在浏览器环境中执行一个函数。这个函数接收具有.article-item-link类名的元素数组作为参数els。在函数内部,遍历这些元素,提取每个元素的href属性作为文章链接url,以及通过查找具有.article-detail类名的元素的第一个子元素的文本内容作为文章名称name,并以对象的形式组成一个数组categoryTexts返回。

categoryTexts.forEach((text, i) => {
  console.log(`文章${i + 1}: ${JSON.stringify(text, undefined, 2)}\n`);
});

最后,遍历提取到的文章信息数组,将每个文章信息以格式化的 JSON 字符串形式打印到控制台,并在前面加上“文章[序号]”的标识。

四、启动爬虫

crawler.run(["https://juejin.cn/hot/articles/6809637767543259144"]);

启动爬虫,传入一个包含要爬取的 URL 的数组,这里只有一个“前端热榜”的 URL。爬虫会访问这个 URL,并执行前面定义的请求处理函数,提取文章的链接和名称信息并输出到控制台。

最后的彩蛋:附上我用 crawlee 抓取 9 月掘金面试相关文章列表

面试

后端

前端

后端,面试

Rust,算法

后端,MySQL

Android

React.js

Rust

前端,JavaScript

JavaScript

数据分析

前端,面试

创业

Java

测试

面试,Flutter

后端,Redis