Rod 一个为简化自动化和爬虫设计的 devtools driver

2020-07-02 19:12:41 +08:00
 ysmood

项目地址: https://github.com/ysmood/rod

这个库的主要原理就是利用浏览器的 devtools 可编程接口来操控浏览器。日常你可以用它自动化一些重复的页面任务,相比油猴子有更多的高级功能和 golang 强大的生态。工作上可以用它辅助集成化测试减少人力消耗。开发上可以用它简化一些传统爬虫需要费很多时间逆向工程的场景。

根目录的 readme 里有常见的问答,以及和 chromedp,puppeteer 等库的比较。

同类的项目有 chromedp,但是其存在架构设计上的问题且更新缓慢,所以我们开发了 rod,感兴趣的朋友请来试试。欢迎对自动化有兴趣的朋友加入到项目中来,这是我们的聊天室: https://discord.gg/PAaMGJw

因为问的人特别多,我们列了个表格用实际可运行的例子帮助大家直观对比 rod 和 chromedp: https://github.com/go-rod/rod/tree/master/lib/examples/compare-chromedp

下面是一个打印 awesome-go 某一类别项目列表的例子:

package main

import (
    "log"

    "github.com/go-rod/rod"
)

func main() {
    // 启动一个浏览器并新建一个页面
    page := rod.New().Connect().Page("https://github.com/avelino/awesome-go")

    // 获取页面里含有 "Selenium and browser control tools" 标题的下方元素
    // 这里我们将获取到 p 标签下方的列表
    section := page.ElementMatches("p", "Selenium and browser control tools").Next()

    // 在列表里获取全部 li 标签
    projects := section.Elements("li")

    for _, project := range projects {
        // 从 li 标签里获取 a 标签
        link := project.Element("a")
        
        // 打印 a 里的文字,a 的链接,以及 li 里的文字
        log.Println(
            link.Text(),
            link.Property("href"),
            project.Text(),
        )
    }
}
12444 次点击
所在节点    Go 编程语言
66 条回复
ysmood
2020-07-08 13:38:45 +08:00
@Jirajine 看场景吧,没有最好的,只有合不合适需求。如果项目复杂或者需要多人合作可能有类型会更方便,我觉得道理和为什么 javascript 的大量开发者转为 typescript 是一样的。

而且写 golang 感觉和写脚本也没太大差别,大部分类型都可以省略。有了 IDE 辅助,反而比脚本语言完成同样的任务花的时间更少,也更少需要去看文档了。
missdeer
2020-07-08 17:37:59 +08:00
@ysmood 不想再多一个聊天软件啊
ysmood
2020-07-08 19:58:40 +08:00
@missdeer 我从来都不安装软件啊,打开页面就能用,discord 的网页版比 tg 的网页版好用太多了。
WilliamYang
2020-07-09 13:05:23 +08:00
关注,对这个项目很有兴趣
ysmood
2020-07-09 20:42:53 +08:00
@WilliamYang 欢迎来提需求或贡献代码~
tinytin
2020-07-10 01:40:32 +08:00
支持👏
ysmood
2020-07-10 13:22:53 +08:00
@tinytin 多谢支持
iyaozhen
2020-07-11 16:25:11 +08:00
关于 selenium 这部分不太同意
“It's slower by design because it encourages the use of hard-coded sleep.”

这个没有哪里说要使用 sleep,自带的就有很多 wait 方法(比如官方例子 https://www.selenium.dev/documentation/en/),虽然没有内置 ajax 请求等待,但扩展一下就行了
而且也支持 headless 模式运行

只是说 selenium 走的 webdriver 这条路子没有 devtools 那么时髦,但事实上两条路都在持续发展

应该说是 selenium 更侧重 web UI 自动化测试
ysmood
2020-07-11 18:54:58 +08:00
@iyaozhen 是的。这段是很早期写的,用词有些过分了。我这就去修改下。我觉的 selenium 主要问题还是它基于 webdriver 协议 https://www.w3.org/TR/webdriver1/。这个协议的主要问题是还太早期,很多功能上的支持和 devtools 协议比起来还是太弱了,我还没研究 webdriver2,说不定会好些。比如你提到的劫持 ajax,webdriver1 根本就不支持,比如你要劫持 https 的请求时,webdriver1 只能借助代理,还要处理一堆证书问题,我恐怕你很难找个现成好用的插件(反正我是没找到 golang 和 java 的,只看到个 python 的 selenium-wire 但它还有限制)。你觉得这说服不了你,那对于 shadow-dom,webdriver1 就根本无法处理了。

如果你看下这个 https://github.com/sukgu/shadow-automation-selenium/issues/7#issuecomment-563062460
你就会知道这是质的差别,selenium 是无法处理 closed shadow root 的,然而 rod 可以。还有很多本质差别,日后有时间我们会尽量列个表出来。
ysmood
2020-07-11 19:19:18 +08:00
@iyaozhen 说白了就是两个协议间的抗衡,目前来看由于 puppeteer 的广泛接受度,以及微软也加入到 chromium 阵营,恐怕留给 webdriver 的时间就不多了。

我刚看了下 webdriver2,比起 1,就加了一点功能而已,还是太鸡肋了。举个简单的例子,你说 selenium 更侧重自动化测试,测试需要 profiling 的时候检测性能的时候,selenium 就得使用及其 hack 的手段了,而且也没发支持 devtools 那样丰富的功能。

总体来说 webdriver 协议理想是非常好的但是相比 devtools 协议的成熟度,还是差太远了。关键是 firefox 都已经意识到这点在与 puppeteer 团队合作开发 devtools 的支持了,可见一斑。我当然是希望能用统一的协议,但现实就是这么骨感。
iyaozhen
2020-07-11 20:23:50 +08:00
@ysmood 嗯 我知道。应该说是 selenium 唯一的优势就是多浏览器支持了,IE 、Safari 。自动化测试还是需要的。但已经很有局限性,优势也越来越不重要了(很多系统都是 chrome only )

webdriver 一直也在更新(也是浏览器厂商支持,chrome 每版都有更新)但确实是昨日黄花了。

还是那句话没有银弹,传统的自动化功能测试(代替手工回归),devtools 没有比 webdriver 明显的优势,有些奇怪的页面还是不稳定。

当然绝大部分场景来说肯定还是首选 devtools,我的意思是可以更客观的对比下场景差异(也不用搞个细节技术点的列表)
ysmood
2020-07-14 00:14:56 +08:00
@iyaozhen 更新了文档,把不正的描述去掉了,欢迎来指点。

关于 chrome only 这个观点,我补充下。随着旧浏览器的淘汰,如今都用 react vue 之类的框架开发网页,跨浏览器支持已经不再是自动化测试的重点了,单测也往往不用 headless 这么重的东西,单测就够了,用了 headless 大概率就是集成测了,集成测试往往目标是冒烟保障,比如监测关键功能是否异常,浏览器兼容性这种细枝末节基本不是瓶颈所在。
iyaozhen
2020-07-14 01:53:00 +08:00
@ysmood 赞 现在描述好很多了

求同存异,大家观点差不多

可惜团队技术栈不是 go,不然可以用用你的。祝项目越来越好
iyaozhen
2020-07-14 01:59:11 +08:00
@ysmood 我擦,说了几天没注意看 ID,学长好
ysmood
2020-07-14 02:11:54 +08:00
@iyaozhen 多谢。世界就是这么小呢。不是 Go 也没事,偶尔尝试下别的东西也不坏。我们 QA 也不会 Go,几天就能自己用 rod 写测试保障功能了。
abc0707
2020-07-24 17:57:49 +08:00
请问 反反爬怎么做

go browser.EachEvent(func(e *proto.TargetTargetCreated) {
// We only want to listen to events which are when a Page is created.
// This filters out all other target types are created, e.g service
// workers, shared workers, and background pages.
fmt.Println(e.TargetInfo.Type)
fmt.Println(proto.TargetTargetInfoTypePage)
if e.TargetInfo.Type != proto.TargetTargetInfoTypePage {
return
}

// We use the ID to obtain the page ourselves to use.
page02 := browser.PageFromTargetID(e.TargetInfo.TargetID)
fmt.Println(page02)
// Log "hey" on each newly created page.
page02.Eval(`Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})`)
})()

按照官网例子还是不行呢
ysmood
2020-07-24 18:25:01 +08:00
@abc0707 朋友我们没有这样的例子,我们的例子是这个啊 https://github.com/go-rod/bypass/blob/master/example/main.go
abc0707
2020-07-24 21:43:30 +08:00
好的 这个是看 issue 里面的 我去试试你说的这个
abc0707
2020-07-24 21:46:37 +08:00
大佬 有没有交流群啊 之前的一个项目加了反爬虫 好多验证 今天刚搜索到这个库感觉还可以
abc0707
2020-07-24 21:51:26 +08:00
bypass.Page 如何设置 .Headless(false) 这个呢

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/686655

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX