笔者说:近期在使用golang进行开发工作时,受360技术公众号曾发布过文章的启发,想到是否可以使用golang操作无屏浏览器(headless browser)实现诸如爬虫、截屏、自动化测试等功能。

经过调研和测试,发现golang实现也是很好的一种选择。

背景

360技术公众号曾经发布过一篇文章《服务端浏览器截屏》,文章中对基于Selenium(Python SDK)实现的服务端截屏技术进行了详细讲解,可操作性非常强。

我曾使用Python+Selenium实现过爬虫和简单的自动化测试功能,对上面文章中使用的技术和组件都有涉及,我认为初学者完全可以通过该文章手把手的教学,实现服务端截屏功能。

不过基于Selenium的截图实现存在如下一些缺点:

  • 需要安装Selenium或是PhantomJS

  • PhantomJS已经停止维护了

  • Selenium的运行需要安装chromedriver

  • chromedriver对chrome的版本有一定要求

  • 截图时需要使用html2canvas JS库

可见,整体环境的搭建(包括各个软件之间版本的匹配),还是需要花费不少时间和精力适配并测试的。因此原文章作者在上述文章的最后也提供了“集成Docker”的方案,在上述环境docker化后,可以解决环境部署的问题。

而基于golang实现的方案,可以完美解决上述问题。该方案对运行时环境的要求为仅安装chrome浏览器即可。

无屏浏览器

Headless browser是浏览器的无界面形态,可以在不打开浏览器的前提下,使用所有浏览器支持的特性,例如:获取HTML,执行Javascript,渲染目标网页,获取cookie等。

本文主要使用的是headless chrome,下文提到的“浏览器”均代指headless chrome。

主要框架

为了方便地在golang程序里使用headless chrome,需要借助一些开源框架。实现headless chrome交互的库有很多,笔者经过对比后选择了chromedp。

chromedp的主要特点有:

  • 提供了更快,更简单的方式来驱动浏览器

  • 提供了丰富的底层API接口(基于CDP协议——Chrome Debugging Protocol)

  • 提供了灵活的上层API接口(Actions & Tasks),类似Selenium的WebElement actions

  • 除了浏览器本身,没有任何外部依赖 (如Selenium, PhantomJS等)

  • “一次编译,随处拷贝,到处运行”(基于golang的特性)

实现

安装

go get -u github.com/chromedp/chromedp

截图实现代码

package mainimport ("context""io/ioutil""log"cdp "github.com/chromedp/chromedp"
)func main() {// 创建新的cdp上下文ctx, cancel := cdp.NewContext(context.Background())defer cancel()// 此处以360搜索首页为例urlstr := `https://www.so.com/`var buf []byte// 需要截图的元素,支持CSS selector以及XPath queryselector := `#main`if err := cdp.Run(ctx, elementScreenshot(urlstr, selector, &buf)); err != nil {log.Fatal(err)}// 写入文件if err := ioutil.WriteFile("360_so.png", buf, 0644); err != nil {log.Fatal(err)}
}// 截图方法
func elementScreenshot(urlstr, sel string, res *[]byte) cdp.Tasks {return cdp.Tasks{// 打开url指向的页面cdp.Navigate(urlstr),// 等待待截图的元素渲染完成cdp.WaitVisible(sel, cdp.ByID),// 也可以等待一定的时间//cdp.Sleep(time.Duration(3) * time.Second),// 执行截图cdp.Screenshot(sel, res, cdp.NodeVisible, cdp.ByID),}
}

编译执行后,代码中URL截图的效果如下所示

导出PDF

在该框架下,也可以方便地将URL指向的WEB页面导出为PDF文件(调用浏览器的“打印为PDF功能”),调用如下方法即可:

// 导出指定元素为PDF
func elementPDFPrint(urlstr, sel string, res *[]byte) cdp.Tasks {var err errorreturn cdp.Tasks{cdp.Navigate(urlstr),cdp.Sleep(time.Duration(5) * time.Second),cdp.ActionFunc(func(ctx context.Context) error {// 获取pdf数据*res, _, err = page.PrintToPDF().Do(ctx)if err != nil {return err}return nil}),}
}

以360.cn网址为例,导出的PDF效果如下图所示

使用下述方法可以截取全屏图片

func main() {// 创建新的cdp上下文ctx, cancel := cdp.NewContext(context.Background())defer cancel()// 此处以360官网首页为例urlstr := `https://www.360.cn/`var buf []byte// 获取 png, quality=90if err := cdp.Run(ctx, fullScreenshot(urlstr, 90, &buf)); err != nil {log.Fatal(err)}if err := ioutil.WriteFile("360_cn_full.png", buf, 0644); err != nil {log.Fatal(err)}
}func fullScreenshot(urlstr string, quality int64, res *[]byte) cdp.Tasks {return cdp.Tasks{cdp.Navigate(urlstr),cdp.ActionFunc(func(ctx context.Context) error {_, _, contentSize, err := page.GetLayoutMetrics().Do(ctx)if err != nil {return err}width, height := int64(math.Ceil(contentSize.Width)), int64(math.Ceil(contentSize.Height))err = emulation.SetDeviceMetricsOverride(width, height, 1, false).WithScreenOrientation(&emulation.ScreenOrientation{Type:  emulation.OrientationTypePortraitPrimary,Angle: 0,}).Do(ctx)if err != nil {return err}// 获取全屏截图*res, err = page.CaptureScreenshot().WithQuality(quality).WithClip(&page.Viewport{X:      contentSize.X,Y:      contentSize.Y,Width:  contentSize.Width,Height: contentSize.Height,Scale:  1,}).Do(ctx)if err != nil {return err}return nil}),}
}

以360.cn网址为例,截取全屏图片效果如下图所示

模拟其他设备

chromedp支持对多种设备的模拟(通过修改浏览器User-Agent的方式),如下代码实现了模拟iPhone7的请求:

func main() {// 创建新的cdp上下文ctx, cancel := cdp.NewContext(context.Background())defer cancel()// runvar b []byteif err := cdp.Run(ctx,// 模拟 iPhone 7cdp.Emulate(device.IPhone7landscape),cdp.Navigate(`https://www.whatsmyua.info/`),cdp.CaptureScreenshot(&b),); err != nil {log.Fatal(err)}if err := ioutil.WriteFile("iphone7_ua.png", b, 0644); err != nil {log.Fatal(err)}
}

效果如下

组合操作

chromedp本身提供了Actions和Tasks数据结构,供用户把任意WEB操作动作组合在一起之后执行,具体可以查看github主页examples下面的例子,这里就不再赘述了。

写在最后

使用golang和chromedp框架,借助chrome的CDP接口,可以在headless chrome上实现浏览器的几乎所有操作。

在2.1的例子中,我们使用不到40行代码,就实现了服务端浏览器截屏功能。同时,除了chrome浏览器、golang SDK和chromedp本身的代码之外,没有引用其他代码或工具。

在上述测试结果的基础上,我们可以继续开发:

  • 封装便捷、通用的服务端页面 [截图/PDF导出] 工具,供其他产品项目使用。应用场景:

  • 前端开发了样式美观的图表,需要导出为图片或PDF作为邮件附件发送给用户查看;

  • 定时发送重要指标图表到用户邮箱,无需用户登陆系统查看数据

  • 开发高效的[WEB自动化测试平台],对WEB产品进行自动化测试。应用场景:

  • 线上环境升级后,自动运行测试用例,测试重点功能(登录,添加、查看测试数据,检查接口返回数据等)

奇麟大数据,360大数据分舵,专注于大数据领域的技术、实践、运维、产品和数据使用方面的分享和交流

想要了解大数据方面知识的初学者,深入技术的研发或运维大神,寻找技术解决方案的传统企业主均可食用

快来留言板交流吧

点击阅读原文,关注奇麟大数据


往期精彩回顾

2019年度精选文章

360技术中台招聘啦!!

为什么我们要从MySQL迁移到TiDB?


360技术公众号

技术干货|一手资讯|精彩活动

扫码关注我们

golong实现服务端浏览器截屏相关推荐

  1. js截屏代码_服务端浏览器截屏

    服务端浏览器截屏是结合 selenium + html2canvas 实现的通过在 Chrome 环境下生成图片. selenium是最广泛使用的开源Web UI自动化测试套件之一.本文中使用sele ...

  2. golang实现服务端浏览器截屏

    " 每天,探索一点点." 笔者近期在使用golang进行开发工作时,受360技术公众号曾发布过文章的启发,想到是否可以使用golang操作无屏浏览器(headless browse ...

  3. Chrome浏览器截屏插件的开发

    目 录 第一章 绪论 1 1.1选题背景及意义 1 1.2发展现状研究 2 1.2.1浏览器简介 2 1.2.2 浏览器发展历程 2 1.2.3 浏览器分类 3 1.2.4 chrome浏览器简介 3 ...

  4. 运用插件html2canvas浏览器截屏的方法

    运用插件html2canvas浏览器截屏的方法 首先先安装 html2canvas 插件 toIMage() {// 获取dom元素let canvasBox = this.imageToFileRe ...

  5. Python+Selenium_UI自动化操作(5)——浏览器截屏

    UI自动化--浏览器截屏 练习: 用chrome浏览器打开不同的网页,并截屏. 语法: get_screenshot_as_file("图片名.格式") 数据准备: 将网页的域名w ...

  6. chrome 浏览器截屏

    文章目录 文章参考 问题描述 使用步骤 文章参考 chrome浏览器怎么截图 chrome截屏快捷键 问题描述 在浏览器中写了一个demo ,内容非常的多,出现了纵向滚动条,想要截屏,发现之前的滚动截 ...

  7. uniapp安卓端禁止截屏允许截屏

    方法一: 设置禁止截屏,可以放在App.vue onLaunch中. let activity = plus.android.runtimeMainActivity(); plus.android.i ...

  8. 【日常】edge和chrome浏览器截屏工具快捷键

    首先打开开发者工具 使用右键===>检查 就能打开开发者模式 在开发者模式下,快捷键ctrl+shift + p 然后输入截屏,就能看到了

  9. selenium-java之浏览器截屏

    一,全面截屏 driver 强制转成TakesScreenshot这个接口 File src=((TakesScreenshot)driver).getScreenshotAs(OutputType. ...

最新文章

  1. 筛选法求N以内的所有素数
  2. 华为AI再进化,CANN 3.0释放「算力狂魔」
  3. :src 三目运算
  4. DataTable某一列的值转化成集合
  5. 一文详解DeepMind最新模型SUNDAE,了解迭代去噪模型的前世今生
  6. MySQL字符串长度
  7. seo全攻略_SaaS 企业推广获客全攻略(2):如何做好企业官网?
  8. LIDAR in Google Earth
  9. R数据分析:论文中的轨迹的做法,潜增长模型和增长混合模型
  10. 微信看一看+视频下载方法
  11. coursera “the media could not be loaded either because the server or network falled...“解决办法
  12. 基于Java的亚马逊“手机”评论爬虫的情感分类分析
  13. JUC下的CountDownLatch,CyclicBarrier、Semaphore的使用方法
  14. PyQt5 自定义颜色、形状粗细、虚线等组合下拉框
  15. 今日头条——青龙羊毛
  16. jquery实现下拉框
  17. 二级python多少分过关_计算机等级考试的合格分数是多少_高职招生网
  18. 建设网络强国,迎接Linux曙光
  19. log4j发送日志邮件
  20. 图解HTTP笔记第二章

热门文章

  1. 基于在STM32下完成FreeRTOS的多任务程序开发,多任务串口以及AHT20封装库,原理图,PCB图以及AHT20(实际用到的是LMT70)及采集一次温度数据的模块实战
  2. R语言glm.nb函数构建负二项分布回归模型、epiDisplay包的poisgof函数对拟合的负二项分布回归模型进行拟合优度检验、即模型拟合的效果、验证模型是否有过度离散overdispersion
  3. 微信access_token如何保存
  4. ctfshow-misc-WP
  5. 网站丨别再说你找不到好用的工具了
  6. tf.strided_slice函数(类似K.shape(feats)[1:3])
  7. Android集成微信分享,由于分享的缩略图大于32K,而无法调起微信客户端
  8. c语言中字符型常量在内存中存放的是,【2017年整理】c语言中字符型常量与变量使用注意事项.doc...
  9. python-TGI指数分析实战
  10. 2023年深圳杯A题完整版论文