楔子
最近帮一个小伙伴找实习岗位,看到某公司给他发的面试题挺有意思,趁着不忙自己研究了一番,做个笔记留待以后复习。
面试题
使用 http://www.nightmarejs.org/ 爬取 https://box.jimu.com/Venus/List 第一页项目数据,并生成一个数组,每个数据格式为 {name: **, rate: **, month: **, status: **}
分析
首先当我们看到这个题目的时候应该大概就了解这是一个爬虫任务,使用工具到指定页面爬取数据,同时将爬取到的数据生成某种格式。
那么这道面试题的目的是要考察求职者哪些知识/能力呢?这里简单分析了下:
- 有没有接触过node/npm 这个是最基础的,如果这个都不知道就不用往下看了
- nightmare工具的使用
- JS数据的处理,如何生成项为对象格式的数组
- JS基础知识,比如获取元素、分割字符串等
- 踩坑能力(这个后面再说)
好了,分析就这么多,接下来我们开始试着去解答这道面试题。
开撸
首先我们应该先了解下nightmare这个工具,官网链接http://www.nightmarejs.org/
官方说法A high-level browser automation library
,翻译过来就是高级浏览器自动化库
OK,既然要使用这个库首先要安装,我们新建nightmare文件夹,然后执行npm install nightmare
按照常理应该稍等就安装好,但是这里居然报错了。。。错了。。。了。
我就是在这里踩了一个坑,报错就是在执行下面图这步
百度了下发现,nightmare依赖于electron,那么先安装electron呢?不好意思,也报错。。瞬间我就懵了,于是我试着在百度搜报错的代码,找到下面的解决方法eletron安装卡在 node install.js,原因居然是网速问题!!!无力吐槽。。
OK,按照链接中的方法,成功安装nightmare。这里贴一个nightmare在github上的示例:
var Nightmare = require('nightmare');
var nightmare = Nightmare({ show: true });
nightmare
.goto('https://duckduckgo.com')
.type('#search_form_input_homepage', 'github nightmare')
.click('#search_button_homepage')
.wait('#zero_click_wrapper .c-info__title a')
.evaluate(function () {
return document.querySelector('#zero_click_wrapper .c-info__title a').href;
})
.end()
.then(function (result) {
console.log(result);
})
.catch(function (error) {
console.error('Search failed:', error);
});
有兴趣可以在复制下来自已看一下效果,这里重点看一下nightmare常用的API
- goto(url[,headers]) url为你要跳转的网站url
- wait(selector) 等待某个dom元素出现
- type(selector[,text]) 在selector元素中输入text文本
- click(selector) 点击某个dom元素
- evaluate(fn[,agr1,agr2,...]) 在客户端注入JS脚本并执行 也就是你自己要封装数据的代码
- end() 执行完成,等待对数据的处理
其他的API大家可以自行去官方文档查看。其实整个API看下来还是挺简单的,那么我们就直接开始我们的需求。
var Nightmare = require("nightmare");
var nightmare = Nightmare({show:false})
nightmare
.goto("https://box.jimu.com/Venus/List")
.evaluate(function(){
// ourcode
})
.end()
.then(function(result){
console.log(result);
})
.catch(function(error){
console.log(error);
})
大致结构就是这样,剩下的就是我们对要爬取的网站进行结构分析,然后写出符合要求的代码,我这里贴出我自己写的代码,轻喷(o(╯□╰)o)
var links = document.querySelectorAll(".project");
var listArr = [],
listObj = {},
len = links.length;
for(let i = 0;i < len;i++){
listObj.name = links[i].getElementsByClassName("title")[0].innerText;
listObj.rate = links[i].getElementsByClassName("invest-item-profit")[0].innerText + "%";
listObj.month = links[i].getElementsByClassName("time")[0].getElementsByClassName("num")[0].innerText + links[i].getElementsByClassName("time")[0].getElementsByClassName("tip")[0].innerText.slice(-2,-1);
listObj.status = links[i].getElementsByClassName("more-title")[0].innerHTML;
listArr.push(listObj);
listObj = {};
}
return listArr;
最终返回的数据如下图
这里不足的地方就是返回的数据中month出现在第一个位置上,百度了下这是chrome浏览器的默认机制,按照字母顺序排序对象属性,目前还在查找相关方法以达到题目要求
写在最后
虽然本文写的是nightmare工具的使用,但是要想写出最终代码JS基础知识是必不可少的,框架/库每天都在更新,只有打牢基础才能以不变应万变,这才是最重要的。