2017年网页抓取:先进的Headless Chrome技巧

2023-10-13 04:40

本文主要是介绍2017年网页抓取:先进的Headless Chrome技巧,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文:Web Scraping in 2017: Advanced Headless Chrome Tips & Tricks
作者: Martin Tapia
翻译:不二

Headless Chrome是Chrome 浏览器的无界面形态,可以在不打开浏览器的前提下,使用所有 Chrome 支持的特性运行程序。相比于现代浏览器,Headless Chrome 更加方便测试web应用,获得网站的截图,做爬虫抓取信息等,也更加贴近浏览器环境。下面看看作者分享的使用Headless Chrome进行网页抓取的经验。

PhantomJS的研发已经停止,而Headless Chrome成了热门关注的焦点,大家都很喜欢它,包括我们。在Phantombuster公司,网页抓取是我们工作的很大一部分,现在我们广泛使用Headless Chrome。

这篇文章,将告诉你如何快速入门Headless Chrome生态系统,并展示从已经抓取数百万网页中学到的经验。

文章摘要:
1. 有很多库可以控制Chrome,可以根据自己的喜欢选择。
2. 使用Headless Chrome进行网页抓取非常简单,掌握下面的技巧之后更是如此。
3. Headless浏览器访客可以被检测到,但没人这么做。

Headless Chrome简述

Headless Chrome基于PhantomJS(QtWebKit内核)由谷歌Chrome团队开发。团队表示将专注研发这个项目,未来也会不断维护它。

这意味着对于网页抓取和自动化的需求,现在可以体会Chrome的速度和功能,因为它具备世界上使用最多的浏览器的特性:支持所有网站,支持JS引擎,还有伟大的开发者工具API。太可怕啦!

选用哪个工具控制Headless Chrome?


image

市面上确实有很多NodeJS库来支持Chrome新版headless模式,每一个都各有特色,我们自己的一款是NickJS。倘若没有自己的抓取库,怎么敢轻易的说自己是网页抓取专家。

还有一套C++ API和社区用其他语言发布的库,比如说基于GO语言。我们推荐使用NodeJS工具,因为它和网页解析语言一样(下面你会看到它有多便利)。

网页抓取?它不是非法的吗?

我们无意挑起无休止的争论,但不到两周前,美国一名地方法官下令允许第三方抓取领英(LinkedIn)公众档案。目前为止这只是初步的法令,诉讼仍会继续进行,领英肯定会反对,但尽管放心,我们会密切关注情况,因为这篇文章里谈论了很多关于领英的内容。

无论如何作为一篇技术性的文章,我们不会深入探究特定的抓取操作的合法性问题,我们应该始终努力去尊重目标网站的ToS。而对你在这篇文章中所学到的造成任何损害概不负责。

目前为止学到的很酷的东西

下面列出的一些技巧,我们每天几乎都在使用。代码示例采用NickJS抓取库,但它们很容易被其他Headless Chrome工具改写,重要的是分享概念。

把cookies放回cookie jar

使用功能齐全的浏览器抓取会让人安心,无需担心CORS、会话、cookie、CSRF和其他web问题。

但有时登录表单变得非常强硬,唯一的解决方案是恢复以前保存的会话cookie。当察觉故障时,有些网站会发送电子邮件或短信。我们就没有时间这么做,只是使用已设置好的会话cookie打开页面。

领英有一个很好的例子,设置li_atcookie能保证抓取机器访问他们的社交网络(请记住:注意尊重目标网站Tos)。

await nick.setCookie({name: "li_at",value: "a session cookie value copied from your DevTools",domain: "www.linkedin.com"
})

相信像领英这样的网站不会用一个有效的会话cookie来阻止一个真实的浏览器访问。这么做相当有风险,因为错误的信息会引发愤怒用户的大量支持请求。

jQuery不会让你失望

我们学到了一件重要的事,那就是通过jQuery从网页提取数据真是太容易了。现在回想起来,这是显而易见的。网站提供了一个高度结构化的、可查询的、包含数据元素的树(它被称为DOM),而jQuery是非常高效的DOM查询库。所以为什么不用它来抓取呢?这个技巧会屡试不爽。

很多网站都已经使用了jQuery,所以只需在页面中添加几行就可以得到数据。

await tab.open("news.ycombinator.com")
await tab.untilVisible("#hnmain") // Make sure we have loaded the page
await tab.inject("https://code.jquery.com/jquery-3.2.1.min.js") // We're going to use jQuery to scrape
const hackerNewsLinks = await tab.evaluate((arg, callback) => {// Here we're in the page context. It's like being in your browser's inspector toolconst data = []$(".athing").each((index, element) => {data.push({title: $(element).find(".storylink").text(),url: $(element).find(".storylink").attr("href")})})callback(null, data)
})
印度、俄罗斯和巴基斯坦屏蔽机器人的做法有什么共同之处?


image

答案就是利用验证码解决服务器验证。你可以几美元买到上千个验证码,通常产生验证码不到30秒。但晚上的时候,因为没有人,所以一般比较贵。

一个简单的谷歌搜索将提供多个api来解决任何类型的验证码问题,包括获取谷歌最新的recaptcha验证码(2美元1000个)。

将抓取机器连接到这些服务就如发出HTTP请求一样简单,现在机器人是人类了。

在我们的平台上,用户很容易解决他们需要的验证码问题。我们的巴斯特图书馆可以调用多个解决服务器验证:

if (await tab.isVisible(".captchaImage")) {// Get the URL of the generated CAPTCHA image// Note that we could also get its base64-encoded value and solve it tooconst captchaImageLink = await tab.evaluate((arg, callback) => {callback(null, $(".captchaImage").attr("src"))})// Make a call to a CAPTCHA solving serviceconst captchaAnswer = await buster.solveCaptchaImage(captchaImageLink)// Fill the form with our solutionawait tab.fill(".captchaForm", { "captcha-answer": captchaAnswer }, { submit: true })
}
等待的是DOM元素,而不是固定的时间

经常看到抓取初学者让他们的机器人在打开一个页面或点击一个按钮后等待5到10秒——他们想要确定他们所做的动作有时间产生效果。

但这不是应该做的。我们的3步理论适用于任何抓取场景:应该等待的是想要操作的特定DOM元素。它更快、更清晰,如果出了问题,会得到更准确的错误提示。

await tab.open("https://www.facebook.com/phbuster/posts/676836339178597")
// await Promise.delay(5000) // DON'T DO THIS!
await tab.waitUntilVisible(".permalinkPost .UFILikeLink")
// You can now safely click the "Like" button...
await tab.click(".permalinkPost .UFILikeLink")

在某些情况下,可能的确有必要伪造人为的延迟。可以使用

await Promise.delay(2000 + Math.random() * 3000)

糊弄过去。

MongoDB

我们发现MongoDB很适合大部分的抓取工作,它有一套优秀的JS API和Mongoose ORM。考虑到当使用Headless Chrome时已经处于NodeJS环境中,为什么不采用它呢?

JSON-LD 和微数据开发

有时网页抓取并不需要理解DOM,而是要找到正确的“导出”按钮。记住这一点可以节省了不少时间。

严谨的说有些网站会比其他网站容易一些,以Macys.com为例,他们所有的产品页面都以JSON-LD形式的产品数据显示在DOM中。可以说到它们的任何一个产品页面然后运行

JSON.parse(document . queryselector(" # productSEOData "). innertext)

将得到一个可以插入MongoDB很好的数据对象,没有真正抓取的必要!

网络请求拦截


image

因为使用的是DevTools API,所以编写的代码具有使用Chrome的DevTools的等效功能。这意味着产生的机器人可以拦截、检查甚至修改或中止任何网络请求。

通过从LinkedIn下载PDF格式的简历来测试网络请求拦截。从配置文件中单击“Save to PDF”按钮触发XHR,其中响应内容为PDF文件,这是一种拦截文件并将其写入磁盘的方法。

let cvRequestId = null
tab.driver.client.Network.responseReceived((e) => {if (e.type === "XHR" && e.response.url.indexOf("profile-profilePdf/") > 0) {cvRequestId = e.requestId}
})
tab.driver.client.Network.loadingFinished((e) => {if (e.requestId === cvRequestId) {tab.driver.client.Network.getResponseBody({ requestId: cvRequestId }, (err, cv) => {require("fs").writeFileSync("linkedin-cv.pdf", Buffer.from(cv.body, (cv.base64Encoded ? 'base64' : 'utf8')))})}
})

值得一提的是DevTools协议正在迅速发展,现在有一种方法可以使用Page.setDownloadBehavior()设置下载传入文件的方式和路径。我们还没有测试它,但看起来很有前途!

广告拦截
const nick = new Nick({loadImages: false,whitelist: [/.*\.aspx/,/.*axd.*/,/.*\.html.*/,/.*\.js.*/],blacklist: [/.*fsispin360\.js/,/.*fsitouchzoom\.js/,/.*\.ashx.*/,/.*google.*/]
})

同样可以通过屏蔽不必要的请求来加速抓取,分析、广告和图片是典型的屏蔽目标。然而,谨记它会让机器人变得不那么像人(例如,如果屏蔽了所有的图片,领英就不会正确响应页面请求——不确定这是否是故意的)。

在NickJS中用户可以指定一个白名单和一个包含正则表达式或字符串的黑名单。白名单特别强大,但如果不小心的话,很容易让目标网站崩溃。

DevTools协议也有Network.setBlockedURLs(),它使用带有通配符的字符串数组作为输入。

更重要的是,新版本的Chrome将带有谷歌自带的“广告拦截器”——它更像是一个广告“过滤器”。协议已经有一个端点叫做Page.setAdBlockingEnabled()。

这就是我们说的技巧!

Headless Chrome检测

最近发表的一篇文章列举了多种方法来检测Headless Chrome访问者,也有可能检测PhantomJS。那些方法描述了从基本的User-Agent字符串比较到更复杂的诸如触发错误和检查堆栈跟踪的技术。

在愤怒的管理员和巧妙的机器人制造商之间,这基本上是一个加大版的猫捉老鼠游戏。但从未见过这些方法在官方实施。在技术上是可以检测到自动访问者,但谁会愿意面对潜在的错误消息呢?对于大型的网站来说尤其有风险。

如果你知道那些网站有这些检测功能,请告诉我们!

结束语

抓取从来没有这么容易过,有了我们最新的工具和技术,它甚至可以成为我们开发人员愉快而有趣的活动。

顺便说一下,我们从Franciskim.co“我不需要臭烘烘的API”文章中受到了启发,非常感谢!另外,关于了解怎样开始使用木偶的详细说明,请点击这里。

在下一篇文章中,将写到关于“bot mitigation”的工具,比如Distill Networks,讲述HTTP代理和IP地址分配的美妙世界。

在Phantombuster.com上有我们的抓取和自动化平台 NickJS.org库。有兴趣的话还可以了解我们的3个抓取步骤的理论信息。

这篇关于2017年网页抓取:先进的Headless Chrome技巧的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/200835

相关文章

Pandas中多重索引技巧的实现

《Pandas中多重索引技巧的实现》Pandas中的多重索引功能强大,适用于处理多维数据,本文就来介绍一下多重索引技巧,具有一定的参考价值,感兴趣的可以了解一下... 目录1.多重索引概述2.多重索引的基本操作2.1 选择和切片多重索引2.2 交换层级与重设索引3.多重索引的高级操作3.1 多重索引的分组聚

Redis多种内存淘汰策略及配置技巧分享

《Redis多种内存淘汰策略及配置技巧分享》本文介绍了Redis内存满时的淘汰机制,包括内存淘汰机制的概念,Redis提供的8种淘汰策略(如noeviction、volatile-lru等)及其适用场... 目录前言一、什么是 Redis 的内存淘汰机制?二、Redis 内存淘汰策略1. pythonnoe

Python如何使用seleniumwire接管Chrome查看控制台中参数

《Python如何使用seleniumwire接管Chrome查看控制台中参数》文章介绍了如何使用Python的seleniumwire库来接管Chrome浏览器,并通过控制台查看接口参数,本文给大家... 1、cmd打开控制台,启动谷歌并制定端口号,找不到文件的加环境变量chrome.exe --rem

怎么关闭Ubuntu无人值守升级? Ubuntu禁止自动更新的技巧

《怎么关闭Ubuntu无人值守升级?Ubuntu禁止自动更新的技巧》UbuntuLinux系统禁止自动更新的时候,提示“无人值守升级在关机期间,请不要关闭计算机进程”,该怎么解决这个问题?详细请看... 本教程教你如何处理无人值守的升级,即 Ubuntu linux 的自动系统更新。来源:https://

将Python应用部署到生产环境的小技巧分享

《将Python应用部署到生产环境的小技巧分享》文章主要讲述了在将Python应用程序部署到生产环境之前,需要进行的准备工作和最佳实践,包括心态调整、代码审查、测试覆盖率提升、配置文件优化、日志记录完... 目录部署前夜:从开发到生产的心理准备与检查清单环境搭建:打造稳固的应用运行平台自动化流水线:让部署像

Java 枚举的常用技巧汇总

《Java枚举的常用技巧汇总》在Java中,枚举类型是一种特殊的数据类型,允许定义一组固定的常量,默认情况下,toString方法返回枚举常量的名称,本文提供了一个完整的代码示例,展示了如何在Jav... 目录一、枚举的基本概念1. 什么是枚举?2. 基本枚举示例3. 枚举的优势二、枚举的高级用法1. 枚举

不删数据还能合并磁盘? 让电脑C盘D盘合并并保留数据的技巧

《不删数据还能合并磁盘?让电脑C盘D盘合并并保留数据的技巧》在Windows操作系统中,合并C盘和D盘是一个相对复杂的任务,尤其是当你不希望删除其中的数据时,幸运的是,有几种方法可以实现这一目标且在... 在电脑生产时,制造商常为C盘分配较小的磁盘空间,以确保软件在运行过程中不会出现磁盘空间不足的问题。但在

Python中列表的高级索引技巧分享

《Python中列表的高级索引技巧分享》列表是Python中最常用的数据结构之一,它允许你存储多个元素,并且可以通过索引来访问这些元素,本文将带你深入了解Python列表的高级索引技巧,希望对... 目录1.基本索引2.切片3.负数索引切片4.步长5.多维列表6.列表解析7.切片赋值8.删除元素9.反转列表

Python中处理NaN值的技巧分享

《Python中处理NaN值的技巧分享》在数据科学和数据分析领域,NaN(NotaNumber)是一个常见的概念,它表示一个缺失或未定义的数值,在Python中,尤其是在使用pandas库处理数据时,... 目录NaN 值的来源和影响使用 pandas 的 isna()和 isnull()函数直接比较 Na

Oracle数据库执行计划的查看与分析技巧

《Oracle数据库执行计划的查看与分析技巧》在Oracle数据库中,执行计划能够帮助我们深入了解SQL语句在数据库内部的执行细节,进而优化查询性能、提升系统效率,执行计划是Oracle数据库优化器为... 目录一、什么是执行计划二、查看执行计划的方法(一)使用 EXPLAIN PLAN 命令(二)通过 S