【Chrome】使用k8s、docker部署无头浏览器Headless,Java调用示例

什么是无头浏览器?

无头浏览器是一种没有图形用户界面的浏览器。无头浏览器不通过其图形用户界面(GUI)控制浏览器的操作,而是使用命令行。

为什么要用Chrome无头?

  • Chrome Headless用于抓取(谷歌)、测试(开发者)和黑客(黑客)。
  • 搜索引擎,使用它来呈现页面、生成动态内容和索引来自单页Web应用程序的数据。
  • SEO工具,用来分析网站,提出如何改进的建议。
  • 监控工具,用于监控Web应用中JavaScript的执行时间。
  • 一个测试工具,用于呈现页面并将其与以前的版本进行比较,以跟踪用户界面的变化。
  • 使用Headless Chrome的主要优势在于,用户可以编写脚本以编程方式运行浏览器,并快速、大规模地执行抓取、分析或成像网站等任务,而无需打开浏览器的GUI并点击一百万个东西。
  • 要做到这一点需要三样东西:无头Chrome、DevTools协议和木偶师。
  • 你已经见过Chrome Headless了。Dev Protocol是Chrome DevTools的远程实例,在另一个浏览器中打开。它允许你“通过你的眼睛”看到无头Chrome,而不需要运行浏览器GUI。Puppeteer是一个节点库,它为开发者提供了通过DevTools协议编程控制无头Chrome的工具。
  • 把三者结合起来,就可以用Headless Chrome编写重复的大规模动作脚本,并快速大规模运行。

    安装chrome浏览器并测试

    基本上每个程序员都会安装chrome浏览器,如果没有安装的可以去下载安装,安装好之后,可以直接利用chrome浏览器执行无头浏览器的命令,假设chrome浏览器安装路径是: C:\Users\administrator\AppData\Local\Google\Chrome\Application\chrome.exe,可以执行如下命令

    C:\Users\best5\AppData\Local\Google\Chrome\Application\chrome.exe --headless --hide-scrollbars --disable-gpu --screenshot=e:\chrome.jpg  --window-size=1280,1696 https://www.baidu.com
    

    会生成一个chrome.jpg文件

    Docker运行

    • 拉取镜像: docker pull browserless/chrome:latest
    • 运行容器: docker run -p 3000:3000 browserless/chrome:latest
    • 使用浏览器访问: http://localhost:3000/

      看起来很厉害的样子

      k8s部署

      • 编写部署ymal文件,并命名browserless-chrome.yaml
        ---
        apiVersion: v1
        kind: Service
        metadata:
          name: browserless-chrome
          namespace: kube-public
          labels:
            app: browserless-chrome
        spec:
          type: NodePort
          ports:
            - name: websocket
              port: 30000
              targetPort: 3000
              nodePort: 30000
          selector:
            app: browserless-chrome
        ---
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: browserless-chrome
          namespace: kube-public
        spec:
          replicas: 1
          revisionHistoryLimit: 0 #Replica Sets中的历史数量
          selector:
            matchLabels:
              app: browserless-chrome
          template:
            metadata:
              labels:
                app: browserless-chrome
            spec:
              containers:
                - name: browserless-chrome
                  imagePullPolicy: Always
                  image: browserless/chrome:latest
                  env:
                    - name: PORT
                      value: "3000"
                  securityContext:
                    runAsNonRoot: true
                    runAsUser: 999
                    runAsGroup: 999
                  ports:
                    - containerPort: 3000
                  livenessProbe:
                    tcpSocket:
                      port: 3000
                    initialDelaySeconds: 5
                    failureThreshold: 2
                    periodSeconds: 60
                  readinessProbe:
                    tcpSocket:
                      port: 3000
                    initialDelaySeconds: 5
                    periodSeconds: 10
                  startupProbe:
                    tcpSocket:
                      port: 3000
                    failureThreshold: 30
                    periodSeconds: 10
                  resources:
                    requests:
                      cpu: 0.2
                      memory: 300Mi
                    limits:
                      cpu: 1
                      memory: 1Gi
              imagePullSecrets:
                - name: puller
        
        • kubectl apply -f browserless-chrome.yaml

          把镜像推送到私有仓库

          • 给镜像重新打标签: docker tag browserless/chrome:latest xxx.cn/base/browserless-chrome:latest
          • 推送到私有仓库: docker push imgsreg.ipipa.cn:20443/base/browserless-chrome:latest

            Java调用示例

            • 在pom.xml中添加以下依赖
               io.github.fanyong920 jvppeteer 1.1.5
              • 使用本地chrome程序调用示例代码
                public class BrowserTest { @SneakyThrows
                    @Test
                    void test() { //自动下载,第一次下载后不会再下载
                //        BrowserFetcher.downloadIfNotExist(null);
                        ArrayList arrayList = new ArrayList<>();
                        //生成pdf必须在无头模式下才能生效
                        LaunchOptions options = new LaunchOptionsBuilder()
                                .withExecutablePath("C:\\Users\\administrator\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe")
                                .withArgs(arrayList)
                                .withHeadless(true)
                                .build();
                        arrayList.add("--no-sandbox");
                        arrayList.add("--disable-setuid-sandbox");
                        Browser browser = Puppeteer.launch(options);
                        Page page = browser.newPage();
                        page.goTo("https://www.baidu.com");
                        PDFOptions pdfOptions = new PDFOptions();
                        pdfOptions.setPath("test.pdf");
                        page.pdf(pdfOptions);
                        page.close();
                        browser.close();
                    }
                }
                
                • 使用wetsocket远程调用chrome示例代码
                  public class BrowserTest { @SneakyThrows
                      @Test
                      void test() { //自动下载,第一次下载后不会再下载
                  //        BrowserFetcher.downloadIfNotExist(null);
                          ArrayList arrayList = new ArrayList<>();
                          //生成pdf必须在无头模式下才能生效
                          LaunchOptions options = new LaunchOptionsBuilder()
                                  .withArgs(arrayList)
                                  .withHeadless(true)
                                  .build();
                          arrayList.add("--no-sandbox");
                          arrayList.add("--disable-setuid-sandbox");
                          Browser browser = Puppeteer.connect(options, "ws://localhost:3000", null, null);
                          Page page = browser.newPage();
                          page.goTo("https://www.baidu.com");
                          PDFOptions pdfOptions = new PDFOptions();
                          pdfOptions.setPath("test.pdf");
                          page.pdf(pdfOptions);
                          page.close();
                          browser.close();
                      }
                  }
                  

                  在工程目录下会生成test.pdf文件,可以打开看看效果