登录
  • 人们都希望被别人需要 却往往事与愿违
  • 如果鲁迅活在这个年代: 他的博客首先会被和谐, 然后被请喝茶谈话, 最后以煽动颠覆国家罪被捕入狱...

Go 使用selenium截图

编程 Benny小土豆 4196次浏览 2596字 4个评论
文章目录[显示]

今天想给wayback machine bot增加一个截图的功能,难度不大,用selenium打开浏览器,截图,再发给用户就可以了。

网上随便就可以找到教程,比如说这样

package main

import (
	"fmt"
	log "github.com/sirupsen/logrus"
	"github.com/tebeka/selenium"
	"io/ioutil"
)

const (
	chromeDriverPath = "/usr/local/bin/chromedriver"
	port = 9515
)

func main() {
	var opts []selenium.ServiceOption
	selenium.SetDebug(false)
	service, err := selenium.NewChromeDriverService(chromeDriverPath, port, opts...)
	if err != nil {
		panic(err) // panic is used only as an example and is not otherwise recommended.
	}
	defer service.Stop()

	caps := selenium.Capabilities{"browserName": "chrome"}
	wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port))
	if err != nil {
		panic(err)
	}

	defer wd.Quit()
	if err := wd.Get("https://github.com/tgbot-collection/archiver"); err != nil {
		panic(err)
	}

	screenshot, err := wd.Screenshot()
	if err != nil {
		log.Errorln(err)

	}
	ioutil.WriteFile("screenshot.png", screenshot, 0644)

}

Go 使用selenium截图

但是问题来了,这里的截屏只有当前窗口,怎么把整个页面都截屏了呢?

整页截屏

方法还是有的,一个简单的办法就是获取到网页的宽高,然后把浏览器的窗口设置成这么大,然后再截图就好了!需要注意的是只有headless模式可以任意设置窗口大小,否则最大高度不能超过你的显示器分辨率

设置headless只需要加个参数就好了,如下

caps := selenium.Capabilities{"browserName": "chrome"}
	chromeCaps := chrome.Capabilities{
		Path: "",
		Args: []string{
			"--headless",
		},
	}
	caps.AddChrome(chromeCaps)
	wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port))

获取网课宽高很容易,偷懒的话只要获取网页的高就可以了,宽我们可以固定成固定的像素,比如1920.

在chrome的控制台里,输入这么一串神秘代码可获得网页的高

document.body.parentNode.scrollHeight

在selenium中使用ExecuteScript就可以执行JavaScript代码,需要注意返回值是interface,所以要类型断言成float,然后再转成int

height, _ := wd.ExecuteScript("return document.body.parentNode.scrollHeight", nil)
var realHeight = int(height.(float64))

然后我们需要设置窗口大小

wd.ResizeWindow("", 1920, realHeight)

运行一下看看,果然正确且完美

在服务器中运行

必然这个东西是要在某台服务器中跑起来的,也没什么不同的,下载自己的webdriver,安装浏览器,照样headless启动就好了。应该不会遇到大问题

在容器中运行

理论上来说,在容器中运行和在某个Linux发行版运行是没什么太大差别的。无非就是找到对应的webdriver。比如我经常用的alpine恰巧提供了chrome和chrome-webdriver,并且有amd64和arm64(aarch64)的预编译包

直接运行 apk add chromium-chromedriver 浏览器和webdriver会一起安装好

要注意一件事情,如果你是root用户运行的,那么要加上--no-sandbox 参数

一运行却发现结果不如人意,总是写入0大小的文件,或者报错

Go 使用selenium截图

强行加一行sleep,会有比较大的概率会避免这个问题,但是这不是个办法嘛。

if err := wd.Get("https://www.baidu.com"); err != nil {
	panic(err)
}
time.Sleep(10 * time.Second)

后来搜了一下,是Chrome和 container的兼容性问题,Chrome需要比较大的/dev/shm,然而容器中的/dev/shm往往都比较小,对于Chrome这种内大户来说不太行。

Go 使用selenium截图

解决方法要么就增大容器里的/dev/shm,可以通过run时额外参数--shm-size=256m

Go 使用selenium截图

也可以直接把宿主机的共享进去

docker run --rm -v /dev/shm:/dev/shm -it alpine sh

也可以禁用Chrome的shm功能,加一个参数

"--disable-dev-shm-usage",

还有一种办法,换Firefox也许也有救。

中文乱码

alpine里没带中文字体,所以中文会乱码。可以用alpine自带的一个,这样安装就好,也可以自己偷字体,然后放到/usr/share/fonts/ 就好了

apk add wqy-zenhei --update-cache --repository https://nl.alpinelinux.org/alpine/edge/testing

参考资料

https://stackoverflow.com/a/53970825/10264400

https://github.com/tgbot-collection/archiver/blob/master/screenshot.go


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/go-selenium.html
喜欢 (33)
分享:-)
关于作者:
If you have any further questions, feel free to contact me in English or Chinese.
发表我的评论
取消评论

                     

去你妹的实名制!

  • 昵称 (必填)
  • 邮箱 (必填,不要邮件提醒可以随便写)
  • 网址 (选填)
(4)个小伙伴在吐槽
  1. https://github.com/go-rod/rod 你看看这个包,方便多了
    chengzi2023-03-10 15:17 回复
    • 哇, 好东西啊,确实方便很多!
      Benny小土豆2023-03-10 15:19 回复
  2. wayback machine bot 全是用selenium写的?
    ajenti2022-07-24 00:12 回复
    • Go写的
      --本评论由Telegram Bot回复~❤️
      Benny小土豆2022-07-24 00:18 回复