C#使用Puppeteer

news2024/11/14 20:43:43

Puppeteer

Puppeteer是一个Node.js库,它提供了高级API来通过DevTools协议(Chrome DevTools Protocol https://devtools.chrome.com)控制Chrome或Chromium。 Puppeteer默认情况下无头运行(headless)。

可以配置为运行完整的Chrome或Chromium,运行效果如下

Puppeteer具备以下功能:

1、页面截图和生成PDF

2、抓取动态网页内容

3、自动化表单提交,UI测试,键盘输入等

4、测试Chrome扩展程序

Puppeteer项目地址:

GitHub - puppeteer/puppeteer: JavaScript API for Chrome and Firefox

在C#中调用,是使用了Puppeteer的移植版本,puppeteer-sharp,项目地址:

GitHub - hardkoded/puppeteer-sharp: Headless Chrome .NET API

Puppeteer-sharp是基于.Net Standard 2.0开发,所以可以运行于NET Framework 4.6.1+、 .NET Core 2.0+的版本上.

操作系统的要求是Windows 8+或Windows Server2012+。如果需要在Windows 7上运行Puppeteer-Sharp,则可以通过设置LaunchOptions.WebSocketFactory属性的值为System.Net.WebSockets.Client.Managed来实现。

对于前端开发人员来说,Puppeteer最大的用处应该就是自动化测试,而对于爬虫开发人员,Puppeteer最大的用处是可以很方便的抓取动态网页。Puppeteer就等于是一个人为操作的浏览器,你可以控制它抓取任何动态网页内容。

对比CEF

在前面的文章中,我使用了CEFSharp嵌入到界面中,来进行了动态页面的抓取(https://www.cnblogs.com/zhaotianff/p/9556270.html),

使用Puppeteer也可以达到同样的效果,但它用起来会更加方便, 因为它能以headless方式运行,不用显示在界面上。而且它封装了很多方便开发人员使用的函数。

本质 上来说,Puppeteer是通过Chrome DevTools Protocol来控制Chromium浏览器,而CEF提供了Chromium浏览器本身,它是一个Web Browser控件。

抓取动态页面

1 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
2 var browser = await Puppeteer.LaunchAsync(new LaunchOptions
3             {
4                 Headless = true
5             });
6 var page = await browser.NewPageAsync();
7 await page.GoToAsync("https://www.baidu.com");
8 var html = await page.GetContentAsync();

网页截图

 1   await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
 2   browser = await Puppeteer.LaunchAsync(new LaunchOptions
 3   {
 4                  Headless = true
 5   });
 6   var page = await browser.NewPageAsync();  //打开一个新标签
 7   await page.GoToAsync("https://www.baidu.com"); //访问页面
 8  
 9   
10  //设置截图选项
11  ScreenshotOptions screenshotOptions = new ScreenshotOptions();
12  //screenshotOptions.Clip = new PuppeteerSharp.Media.Clip() { Height = 0, Width = 0, X = 0, Y = 0 };//设置截剪区域
13  screenshotOptions.FullPage = true; //是否截取整个页面
14  screenshotOptions.OmitBackground = false;//是否使用透明背景,而不是默认白色背景
15  screenshotOptions.Quality = 100; //截图质量 0-100(png不可用)
16  screenshotOptions.Type = ScreenshotType.Jpeg; //截图格式
17 
18  await page.ScreenshotAsync("D:\\a.jpg",screenshotOptions);

截图效果如下:

保存网页为PDF

 1 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
 2  browser = await Puppeteer.LaunchAsync(new LaunchOptions
 3  {
 4                   Headless = true
 5  });
 6 var page = await browser.NewPageAsync();  //打开一个新标签
 7 await page.GoToAsync("https://www.baidu.com"); //访问页面
 8 
 9 //设置PDF选项
10 PdfOptions pdfOptions = new PdfOptions();
11 pdfOptions.DisplayHeaderFooter = false; //是否显示页眉页脚
12 pdfOptions.FooterTemplate = "";   //页脚文本
13 pdfOptions.Format = new PuppeteerSharp.Media.PaperFormat(8.27m,11.69m);  //pdf纸张格式 英寸为单位 
14 pdfOptions.HeaderTemplate = "";   //页眉文本
15 pdfOptions.Landscape = false;     //纸张方向 false-垂直 true-水平 
16 pdfOptions.MarginOptions = new PuppeteerSharp.Media.MarginOptions() { Bottom = "0px", Left = "0px", Right = "0px", Top = "0px" }; //纸张边距,需要设置带单位的值,默认值是None
17 pdfOptions.Scale = 1m;            //PDF缩放,从0-1
18 await page.PdfAsync(path, pdfOptions);

保存出来的PDF效果并不怎么好,应该是文档宽高没控制好的原因。

重要说明:

Puppeteer需要先下载Chromium浏览器的相关文件,也就是下面这句代码执行的操作

1 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);

可能会出现下载失败的情况,如下图:

 可以从这里下载 ,并解压到程序运行目录。(推荐这种方式,因为出现了上面的异常,第二种方式中的链接你也访问不了

也可以通过以下方式:

访问google chromium开源镜像网站,下载Chromium浏览器

https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Win_x64/

下载后解压到相应位置,然后通过指定Chromium路径来进行初始化

 1 LaunchOptions options = new LaunchOptions();
 2 options.Headless = true;
 3 options.DefaultViewport = null;
 4 //忽略证书错误
 5 options.IgnoreHTTPSErrors = true;
 6 
 7 //chromePath就是下载的Chromium浏览器解压的位置
11 options.ExecutablePath = chromePath;
12 
13 browser = await Puppeteer.LaunchAsync(options);

本文示例代码

GitHub - zhaotianff/PuppeteerDemo: 博客园Puppeteer-Sharp使用示例代码

如果在使用过程中,遇到了问题,可以提个issue给我。

更加详细的Puppeteer使用教程以及爬虫相关知识,可以访问我的github

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1996871.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【中项】系统集成项目管理工程师-第11章 项目范围管理-11.2收集需求

前言:系统集成项目管理工程师专业,现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试,全称为“全国计算机与软件专业技术资格(水平)考试”&…

开源AI搜索平台Search4All

什么是 Search4All ? Search4All 是个人 AI 搜索协助工具,是 Perplexity 的开源替代品。能让你的 LLM API 支持联网,搜索、新闻、网页总结, 软件特点: 集成对 LLM 的支持,例如 OpenAI、Groq 和 Claude。本…

【学习笔记】Day 8

写在开头: 最近老板突然提出一个全新的组会主题,是关于 “最近我犯的傻”,其目的在于提供乐子的同时引以为戒。本来我还在愁到底去哪里找干的啥事儿,结果今天直接拉了个大的。什么叫无心插柳柳成荫啊,悲。 一…

亿达科创亮相智造数字科技大会

8月8日,IMC2024第七届智造数字科技大会在京启幕。大会以“乘‘数’而上”为题,邀请300智能制造行业数字化转型技术大咖、领军者及实践者共聚一堂,解读智造行业转型进程。亿达科创受邀参会,分享企业前沿数字技术、解决方案与创新实…

Java面试篇(线程池相关专题)

文章目录 1. 为什么要使用线程池2. 线程池的核心参数和线程池的执行原理2.1 线程池的核心参数2.2 线程池的执行原理 3. 线程池中常见的阻塞队列3.1 常见的阻塞队列3.2 ArrayBlockingQueue 和 LinkedBlockingQueue 的区别 4. 如何确定线程池的核心线程数4.1 应用程序中任务的类型…

开源AI智能名片小程序在私域流量运营中的“及时法则”深度应用与策略探讨

摘要:在数字化浪潮的推动下,私域流量已成为企业构建长期竞争优势的关键要素。开源AI智能名片小程序,凭借其智能化、个性化及高度可定制化的特性,正逐步成为私域流量运营的重要工具。本文深入探讨了“及时法则”在开源AI智能名片小…

模型量化——NVIDIA——QAT

概述 QAT 截止目前(20230418)的CUDA 实现并不在pytorch 原生包中(不等同于pytorch 的QAT,它主要支持CPU),需要引入NVIDIA 的第三方包“pytorch-quantization”。需要TRT8+ 、 pytorch 1.8 +。主要流程如下: 工具流转方向如下: 所以目前我的理解+咨询了NVIDIA官…

【代码随想录】螺旋矩阵II

本博文为代码随想录的学习笔记,原文链接:代码随想录 题目 原题链接:59. 螺旋矩阵 II 给你一个正整数 n ,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xf…

【Linux】lvm被删除或者lvm丢失了怎么办

模拟案例 接下来模拟lvm误删除如何恢复的案例: 模拟删除: 查看vg名: vgdisplayvgcfgrestore --list uniontechos #查看之前的操作 例如我删除的,现场没有删除就用最近的操作文件: 还原: vgcfgrestore…

1Panel应用推荐:KubePi开源Kubernetes管理面板

1Panel(github.com/1Panel-dev/1Panel)是一款现代化、开源的Linux服务器运维管理面板,它致力于通过开源的方式,帮助用户简化建站与运维管理流程。为了方便广大用户快捷安装部署相关软件应用,1Panel特别开通应用商店&am…

扩展02:Haporxy+Keepalived+Mysql高可用集群实战

由于这个架构和扩展01的大致步骤都相同,就不讲解了。看如下图再参考扩展01即可。

用C语言实现链式存储结构 万字

各位同学,大家好,我叫小敖。今天给大家分享数据结构之一链式存储结构,下面是对链表简单介绍,希望大家能理解。 链表介绍 链表是一种物理存储单元上非连续、非顺序的存储结构**,数据元素的逻辑顺序是通过链表中的指针链…

大模型快速部署,以浪潮源2.0为例

step1: 申请PAI-DSW试用 step2:魔塔社区授权 由于本地授权一直失败,于是采用了魔塔免费平台实例进行学习。 搭建好之后,打开就有相关页面了: demo搭建: 按照官方提示的步骤进行搭建,内容如下:…

第二十一节、敌人追击状态的转换

一、物理检测中的Boxcast 1、检测敌人Bool 当不知道一个函数的返回值是什么的时候 定义一个var变量 就知道了 二、状态切换 1、switch用法 2、新的语法糖写法

ubuntu2004上的glib编译教程

最近因为工作需要编译glib,写文章记录一下编译流程。 从launchpad上下载源码:链接 根据control文件的提示安装对应的依赖 然后尝试debuild,这里会编译不过出去,不过debuild会自动生成一些编译文件,不要删除。 接下来…

2024云南导游资格证题库

1、释迦三圣是( )。 A、药师佛 B、文殊菩萨 C、释迦牟尼 D、普贤菩萨 E、观音菩萨 答案:BCD 2、下列女士套裙穿法中,错误的是( )。 A、上衣的袖长不超过着装者的手腕,裙子不盖过脚踝 B、女士在正式场合穿…

八、MyBatis

一、MyBatis介绍 MyBatis 是持久层框架,它支持自定义 SQL、存储过程以及⾼级映射。MyBatis 去除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置 和映射原始类型、接口和 Java POJO(Plain Old Java Obj…

数据结构--第七天

递归 -递归的概念 递归其实就是一种解决问题的办法,在C语言中:递归就是函数自己调用自己 -递归的思想 递归的思考方式就是把大事化小的过程 递归的递就是递推的意思,归就是回归的意思 (递归是少量的代码完成大量的运算&#xff09…

数据结构(5.5_2)——并查集

逻辑结构——数据元素之间的逻辑关系 并查集: 并查集(Union-Find)是一种树型的数据结构,用于处理一些不交集的合并及查询问题。它支持两种操作: 用双亲表示存储并查集 首先将所有根节点数组值设为-1,其…

[Android] [解决]Bottom Navigation Views Activity工程带来的fragment底部遮盖的问题

创建了Bottom Navigation Views Activity之后,在fragment_home.xml,加了一个RecyclerView, 后来添加了item之后发现底部会被盖住一部分。 解决:在layout里面加两句: android:paddingBottom"?attr/actionBarSize&…