啊啊啊找不到工作我要死啦
前端时间做项目练手经常要用到数据,要找工作了嘛,没项目怎么行呢?有项目没数据怎么行呢?
数据怎么来?当然是爬虫啦!
然而当我开始写爬虫的时候,发现事情没有那么简单,刚开始自已用原生node写,写出了一堆bug,经常会由于各种各样的问题爬不出数据,遂放弃。
之后就是找轮子的过程了,去npm上面搜了搜,发现node的爬虫框架并不多,一个下载量比较多的是crawler这个框架,用法也比较简单,就决定就是它了!
之后一段时间我要爬取数据都是用的这个框架,用了几次之后我发现虽然用了框架,但是每次爬取数据还是要进行许多重复性的工作,这些工作应该是可以用代码自动完成的呀,所以我着手对crawler进行了一定的封装,使它变得更简单易用,并且功能上也进行了一些完善。
安装:
我已经将该框架上传到npm上了,取名为crawler-lian,要用的话可以直接安装,但是目前仍然存在许多的bug,谨慎使用:
npm i -D crawler-lian
基本用法:
只要简单的设置一些选择器和处理函数,就可以爬取数据了,快来试试吧!
const {fetchBySelector,utils} = require('crawler-lian');
//获取指定元素的属性
fetchBySelector(uri, { selector: 'a', attr: 'href' }).then(({data}) => console.log(data));
fetchBySelector(uri, { selectors:[
{selector:'.position', attr:'text'},
{selector:'.phone-num', attr:'text'}
] }).then(({data}) => console.log(data));
//获取一个页面中的指定列表数据和内部数据
fetchBySelector(uri, { groups:[
{
groupName: 'list', //自己定义一个名字吧
//爬取一个列表的数据,el通常是li元素
el: '.s_position_list > .item_con_list> .con_list_item',
selectors:[
{
selector: '.position_link',
attr: 'href',
name: 'detail_url'
},
{
selector: '.format-time',
attr: 'text',
name: 'time',
handler({ value }) {
return parseTime(value);
}
},
],
//处理具体值
handler({ value }) {
return utils.removeSpace(value);
},
//合并/处理 数据项
process ({ matchs }) => {
//一个选择器选中的是一个数组的数据,我们只要第一项。
if (matchs && matchs.length > 0) {
return matchs[0]
}
},
//获取列表项内部页面数据,并合并到当前项
//支持异步操作哦
itemProcess({ data }) {
let detail_url = data.detail_url;
if (detail_url) {
let pro = fetchBySelector(detail_url, detailOptions)
.then(({ data: detailData }) => ({ ...data, ...detailData }))
.catch(console.log);
return pro;
} else {
// console.log(data)
return data;
}
}
}
] }).then(({data}) => console.log(data));
//其他配置项
const option = {
deDuplication: false, //是否去重
selector: 'a', //默认选择器
attr: 'text', //默认选择的属性
trim: true, //是否去前后空格
handler: null, //处理器,处理选中的具体元素
process: null, //处理选择器选中的一个数组,返回新的数据或者一个promise对象
test: null, //测试标准,传入一个正则表达式
filter:null, //过滤器,与test功能相同,传入一个函数
groups, //分组爬取, 如果和selector同时存在,会覆盖selector
itemProcess: null //处理一组数据
}
试一试:
const { fetchBySelector } = require('crawler-lian')
//爬取douban数据(就爬一点点^v^)
fetchBySelector('https://movie.douban.com/chart',
{
attr: 'text',
groups: [
{
groupName: 'list',
el: 'tr.item',
process({ matchs }) {
return matchs.length > 0 ? matchs[0] : null;
},
itemProcess({ data }) {
let { href } = data;
let pro = fetchBySelector(href, {
selectors: [
{
selector: '#link-report',
name: 'desc',
process({matchs}){
return matchs[0]
}
}
]
})
//一项数据:如果要存数据库的话,也可以在这里直接进行数据存储操作
.then(({ data: detailData }) => ({ ...data, ...detailData }));
return pro;
},
selectors: [
{
selector: 'a.nbg',
attr: 'href',
name: 'href'
},
{
selector: 'a.nbg>img',
attr: 'src',
name: 'img_src'
},
{
selector: 'tr > td:nth-child(2) > div > a',
attr: 'text',
name: 'name',
handler({ value }) {
//去空格
return value.replace(/\s+/g, '');
}
}
]
}
]
}
)
//解析完成输出所有数据
.then(({ data }) => console.log('result=', data))
结果如下:
result = {
list: [
{
href: 'https://movie.douban.com/subject/34805219/',
img_src: 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2566870171.jpg',
name: '饥饿站台/饥饿斗室(港)/绝命大平台(台)',
desc: '在未来的反乌托邦国度中,囚犯们被关押在垂直堆叠的牢房里,饥肠辘辘地看着食物从上层落下,靠近顶层的人吃得饱饱的,而位于底层的人则因饥饿而变得激进。\n' +
' \n' +
'   由加尔德·加斯特卢-乌鲁希亚执导的《饥饿站台》是一部扭曲的社会 寓言,讲述了人类最黑暗和最饥渴的一面。'
},
{
href: 'https://movie.douban.com/subject/2364086/',
img_src: 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2582428806.jpg',
name: '隐形人/隐身人/隐形客(港)',
desc: '西西莉亚(伊丽莎白·莫斯 Elisabeth Moss 饰)再也想不到,曾经将自己迷得神魂颠倒的英俊男人阿德里安(奥利弗·杰森-科恩 Oliver Jackson-Cohen 饰),如今会成为噩梦的始作俑者。在和自己恋爱后没多久,阿德里安便开始对西西莉亚进行精神和肉体上的双重控制,终于,忍无可忍的西西莉亚在一天深夜用安定将阿德里安迷晕,成功的逃 出了魔窟。\n' +
' \n' +
'   之后,西西莉亚震惊的收到了阿德里安自杀的消息了,她几乎不敢相信,这个魔头真的从自己的生活中彻彻底底的消失了。西西莉亚的疑虑并不是空穴来风,在她生活的角角落落中,似乎都有 一个无形的影子在窥视着她,企图触碰她。\n' +
' \n' +
' ©豆瓣'
},
//下面省略好多条...
]
}
总结
该框架还有一些零零散散的简单功能这里没有提到,当然也还有许多待完善的地方,如果有人看的话,我会写一篇文章说说源码(也可以自己看看,写的挺简单的,就是有点乱...)。
最后,如果有人用的话,发现bug可以回复通知我(虽然bug肯定很多就是了...)。
最后的最后,2020届应届生找工作,求好心人收留:1732554225@qq.com。这是我做的一个练手vue项目(用了一些B站数据和样式),感兴趣的可以看看,地址是:lys.buctsnc.cn/ 。