如何使用 Browserless 抓取动态网站?

什么是动态网页?

动态网页是指其内容并非完全直接嵌入在静态HTML中,而是通过服务器端或客户端渲染生成的网页。

它可以根据用户的操作实时显示数据,例如在用户点击按钮或向下滚动页面时加载更多内容(如无限滚动)。这种设计可以改善用户体验,并允许用户无需重新加载整个页面即可获得相关信息。

要判断一个网站是否是动态网页,可以在浏览器中禁用JavaScript。如果该网站是动态的,大多数内容将消失。

爬取动态网站时面临的挑战

指纹识别和封锁

  1. 指纹识别技术: 许多网站使用指纹识别技术来检测和阻止自动爬虫。这些技术通过分析用户的浏览器行为、屏幕分辨率、插件、时区等信息来创建每个用户的唯一“指纹”。如果检测到异常或与正常用户行为不一致,网站可能会阻止访问。

  2. 封锁机制: 为了保护其内容,网站会实施各种封锁机制,例如:

  • IP封锁: 当同一IP地址频繁发出请求时,网站可能会暂时或永久禁止该IP地址访问。
  • 验证码验证: 当检测到自动化流量时,网站可能会引入验证码,以确认访问者是人类。
  • 流量限制: 设置请求速率限制,当请求速率超过预设阈值时,网站将拒绝进一步的请求。

本地加载挑战

  1. 资源消耗: 动态页面通常需要更多系统资源来进行渲染和数据抓取。当使用Puppeteer或Selenium等工具时,可能会导致内存和CPU使用率过高,尤其是在抓取多个页面时。
  2. 延迟和时间成本: 由于需要等待页面完全加载(包括JavaScript执行和AJAX请求),抓取动态页面的时间成本可能会很高,这将影响整个爬虫的效率。
  3. 并发处理: 在高负载情况下,同时处理多个抓取任务可能会导致系统过载,导致请求失败或超时。这需要合理的任务调度和资源管理策略。

你对网页抓取和 Browserless 有什么绝妙的想法或疑问吗?
让我们看看其他开发者在 Discord 和 Telegram 上分享了什么!

抓取动态网站的 6 种有效方法

1. 拦截XHR/Fetch请求

在抓取过程中拦截XHR(XMLHttpRequest)和Fetch请求的一种有效方法是检查浏览器的Network选项卡,以识别提供动态内容的API端点。一旦识别出这些端点,就可以使用HTTP客户端(如Requests库)直接向这些API发送请求以获取数据。

  • 优点: 此方法通常很快,并且可以高效地提取数据,因为它只获取所需的内容,而不是整个网页。
  • 缺点: 如果数据以JSON的形式存储在DOM中,而不是由API返回,这可能具有挑战性。此外,模拟API请求的过程可能会受到API更改、速率限制和身份验证要求的影响,导致可扩展性差。

2. 使用无头浏览器

使用无头浏览器(如Puppeteer或Selenium)可以完全模拟用户行为,包括页面加载和交互。这些工具能够处理JavaScript并抓取动态生成的内容。

  • 优点: 此方法能够抓取高度动态的网站,并支持复杂的用户交互。
  • 缺点: 资源消耗高、抓取速度慢,并且可能需要处理复杂的页面结构和动态内容。

3. API请求

直接从网站的API请求数据是一种高效的抓取方式。分析网站的网络请求,找到API端点,并使用HTTP客户端请求数据。

  • 优点: 能够直接获取所需数据,并避免解析HTML的复杂性。
  • 缺点: 如果API需要身份验证或具有请求频率限制,可能会影响抓取效率。

4. 抓取AJAX请求

通过监控网络请求,识别AJAX调用并重现它们,可以提取动态加载的数据。

  • 优点: 直接获取数据源,减少不必要的加载。
  • 缺点: 需要对AJAX请求的参数和格式有一定了解,并且可能还会遇到身份验证和速率限制问题。

5. 代理和IP轮换

为了避免被网站封锁,使用代理服务和IP轮换是一种重要的策略。这可以帮助分散请求,降低被检测到的风险。

  • 优点: 降低被封锁的概率,可以在大量请求中保持有效性。
  • 缺点: 使用代理服务可能会增加抓取成本,并且需要维护代理列表。

6. 模拟用户行为

编写脚本模拟人类浏览行为,例如在请求之间添加延迟,随机化操作顺序等,可以帮助降低被网站识别为爬虫的风险。

  • 优点: 数据抓取可以更自然地进行,降低被检测到的风险。
  • 缺点: 实现起来比较复杂,需要花费时间调整和优化模拟行为。

什么是 Browserless?

Browserless 是一种无头chrome云服务,它可以在没有图形用户界面的情况下运行在线应用程序和自动化脚本。对于网页抓取和其他自动化操作,它特别有用。

在我们的视频中找到更多细节!

Browserless 使抓取动态网页变得容易

Browserless 也是一个强大的无头浏览器。接下来,我们将以Browserless为例来抓取动态网页。

先决条件

在我们开始之前,我们需要拥有Browserless服务。使用Browserless可以解决复杂的网页抓取和大型自动化任务,并且现在已经实现了全托管云部署。

Browserless 采用浏览器为中心的策略,提供强大的无头部署能力,并提供更高的性能和可靠性。您可以访问 Nstbrwoser 的使用教程了解有关 Browserless 服务配置的更多信息。

在一开始,我们需要获取Nstbrowser的API KEY。您可以前往 Nstbrowser 客户端的 Browserless菜单页面。

确定抓取目标

在我们开始之前,让我们确定本次测试的目标。我们将使用Puppeteer和Playwright来获取动态网站的页面标题内容:

  1. 访问目标网站:https://www.nstbrowser.io/en
  2. 获取动态页面标题内容

初始化项目

按照以下步骤安装依赖项:

  • 步骤1: 在Vs code中创建一个新文件夹
  • 步骤2: 打开Vs code终端,运行以下命令以安装相关的依赖项
npm init -y
pnpm add playwright puppeteer-core

使用Playwright和Browserless抓取动态网页

  • 创建一个抓取脚本
const { chromium } = require('playwright');

async function createBrowser() {
  const token = ''; // required
  const config = {
    proxy:
      '', // required; input format: schema://user:password@host:port eg: http://user:password@localhost:8080
    // platform: 'windows', // support: windows, mac, linux
    // kernel: 'chromium', // only support: chromium
    // kernelMilestone: '124', // support: 113, 120, 124
    // args: {
    //   '--proxy-bypass-list': 'detect.nstbrowser.io',
    // }, // browser args
    // fingerprint: {
    //   userAgent:
    //     'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.85 Safari/537.36',
    // },
  };
  const query = new URLSearchParams({
    token: token, // required
    config: JSON.stringify(config),
  });

  const browserWSEndpoint = `ws://less.nstbrowser.io/connect?${query.toString()}`;
  const browser = await chromium.connectOverCDP(browserWSEndpoint);
  const context = await browser.newContext();
  const page = await context.newPage();

  page.goto('https://www.nstbrowser.io/en');

  // sleep for 5 seconds
  await new Promise((resolve) => setTimeout(resolve, 5000));

  const h1Element = await page.$('h1');
  const content = await h1Element?.textContent();
  console.log(`Playwright: The content of the h1 element is: ${content}`)

  await page.close();
  await page.context().close();
}

createBrowser().then();
  • 检查抓取结果

抓取结果

使用Puppeteer和Browserless抓取动态网页

  • 创建一个抓取脚本
const puppeteer = require('puppeteer-core');

async function createBrowser() {
  const token = ''; // required
  const config = {
    proxy:
      '', // required; input format: schema://user:password@host:port eg: http://user:password@localhost:8080
    // platform: 'windows', // support: windows, mac, linux
    // kernel: 'chromium', // only support: chromium
    // kernelMilestone: '124', // support: 113, 120, 124
    // args: {
    //   '--proxy-bypass-list': 'detect.nstbrowser.io',
    // }, // browser args
    // fingerprint: {
    //   userAgent:
    //     'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.85 Safari/537.36',
    // },
  };
  const query = new URLSearchParams({
    token: token, // required
    config: JSON.stringify(config),
  });

  const browserWSEndpoint = `ws://less.nstbrowser.io/connect?${query.toString()}`;
  const browser = await puppeteer.connect({
    browserWSEndpoint: browserWSEndpoint,
    defaultViewport: null,
  });
  const page = await browser.newPage();

  await page.goto('https://www.nstbrowser.io/en');

  // sleep for 5 seconds
  await new Promise((resolve) => setTimeout(resolve, 5000));

  const h1Element = await page.$('h1');

  if (h1Element) {
    const content = await page.evaluate((el) => el.textContent, h1Element); // use page.evaluate to get the text content of the h1 element
    console.log(`Puppeteer: The content of the h1 element is: ${content}`);
  } else {
    console.log('No h1 element found.');
  }

  await page.close();
}

createBrowser().then();
  • 检查抓取结果

结论

抓取动态网页总是比抓取普通网页更复杂。在抓取过程中很容易遇到各种麻烦。通过本博文的介绍,您一定已经学习到了:

  • 6 种有效的方法来抓取动态网页
  • 使用 Browserless 轻松抓取动态网页
<think>我们正在讨论在NestJS项目中集成Puppeteer。用户提供了多个引用,其中引用[1]提到Node.js适合实时应用,但不适合CPU密集型任务;引用[2][3]提到了关于政采云前端团队的系列分享,其中包括爬虫实战和Node性能优化;引用[4]提供了一些NodeJs爬虫源码,包括使用puppeteer的例子。用户的问题:如何在NestJS中使用Puppeteer实现网页抓取或自动化任务?由于NestJS是一个基于Node.js的后端框架,而Puppeteer是一个Node库,用于控制无头浏览器,我们可以按照以下步骤进行:1.创建或进入现有的NestJS项目。2.安装Puppeteer依赖。3.创建一个服务(Service)来封装Puppeteer操作。4.在需要的地方(如控制器)使用这个服务。注意:Puppeteer在安装时会下载一个Chromium,这可能会在服务器上引起问题(比如在无头服务器环境中)。另外,Puppeteer比较消耗资源,需要注意管理浏览器实例,避免创建过多实例。参考引用[4]中的示例,其中使用了puppeteer和nodeJs,我们可以模仿其思想。步骤:1.安装Puppeteer:```bashnpminstallpuppeteer```2.生成一个服务模块(如果还没有):```bashnestgenerateservicepuppeteer```3.在生成的服务中,编写使用Puppeteer的代码。注意:由于Puppeteer启动浏览器是一个异步过程,并且可能抛出异常,需要妥善处理。4.我们可以创建一个启动浏览器的函数,并实现页面截图、数据提取等操作。5.在控制器中调用该服务。示例代码:在`puppeteer.service.ts`中:```typescriptimport{Injectable}from'@nestjs/common';import*aspuppeteerfrom'puppeteer';@Injectable()exportclassPuppeteerService{asyncscrape(url:string):Promise<string>{constbrowser=awaitpuppeteer.launch();constpage=awaitbrowser.newPage();awaitpage.goto(url);constcontent=awaitpage.content();//获取页面HTML内容awaitbrowser.close();returncontent;}//或者更复杂的操作,例如模拟登录asyncloginAndGetData(url:string,username:string,password:string):Promise<any>{constbrowser=awaitpuppeteer.launch();constpage=awaitbrowser.newPage();awaitpage.goto(url);//假设登录表单的输入框选择器和提交按钮选择器awaitpage.type('#username',username);awaitpage.type('#password',password);awaitpage.click('#submit');//等待导航到新页面awaitpage.waitForNavigation();//现在可以获取登录后的页面内容constcontent=awaitpage.content();awaitbrowser.close();returncontent;}}```在控制器中,我们可以这样使用:```typescriptimport{Controller,Get}from'@nestjs/common';import{PuppeteerService}from'./puppeteer.service';@Controller('scrape')exportclassScrapeController{constructor(privatereadonlypuppeteerService:PuppeteerService){}@Get()asyncscrape(){constdata=awaitthis.puppeteerService.scrape('https://example.com');returndata;}}```注意:上面的例子是每次请求都启动一个浏览器,然后关闭。这在高并发下可能会成为性能瓶颈。因此,通常我们会考虑复用浏览器实例,或者使用连接池等优化方法。另外,由于启动浏览器比较慢,所以也可以考虑在应用启动时就启动一个浏览器,然后作为单例在整个应用中共享。但是要注意,共享的浏览器实例可能会同时处理多个页面,这需要确保每个页面操作是隔离的。参考引用[2][3][4]中提到的关于Node性能优化的内容,以及爬虫实战,我们可以知道在高负载下需要优化。比如,使用`puppeteer-cluster`来管理多个浏览器实例,或者使用`browserless`这样的无头浏览器托管服务,避免在应用本地启动浏览器。另外,引用[3]提到“Node性能优化:我是如何懵逼应对Node定时批量任务爆栈的”,这提醒我们在编写定时任务时要注意内存泄漏和栈溢出问题。相关问题:1.如何在NestJS中复用Puppeteer的浏览器实例?2.如何避免Puppeteer在高并发场景下的性能问题?3.Puppeteer在NestJS中除了爬虫还能做什么自动化任务?4.如何用Puppeteer进行网页截图并保存到本地或云存储?</think> 在 NestJS 项目中集成和使用 Puppeteer 实现网页抓取或自动化任务,可以按照以下步骤操作: ### 一、安装 Puppeteer 依赖 ```bash npm install puppeteer ``` ### 二、创建 Puppeteer 服务(核心功能封装) ```typescript // src/puppeteer/puppeteer.service.ts import { Injectable } from '@nestjs/common'; import * as puppeteer from 'puppeteer'; @Injectable() export class PuppeteerService { private browser: puppeteer.Browser; // 初始化浏览器实例 async initBrowser() { this.browser = await puppeteer.launch({ headless: true, // 无头模式(生产环境推荐) args: ['--no-sandbox', '--disable-setuid-sandbox'], // Docker 环境必需参数 }); } // 创建新页面 async createPage() { if (!this.browser) await this.initBrowser(); return await this.browser.newPage(); } /** * 网页抓取方法 * @param url 目标网址 * @param waitForSelector 等待元素选择器(可选) */ async scrapePage(url: string, waitForSelector?: string) { const page = await this.createPage(); try { await page.goto(url, { waitUntil: 'networkidle2', timeout: 60000 }); if (waitForSelector) { await page.waitForSelector(waitForSelector, { timeout: 30000 }); } // 获取页面内容 const content = await page.content(); // 获取特定数据(示例) const title = await page.title(); const metaDescription = await page.$eval('meta[name="description"]', el => el.content); return { title, metaDescription, html: content }; } finally { await page.close(); // 确保页面关闭 } } // 关闭浏览器(应用退出时调用) async closeBrowser() { if (this.browser) await this.browser.close(); } } ``` ### 三、在模块中注册服务 ```typescript // src/puppeteer/puppeteer.module.ts import { Module } from '@nestjs/common'; import { PuppeteerService } from './puppeteer.service'; @Module({ providers: [PuppeteerService], exports: [PuppeteerService], // 导出以便其他模块使用 }) export class PuppeteerModule {} // 在AppModule中导入 import { PuppeteerModule } from './puppeteer/puppeteer.module'; @Module({ imports: [PuppeteerModule], // ... }) export class AppModule {} ``` ### 四、在控制器中使用(示例) ```typescript // src/scraper/scraper.controller.ts import { Controller, Get } from '@nestjs/common'; import { PuppeteerService } from '../puppeteer/puppeteer.service'; @Controller('scrape') export class ScraperController { constructor(private readonly puppeteerService: PuppeteerService) {}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值