网页新闻抓取(新版headless模式,每一个都各有特色,我们自己的一款是NickJS)
优采云 发布时间: 2021-11-09 13:09网页新闻抓取(新版headless模式,每一个都各有特色,我们自己的一款是NickJS)
市面上确实有很多NodeJS库支持Chrome新的headless模式,每个库都有自己的特点。我们自己的一个是 NickJS。如果你没有自己的爬虫库,你怎么敢说你是网络爬虫专家。
还有一组社区发布的其他语言的C++ API和库,比如GO语言。我们推荐使用 NodeJS 工具,因为它和网页解析语言是一样的(你会在下面看到它有多方便)。
网络爬虫?不违法吗?
我们无意挑起无休止的争议,但不到两周前,一位美国地区法官命令第三方抓取 LinkedIn 的公开文件。到目前为止,这只是一项初步法律,诉讼还将继续。LinkedIn肯定会反对,但是放心,我们会密切关注情况,因为这个文章讲了很多关于LinkedIn的内容。
无论如何,作为技术文章,我们不会深入研究具体爬虫操作的合法性。我们应该始终努力尊重目标网站的ToS。并且不会对您在此文章 中了解到的任何损害负责。
到目前为止学到的很酷的东西
下面列出的一些技术,我们几乎每天都在使用。代码示例使用 NickJS 爬网库,但它们很容易被其他 Headless Chrome 工具重写。重要的是分享这个概念。
将饼干放回饼干罐中
使用全功能浏览器进行爬取,让人安心,不用担心CORS、session、cookies、CSRF等web问题。
但有时登录表单会变得很棘手,唯一的解决办法就是恢复之前保存的会话cookie。当检测到故障时,一些网站会发送电子邮件或短信。我们没有时间这样做,我们只是使用已设置的会话 cookie 打开页面。
LinkedIn有一个很好的例子,设置li_atcookie可以保证爬虫访问他们的社交网络(记住:注意尊重目标网站Tos)。
await nick.setCookie({ name: "li_at", value: "a session cookie value copy from your DevTools", domain: "" })
我相信像LinkedIn这样的网站不会使用有效的会话cookie来阻止真正的浏览器访问。这是相当危险的,因为错误的信息会引发愤怒用户的大量支持请求。
jQuery 不会让你失望
我们学到的一件重要事情是,通过 jQuery 从网页中提取数据非常容易。现在回想起来,这是显而易见的。网站 提供了一个高度结构化、可查询的收录数据元素的树(称为 DOM),而 jQuery 是一个非常高效的 DOM 查询库。那么为什么不使用它进行爬行呢?这种技术将被一次又一次地尝试。
很多网站已经用过jQuery了,所以在页面中添加几行就可以获取数据了。
await tab.open("") await tab.untilVisible("#hnmain") // 确保我们已经加载了页面 await tab.inject("") // 我们将使用 jQuery 来抓取 consthackerNewsLinks = await tab.evaluate((arg, callback) => {// 这里我们在页面上下文中。就像在浏览器的检查器工具中 const data = [] $(".athing").each((index, element ) => {data.push({ title: $(element).find(".storylink").text(), url: $(element).find(".storylink").attr("href")} ) }) callback(null, data) }) 印度、*敏*感*词*和巴基斯坦在拦截机器人的做法上有什么共同点?
答案是使用验证码来解决服务器验证。几块钱就可以买到上千个验证码,生成一个验证码通常需要不到30秒的时间。但是到了晚上,因为没有人,一般都比较贵。
一个简单的谷歌搜索将提供多个 API 来解决任何类型的验证码问题,包括获取谷歌最新的 recaptcha 验证码(21,000 美元)。
将爬虫连接到这些服务就像发出一个 HTTP 请求一样简单,现在机器人是一个人。
在我们的平台上,用户可以轻松解决他们需要的验证码问题。我们的 Buster 库可以调用多个来解决服务器验证:
if (await tab.isVisible(".captchaImage")) {// 获取生成的 CAPTCHA 图像的 URL // 注意我们也可以获取它的 base64 编码值并解决它 const captchaImageLink = await tab.evaluate(( arg, callback) => {callback(null, $(".captchaImage").attr("src")) }) // 调用验证码解决服务 const captchaAnswer = await buster.solveCaptchaImage(captchaImageLink) //用我们的解决方案填写表单 await tab.fill(".captchaForm", {"captcha-answer": captchaAnswer }, {submit: true })} 等待 DOM 元素,不是固定时间
经常看到爬行初学者要求他们的机器人在打开页面或点击按钮后等待 5 到 10 秒——他们想确保他们所做的动作有时间产生效果。
但这不是应该做的。我们的 3 步理论适用于任何爬行场景:您应该等待的是您要操作的特定 DOM 元素。它更快更清晰,如果出现问题,您将获得更准确的错误提示。
await tab.open("") // await Promise.delay(5000) // 不要这样做!await tab.waitUntilVisible(".permalinkPost .UFILikeLink") // 您现在可以安全地单击“喜欢”按钮...等待 tab.click(".permalinkPost .UFILikeLink")
在某些情况下,可能确实有必要伪造人为延迟。可以使用
等待 Promise.delay(2000 + Math.random() * 3000)
鬼混。
MongoDB
我们发现MongoDB非常适合大部分的爬虫工作,它拥有优秀的JS API和Mongoose ORM。考虑到你在使用 Headless Chrome 的时候已经在 NodeJS 环境中了,为什么不采用呢?
JSON-LD 和微数据开发
有时网络爬虫不需要了解DOM,而是要找到正确的“导出”按钮。记住这一点可以节省很多时间。
严格来说,有些网站会比其他网站容易。例如,他们所有的产品页面都以 JSON-LD 产品数据的形式显示在 DOM 中。您可以与他们的任何产品页面交谈并运行
JSON.parse(document.Queryselector("#productSEOData").innertext)
你会得到一个非常好的数据对象,可以插入到MongoDB中,不需要真正的爬取!
网络请求拦截
因为使用了DevTools API,所以编写的代码具有使用Chrome的DevTools的等效功能。这意味着生成的机器人可以拦截、检查甚至修改或中止任何网络请求。
通过从LinkedIn下载PDF格式的简历来测试网络请求拦截。点击配置文件中的“Save to PDF”按钮,触发XHR,响应内容为PDF文件,是一种截取文件写入磁盘的方法。
让 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.* / ], 黑名单: [/.*fsispin360\.js/, /.*fsitouchzoom\.js/, /.*\.ashx.*/, /.*google.*/] })
还可以通过阻止不必要的请求来加速爬行。分析、广告和图像是典型的阻塞目标。但是,请记住,这会使机器人变得不像人类(例如,如果所有图片都被屏蔽,LinkedIn 将无法正确响应页面请求——不确定这是不是故意的)。
在 NickJS 中,用户可以指定收录正则表达式或字符串的白名单和黑名单。白名单特别强大,但是一不小心,很容易让目标网站崩溃。
DevTools 协议还有 Network.setBlockedURLs(),它使用带有通配符的字符串数组作为输入。
更重要的是,新版Chrome会自带谷歌自己的“广告*敏*感*词*”——它更像是一个广告“过滤器”。该协议已经有一个名为 Page.setAdBlockingEnabled() 的端点。
这就是我们正在谈论的技术!
无头 Chrome 检测
最近发表的一篇文章文章列举了多种检测Headless Chrome访问者的方法,也可以检测PhantomJS。这些方法描述了基本的 User-Agent 字符串与更复杂的技术(例如触发错误和检查堆栈跟踪)的比较。
在愤怒的管理员和聪明的机器人制造者之间,这基本上是猫捉老鼠游戏的放大版。但我从未见过这些方法正式实施。检测自动访问者在技术上是可能的,但谁愿意面对潜在的错误消息?这对于大型 网站 来说尤其危险。
如果你知道那些网站有这些检测功能,请告诉我们!
结束语
爬行从未如此简单。借助我们最新的工具和技术,它甚至可以成为我们开发人员的一项愉快而有趣的活动。
顺便说一句,我们受到了 Franciskim.co “我不需要一个臭 API”的启发 文章,非常感谢!此外,有关如何开始使用 Puppets 的详细说明,请单击此处。
下一篇文章,我会写一些“bot缓解”工具,比如Distill Networks,聊聊HTTP代理和IP地址分配的奇妙世界。
网络上有一个我们的抓取和自动化平台库。如果你有兴趣,还可以了解一下我们3个爬行步骤的理论信息。