如何编写简单爬虫

2019-09-27
nodejs
4569

说到爬虫,很多人可能觉得很高端,很厉害。但其实是单间的,它的原理就一条:

请求数据数据,解析数据

请求数据:发送一个http请求,获得数据字符串

解析数据:通过一定的手段把需要的数据从刚才的字符串中选出来

来看一个简单的例子:

目标: 爬取简书文档,上传到掘金上

step1: 获取文章数据

https://www.jianshu.com/p/47f1fb7fc842 为例

通过request库请求页面,打印出来应该是一个html页面

const request = require('request');

request.get('https://www.jianshu.com/p/47f1fb7fc842', function (error, response, body) {
    console.log(body);
});

step2: 解析数据

解析html数据,需要用到另一个模块cheerio,它能在node环境中像jquery一样操作html数据。

const request = require('request');
const cheerio = require('cheerio');

request.get('https://www.jianshu.com/p/47f1fb7fc842', function (err, response, body) {
    const $ = cheerio.load(body);
    const pageTitle = $('title').text();
    console.log(pageTitle) // 页面title Nodejs入门实践第一讲Nodejs基础 - 简书

    // 解析content
    const article = $('article').html();
    console.log(article);
});

到这里,我们想要的html数据已经有了。

但是,html的冗余数据比较多,比如css,冗余结构,不方便我们扩展。这里我们再加工一下,将html转换成markdown文件。

将html转化为md需要用到turndown模块,具体如下:

const TurndownService = require('turndown');
const turndownService = new TurndownService({ codeBlockStyle: 'fenced' });

function jianshuHtml2Md(htmlStr) {
    const md = turndownService.turndown(htmlStr);

    console.log(md);
    return md
}

到这里,html已经转换为md了。

但是,问题还没完,打开这个md,发现没有图片。

找了一下,图片用了另一种样式

<div class="image-package">
<div class="image-container" style="max-width: 700px; max-height: 288px;">
<div class="image-container-fill" style="padding-bottom: 36.83%;"></div>
<div class="image-view" data-width="782" data-height="288"><img data-original-src="//upload-images.jianshu.io/upload_images/3735524-222980d6394acd09.png" data-original-width="782" data-original-height="288" data-original-format="image/png" data-original-filesize="20082"></div>
</div>

这里不要怕,继续加解析就行。例子可以参考:这里>

// 给turndownService解析器加一个自定义规则,用来解析图片
turndownService.addRule('rules1', {
    filter: function (node, options) {
        return node.nodeName === 'IMG'
    },
    replacement: function (content, node, options) {
        return `![](http:${node.getAttribute('data-original-src')})`
    }
});

现在就ok拉。

还有就是图片转存,上传等下次再讲。

完整代码:

const request = require('request');
const cheerio = require('cheerio');
const TurndownService = require('turndown');
const turndownService = new TurndownService({codeBlockStyle: 'fenced'});
const fs = require('fs');


turndownService.addRule('rules1', {
    filter: function (node, options) {
        return node.nodeName === 'IMG'

    },
    replacement: async function (content, node, options) {
        return `![](http:${node.getAttribute('data-original-src')})`
    }
});

request.get({
    url: 'https://www.jianshu.com/p/47f1fb7fc842',
    headers: {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36',
        'referer': 'https://www.jianshu.com/search?q=nodejs&page=1&type=note',
    }
}, function (err, response, body) {
    const $ = cheerio.load(body);
    const pageTitle = $('title').text();
    console.log(pageTitle); // Nodejs入门实践第一讲Nodejs基础 - 简书

    // 解析content
    const article = $('article').html();

    jianshuHtml2Md(article)
});


function jianshuHtml2Md (htmlStr) {
    const md = turndownService.turndown(htmlStr);
    fs.writeFile(`./test.md`, md, (err) => {
        if (err) {
            console.log(err)
        }
    });
    return md
}