17611538698
webmaster@21cto.com

使用Node.js 抓取网页内容

资讯 0 3250 2018-03-24 12:02:40
很长时间以来,我尝试使用后端语言来抓取网页,比如Java,PHP。后端语言开发纯粹,也很方便,但是有时候内容不可见。我开始使用Node.js来抓取页面。
 
准备工作
 
我们需要准备三个包来完成这个任务:
 
Axioshttps://github.com/axios/axios):一个基于Promise的浏览器以及Node.js的HTTP客户端,我们将用它来抓取网站的HTML网页。
 
Cheeriohttps://github.com/cheeriojs/cheerio):一个类似于服务器端JQuery的包。我们将用它分析和过滤从Axios抓取来的内容。
 
 
fshttps://nodejs.org/api/fs.html)是一个Node.js模块,我们用它来获取内容并写入到JSON文件中。
 
接下来,我们开始设置项目。
 
第一步,先创建一个文件夹。在终端中使用 cd 命令进入这个文件夹。
 
接下来初始化该项目:
 
npm init
 
按照提示的内容操作,可以直接按回车。最后输入yes,会在本目录下创建一个package.json的配置文件。
 
接下来,我们安装上面列表中的两个包。
 
npm install --save axios cheerio
 
fs模块已经是node.js的一部分,我们不需要安装。上述命令完成后,我们会看到上面的两个安装包已经在node_modules目录,它们也列在package.json文件中了。
 
从dev.to网站抓取内容
 
这个网站个人资料在以下网址,如https://dev.to/。我们的任务是抓取到我们写的文章内容,并把它保存到JSON文件中。如下所示:
 

1.jpeg

 
 
接下在,在我们的项目文件中创建一个JavaScript文件。如果你愿意,可以叫devtoList.js。
 
接下来需要我们安装软件包:
 
let axios = require('axios');
let cheerio = require('cheerio');
let fs = require('fs');
 
现在,我们开始抓取dev.to的内容:
 
axios.get("https://dev.to/aurelkurtula";);
.then(response) => {
if(response.status === 200){
const html = response.data;
const $ = cheerio.load(html);
}
 
 
},(error) => console.log(err) );
 
 
其中,在第一行我们从指定的URL中获取内容。axios是基于promise的,then检查响应是否正确,然后再开始抓取数据。
 
此时,我们使用控制台来查看 response.data 的内容,会看到来自这个URL的HTML标记,然后我们把这个HTML加载到cheerio。为了把问题解决好,我们用了硬编码的HTML来替代了 response.data 。
 
const html = 'I have a bunch of questions on how to behave when contributing to open source'
 
const h3 = cheerio.load(html)
console.log(h3.text())
 
这将返回没有h3标签的字符串。
 
筛选内容
 
到了这点,我们可以在抓取网站的同时找到控制台,找到区无想要的内容。如下源代码:
 

2.png

 
 
从上面的HTML中,我们看到文章正文CSS类有 single-article,标题使用了H3,文章标签放在tags的CSS类中。
 
接下来我们开始抓取。
 
axios.get('https://dev.to/aurekurtula')
.then((response) => {
if(reponse.status === 2000){
const html = response.data;
const $ = cheerio.load(html);
let devtoList = [];
$('.single-article').each(function(i,elem){
devtoList[i] = {
title: $(this).find('h3').text().trim();
url:$(this).children('.index-article-link').attr('href'),
tags:$(this).find('.tags').text().split('#')
.map(tag => tag.trim())
.filter(function(n){return n != ""})
 
}
});
}
},(error) => console.log(err));
 
以上的代码应该很好读,可以辅助参考上面的HTML源代码截图会更好理解。我们通过.single-article类取了每个.single-article节点。然后我们找到唯一的H3,从其中取得文字,然后使用trim()去掉冗余空格。我们从相关的锚标签中取得超链接。
 
获取文章的tags也很方便。我们把它们全部视为一个字符串(#tag1 #tag2 #tag3),然后把该字符串以#为界转换成一个数组。最后,我们再map数组的每个值用来去掉多余的空格,为了安全,我们过滤掉全部空格。
 
 
我们在循环体外部声明一个空数组。
let devtoList = []
这样我们可以循环体内部去向这个数组中添加数据。
 
于是,devtoList数组对象就包含了我们从网站上获取的数据。现在我们想把这些数据保存到一个JSON文件中,以便我们在任何地方可以使用。如下代码:
 
axios.get('https://dev.to/aurelkurtula')
.then((response) => {
if(resonse.status === 200){
const html = reponse.data;
const $ = cheerio.load(html);
let devtoList = [];
$('.single-article').each(function(i,elem){
devtoList[i] = {
title: $(this).find('h3').text.trim();
url: $(this).children('.index-article-link').attr('href'),
tags:$(this).find('.tags').text().split('#')
.map(tag => tag.trim())
.filter(function(n){return n != ""})
}
});
const devtoListTrimmed = devtoList.filter(n => n != undefined)
fs.writeFile('devtoList.json'),
JSON.stringify(devtoListTrimmed,null,4),
(err)=> console.log('File successfully written!'))
}
},(error) => console.log(err));
 
之前的devtoList数组对象可能包含空值,需要把它们筛选出去,然后使用fs模块写到devtoList.json文件中,这些内容是将数组对象转换为JSON。
 
这一切都是我们需要的。
 
本文相关源代码可以移步到:https://github.com/aurelkurtula/web-scraping来下载。我还在IMDB中抓取了Googlereads和movies的电子书,可以参考bookList和movieList.js文件。这些代码均在同一个GitHub地址。
 
 


作者:aurel kurtula 
编译:亢小龙
原文:https://dev.to/aurelkurtula/in ... s-9h2 


评论