我用node写了一个爬虫

用node爬取页面中的新闻保存到本地

背景:公司官网是我写的纯静态页面,没有后台系统,前两天突然告诉我要同步一下公司公众号的新闻。之前一篇一篇的增加,都是直接CV过来的,也不算多麻烦,这次好长时间没更新了,粗略扫了一眼,大概10+快20条了吧,身为一个开发人员,一个个CV太没效率了,于是乎…

准备工具

  • fs: 保存文件

  • axios: 负责请求公众号新闻页面信息

  • cheerio: 专为服务器设计的核心jQuery的快速,灵活和精益实现

分析

  1. 本地代码分析

    官网用的Nuxt框架,新闻被我统一放到了assets/news/目录下,每篇新闻都是递增序列命名的js文件,如:11.js。包含内容如下:

    1
    2
    3
    4
    5
    6
    export default {
    "title": "新闻标题",
    "source": "新闻源",
    "time": "新闻发布时间",
    "main": "新闻内容"
    }

    图片则在另一个图片文件下以news-11-*.png的命名方式保存。

  2. 公众号新闻页面代码分析

    以这篇新闻为例,打开开发者工具,查找需要的信息

    1
    2
    3
    4
    5
    6
    export default {
    "title": $('.rich_media_title').text(),
    "source": $('.rich_media_meta_nickname').text(),
    "time": $('.rich_media_meta_text').text(),
    "main": $('.rich_media_content').html()
    }
  3. 获取图片

    1
    2
    3
    4
    5
    6
    7
    8
    9
    axios({
    method: 'get',
    url: src,
    responseType: 'stream',
    }).then(data => {
    data.data.pipe(fs.createWriteStream(`./assets/web/news-${newsId}-${(index)}.${type}`));
    }).catch(err => {
    console.log(src, '图片下载失败', err)
    })

爬取代码

项目目录下创建getNews.js文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
function getNews(newsUrl, newsId, newsDate) {//这里多传一个newsDate,是因为公众号新闻的日期会格式化为『上周』等中文,这里就懒得再反格式化为纯数字了
//请求新闻页面
return axios.get(url)
.then(response => {
//1.获取document
var html_string = response.data.toString();
var $ = cheerio.load(html_string, { decodeEntities: false }); // 传递页面到模块
//此时我们已经可以像用 JQ 一样,使用 $ 进行元素获取了

//2.处理img图片
$('.rich_media_content img').each((index, img) => {
var type = $(img).attr('data-type');
//将图片地址转换成本地图片
$(img).attr('src', "${require('~/assets/web/news-" + newsId + "-" + (index) + "." + type + "')}");

//将图片下载到本地
axios({
method: 'get',
url: src,
responseType: 'stream',
}).then(data => {
data.data.pipe(fs.createWriteStream(`./assets/web/news-${newsId}-${(index)}.${type}`));
}).catch(err => {
console.log(src, '图片下载失败', err)
})
})

//3.处理正文
let main = '';
$('.rich_media_content section').each((idx, item) => {
//将引号替换一下,修复格式错误
$(item).attr('style', $(item).attr('style').replace(/\"/g, "'"))
});
main += $('.rich_media_content').html();

//4.写入文件
fs.writeFileSync(`./assets/news/news-${newsId}.js`, `export default {
"title": "${$('.rich_media_title').text().trim()}",
"source": "四维智联",
"time": "${newsDate}",
"main": \`${main.trim()}\`
}`)
})
.catch(error => {
console.log(error)
})
}

node 执行以上方法,喝口水的功夫,一篇新闻就复制下来了~

再加强一下,把所有地址放到一个数组里,一次就全部搞定了~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let newsList = [
{
url: 'https://mp.weixin.qq.com/s?__biz=MzU4OTY1NzI1Mg==&mid=2247484688&idx=1&sn=98e2cc7cce402f508cd5ca0686044f54&chksm=fdcb60dbcabce9cd3bcd17eebbe84de3a4fb0f93924e55b5a16b53491e6137a1143b86e20f48&mpshare=1&scene=1&srcid=&sharer_sharetime=1577262825200&sharer_shareid=1e52e4bd2457f4d240357ec73082fd55#rd',
id: 1,
date: 'XXXX-XX-XX'
},
{
url: 'https://mp.weixin.qq.com/s?__biz=MzU4OTY1NzI1Mg==&mid=2247484714&idx=1&sn=7becb9f151a0a9312d9386894eeaaabe&chksm=fdcb60e1cabce9f740175a39102c8dde82b33e9a61f4eb279cdb4d3ab3f0c3cbade87de97ce8&mpshare=1&scene=1&srcid=&sharer_sharetime=1577262765908&sharer_shareid=1e52e4bd2457f4d240357ec73082fd55#rd',
id: 2,
date: 'XXXX-XX-XX'
}
];

for (var key in newsList) {
let item = newsList[key];
getNews(item.url, item.id, item.date);
}
坚持原创技术分享,您的支持将鼓励我继续创作!