作者 | Lokesh Joshi, 译者 | 张哲刚, 审校丨Noe, 当前,NodeJS拥有大量的库,基本上可以解决所有的常规需求。网络抓取是一项门槛较低的技术,衍生了大量自由职业者以及开发团队。自然而然,NodeJS的库生态系统几乎包含了网络解析所需的一切。, 本文论述中,首先假定已经运行在应用程序皆为NodeJS解析而工作的核心设备之上。此外,我们将研究一个示例,从销售品牌服装和饰品的网站https://outlet.scotch-soda.com 站点中的几百个页面里收集数据。这些代码示例类似于一些真实的抓取应用程序,其中一个就是在Yelp抓取中使用。, 当然,由于本文研究所限,示例中删除了一些生产组件,例如数据库、容器化、代理连接以及进程管理工具(例如pm2)。另外,在诸如linting这类显而易见的事务上也不会停止。, 但是,我们会保证项目的基本结构完善,将使用最流行的库(Axios,Cheerio,Lodash),使用Puppeter提取授权密钥,使用NodeJS流抓取数据并将其写入文件。, 本文将使用以下术语:NodeJS应用程序——服务器应用程序;网站 outlet.scotch-soda.com ——Web资源,网站服务器为Web服务器。大体来说,首先是在Chrome或Firefox中探究网站网络资源及其页面,然后运行一个服务器应用程序,向Web服务器发送HTTP请求,最后收到带有相应数据的响应。, outlet.scotch-soda.com的内容仅对授权用户开放。本示例中,授权将通过由服务器应用程序控制的Chromium浏览器实施,cookie也是从其中接收。这些Cookie将包含在每个向web服务器发出的HTTP请求上的HTTP标头中,从而允许应用程序访问这些授权内容。当抓取具有数万乃至数十万页面的大量资源时,接收到的Cookie需要更新一些次数。, 该应用程序将具有以下结构:, cookieManager.js:带有Cookie管理器类的文件,用以负责获取cookie;, cookie-storage.js: cookie 变量文件;, index.js:安排Cookie管理器调用点;, .env:环境变量文件。, /project_root, |__ /src, | |__ /helpers, | |__ **cookie-manager.js**, | |__ **cookie-storage.js**, |**__ .env**, |__ **index.js**, 主目录和文件结构, 将以下代码添加到应用程序中:, 在cookie-manager.js中:, 某些变量的值是链接到.env文件的。, // .env, NODE_ENV=DEV, LOGIN_PAGE=https://outlet.scotch-soda.com/de/en/login, LOGIN=tyrell.wellick@ecorp.com, PASSWORD=i*m_on@kde, 例如,配置无头消息属性,发送到方法 puppeteerXtra.launch解析为布尔值,它取决于状态可变的process.env.node_env 。在开发过程中,变量被设置为DEV,无头变量被设置为false,因此Puppeteer能够明白它此刻应该在监视器上呈现执行Chromium 。, 方法page.cookies返回一个对象数组,每个对象定义一个 cookie 并包含两个属性:名称和值 。使用一系列 Lodash 函数,循环提取每个 cookie 的键值对,并生成类似于下面的字符串:,
,文件 cookie-storage.js:, 对于闭包的定义,明确的思路是:在该变量作用域内的函数结束后,保持对某个变量值的访问。通常,当函数完成执行返回操作时,它会离开调用堆栈,垃圾回收机制会从作用域内删除内存中的所有变量。, 上面的示例中,本地cookie设置器完成设置后,应该回收的本地已处理cookie变量的值将保留在计算机的内存中。这就意味着只要应用程序在运行,它就可以在代码中的任何地方获取这个值。, 这样,当调用setLocalCookie时,将从中返回getLocalCookie函数。一旦这个LocalCookie函数作用域面临回收时,NodeJS能够看到它具有getLocalCookie闭包函数。此时,垃圾回收机制将返回的获取器作用域内的所有变量都保留在内存中。由于可变的本地处理Cookie在getLocalCookie的作用域内,因此它将继续存在,保持与Cookie的绑定。, 应用程序需要一个url的主列表才能开始爬取。在生产过程中,爬取通常从Web资源的主页开始,经过一定数量次数的迭代,最终建立一个指向登录页面的链接集合。通常,一个Web资源有成千上万个这样的链接。, 在此示例中,爬取程序只会传输8个爬取链接作为输入,链接指向包含着主要产品分类目录的页面,它们分别是:, https://outlet.scotch-soda.com/women/clothing, https://outlet.scotch-soda.com/women/footwear, https://outlet.scotch-soda.com/women/accessories/all-womens-accessories, https://outlet.scotch-soda.com/men/clothing, https://outlet.scotch-soda.com/men/footwear, https://outlet.scotch-soda.com/men/accessories/all-mens-accessories, https://outlet.scotch-soda.com/kids/girls/clothing/all-girls-clothing, https://outlet.scotch-soda.com/kids/boys/clothing/all-boys-clothing, 使用这么长的链接字符,会影响代码美观性,为了避免这种情形,让我们用下列文件创建一个短小精悍的URL构建器:, categories.js: 包含路由参数的文件;, target-builder.js: 构建url集合的文件., /project_root, |__ /src, | |__ /constants, | | |__ **categories.js**, | |__ /helpers, | |__ cookie-manager.js, | |__ cookie-storage.js, | |__ **target-builder.js**, |**__ .env**, |__ index.js, 添加以下代码:, // .env, MAIN_PAGE=https://outlet.scotch-soda.com, 这三个代码片段构建了本段开头给出的8个链接,演示了内置的URL以及路径库的使用。可能有人会觉得,这不是大炮打蚊子嘛!使用插值明明更简单啊!, 有明确规范的NodeJS方法用于处理路由以及URL请求参数,主要是基于以下两个原因:, 1、插值在轻量级应用下还好;, 2、为了养成良好的习惯,应当每天使用。, 向服务器应用程序的逻辑中心添加两个文件:, ·crawler.js:包含用于向 Web 服务器发送请求和接收网页标记的爬网程序类;, ·parser.js:包含解析器类,其中包含用于抓取标记和获取目标数据的方法。, /project_root, |__ /src, | |__ /constants, | | |__ categories.js, | |__ /helpers, | | |__ cookie-manager.js, | | |__ cookie-storage.js, | | |__ target-builder.js, ****| |__ **crawler.js**, | |__ **parser.js**, |**__** .env, |__ **index.js**, 首先,添加一个循环index.js,它将依次传递URL链接到爬取程序并接收解析后的数据:, 爬取代码:, 解析器的任务是在接收到 cheerio 对象时选择数据,然后为每个 URL 链接构建以下结构:, 解析代码:, 爬取程序和解析器运行的结果将是8个内部包含对象的数组,并传递回index.js文件的for循环。, 流写入文件, 要写入一个文件,须使用可写流。流是一种JS对象,包含了许多用于处理按顺序出现的数据块的方法。所有的流都继承自EventEmitter类(即事件触发器),因此,它们能够对运行环境中的突发事件做出反应。或许有人遇到过下面这种情形:, 这是NodeJS流的优秀范例,尽管它们的名字不那么原始:我的服务器和我的对象。在此示例中,它们侦听某些事件:HTTP请求(事件)的到达和一段数据(事件)的到达,然后安排它们各就各位去工作。“流式传输”的立足之本在于它们使用片状数据片段,并且只需要极低的运行内存。, 在此情形下,for循环按顺序接收 8 个包含数据的数组,这些数组将按顺序写入文件,而无需等待累积完整的集合,也无需使用任何累加器。执行示例代码时,由于能够得知下一部分解析数据到达for循环的确切时刻,所以无需任何侦听,就可以使用内置于流中的方法立即写入。, 写入到何处, /project_root, |__ /data, | |__ **data.json**, ..., 嵌套的for循环解决了一个问题:为在输出中获取有效的json文件,需要注意结果数组中的最后一个对象后面不要有逗号。嵌套for循环决定哪个对象是应用程序中最后一个撤消插入逗号的。, 如果事先创建data/data.json并在代码运行时打开,就可以实时看到可写流是如何按顺序添加新数据片段的。, 结论, 输出结果是以下形式的JSON对象:, 应用程序授权处理时间约为20秒。, 完整的开源项目代码存在GitHub上。并附有依赖关系程序包package.json。, 张哲刚,51CTO社区编辑,系统运维工程师,国内较早一批硬件评测及互联网从业者,曾入职阿里巴巴。十余年IT项目管理经验,具备复合知识技能,曾参与多个网站架构设计、电子政务系统开发,主导过某地市级招生考试管理平台运维工作。, 原文标题:Web Scraping Sites With Session Cookie Authentication Using NodeJS Request, 链接:, https://hackernoon.com/web-scraping-sites-with-session-cookie-authentication-using-nodejs-request
© 版权声明
文章版权归作者所有,未经允许请勿转载。