技能树升级Chrome Headless 模式 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Get Google Chrome
Vimium 在 Chrome 里使用 vim 快捷键
yesvods
V2EX    Chrome

技能树升级Chrome Headless 模式

  •  
  •   yesvods 2017-04-15 01:41:43 +08:00 3856 次点击
    这是一个创建于 3181 天前的主题,其中的信息可能已经有所发展或是发生改变。

    作者: Jogis

    原文链接: https://github.com/yesvods/Blog/issues/10

    也许最近已经听说 Chrome59 将支持headless模式,PhantomJS核心开发者Vitaly表示自己将会失业了。

    Headless 模式解决了什么问题

    3 年前,无头浏览器PhantomJS已经如火如荼出现了,紧跟着NightmareJS也成为一名巨星。无头浏览器带来巨大便利性:页面爬虫、自动化测试、 WebAutomation...

    为啥 Chrome 又插了一脚

    用过 PhantomJS 的都知道,它的环境是运行在一个封闭的沙盒里面,在环境内外完全不可通信,包括 API 、变量、全局方法调用等。一个之前写的微信页面爬虫,实现内外通信的方式极其 Hack ,为了达到目的,不择手段,令人发指,看过的哥们都会蛋疼。

    So, 很自然的, Chrome59 版支持的特性,全部可以利用,简直不要太爽:

    • ES2017
    • ServiceWork(PWA 测试随便耍)
    • 无沙盒环境
    • 无痛通讯&API 调用
    • 无与伦比的速度
    • ...

    技能树启动点

    为了点亮技能树,我们需要以下配置:

    大致来说,有那么个过程:

    启动 Headless 模式

    有各种脚本启动方式,本次我们使用 termial 参数方式来打开:

    $ /Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --headless --remote-debugging-port=9222 

    在 Dock 中,一个黄色的东西就会被启动,但是他不会跳出来。

    操控无头浏览器

    依旧有各种方式,我们先安装一个工具帮助我们来对黄色浏览器做点事情:

    $ tnpm i -S chrome-remote-interface 

    燥起来

    捕获所有请求

    Pretty Simple ,写一个 index.js :

    const CDP = require("chrome-remote-interface"); CDP(client => { // extract domains const { Network, Page } = client; // setup handlers Network.requestWillBeSent(params => { console.log(params.request.url); }); Page.loadEventFired(() => { client.close(); }); // enable events then start! Promise.all([Network.enable(), Page.enable()]) .then(() => { return Page.navigate({ url: "https://github.com" }); }) .catch(err => { console.error(err); client.close(); }); }).on("error", err => { // cannot connect to the remote endpoint console.error(err); }); 

    AND run it :

    $ node index.js 

    结果会展示一堆 url :

    https://github.com/ https://assets-cdn.github.com/assets/frameworks-12d63ce1986bd7fdb5a3f4d944c920cfb75982c70bc7f75672f75dc7b0a5d7c3.css https://assets-cdn.github.com/assets/github-2826bd4c6eb7572d3a3e9774d7efe010d8de09ea7e2a559fa4019baeacf43f83.css https://assets-cdn.github.com/assets/site-f4fa6ace91e5f0fabb47e8405e5ecf6a9815949cd3958338f6578e626cd443d7.css https://assets-cdn.github.com/images/modules/site/home-illo-conversation.svg https://assets-cdn.github.com/images/modules/site/home-illo-chaos.svg https://assets-cdn.github.com/images/modules/site/home-illo-business.svg https://assets-cdn.github.com/images/modules/site/integrators/slackhq.png https://assets-cdn.github.com/images/modules/site/integrators/zenhubio.png https://assets-cdn.github.com/assets/compat-8a4318ffea09a0cdb8214b76cf2926b9f6a0ced318a317bed419db19214c690d.js https://assets-cdn.github.com/static/fonts/roboto/roboto-medium.woff ... 

    捕获 DOM 内所有图片

    这次轮到演示一下如何操控 DOM :

    const CDP = require("chrome-remote-interface"); CDP(chrome => { chrome.Page .enable() .then(() => { return chrome.Page.navigate({ url: "https://github.com" }); }) .then(() => { chrome.DOM.getDocument((error, params) => { if (error) { console.error(params); return; } const optiOns= { nodeId: params.root.nodeId, selector: "img" }; chrome.DOM.querySelectorAll(options, (error, params) => { if (error) { console.error(params); return; } params.nodeIds.forEach(nodeId => { const optiOns= { nodeId: nodeId }; chrome.DOM.getAttributes(options, (error, params) => { if (error) { console.error(params); return; } console.log(params.attributes); }); }); }); }); }); }).on("error", err => { console.error(err); }); 

    最后会返回数组,看起来像酱紫:

    [ [ 'src', 'https://assets-cdn.github.com/images/modules/site/home-illo-conversation.svg', 'alt', '', 'width', '360', 'class', 'd-block width-fit mx-auto' ] [ 'src', 'https://assets-cdn.github.com/images/modules/site/home-illo-chaos.svg', 'alt', '', 'class', 'd-block width-fit mx-auto' ] [ 'src', 'https://assets-cdn.github.com/images/modules/site/home-illo-business.svg', 'alt', '', 'class', 'd-block width-fit mx-auto mb-4' ] ... ] 

    chrome-remote-interface 提供一套完整的 API 用于利用全量 Chrome 特性,更多使用方法参考: https://github.com/cyrus-and/chrome-remote-interface

    总结

    Chrome Headless 特性,不仅仅革新了原有格局,而且提高开发效率,降低使用门槛,对于经常使用爬虫、自动化测试前端童鞋来说简直是巨大福音,对于新童鞋来说也是一个新潮的玩具。

    3 条回复    2017-04-15 12:15:20 +08:00
    HaEx
        1
    HaEx  
       2017-04-15 03:13:44 +08:00
    tnpm -> cnpm ,同时后面的链接仅供内部访问
    binux
        2
    binux  
       2017-04-15 04:19:02 +08:00 via Android
    其实并不是什么新鲜玩意, chrome webview 的 headless 通过 electron 很早就实现了。

    这东西直接用还太早,生产中还需要一层封装。
    而且 debugger API 可靠性还没准,但是就 chrome 来说,分分钟搞死一个标签页的方法不计其数,那时候 debugger 是否还活着真不好说。最后还是需要进程级别的控制的
    iyaozhen
        3
    iyaozhen  
       2017-04-15 12:15:20 +08:00 via Android
    额,还是不太明白,这个优势在哪儿了?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5614 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 57ms UTC 03:10 PVG 11:10 LAX 19:10 JFK 22:10
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86