相关
- 官网:https://nodejs.org/en/
- API:https://nodejs.org/api/
- 慕课网:进击Node.js基础(一):http://www.imooc.com/learn/348
说点啥
一直想做一个属于自己的应用。于是“被迫”就来学一门后台相关的语言。以前从没搞过相关的,node应该算是我的启蒙语言了吧。
js嘛 很难想不到JavaScript,学会了这个,是不是再学Web就简单了?
我是从慕课网看视频学起的,这篇文章算是学习笔记吧,视频地址见下面的相关
API
URL
对应api地址:https://nodejs.org/api/url.html
对应慕课网视频地址:http://www.imooc.com/video/6710
api里乍一看啥玩意儿啊,全是英文,然后我就去看视频了。看完视频反过来再看api,卧槽,原来前面那一大坨Example是这个啊,哈哈,我们一起来看
我们在cmd中输入node,回车,便进入了nodejs的环境。 输入url,回车,我们会看到:
{
parse: [Function: urlParse],
resolve: [Function: urlResolve],
resolveObject: [Function: urlResolveObject],
format: [Function: urlFormat],
Url: [Function: Url]
}
这就是我们url的几个方法。其中最重要的当属 parse 了。 api中如下,我也不懂。。。:
url.parse(urlStr, [parseQueryString], [slashesDenoteHost])
parse基础
作用:解析 url
输入:url.parse(‘http://www.flowerfat.com‘)
输出:
{
protocol: 'http:',
slashes: true,
auth: null,
host: 'www.flowerfat.com',
port: null,
hostname: 'www.flowerfat.com',
hash: null,
search: null,
query: null,
pathname: '/',
path: '/',
href: 'http://www.flowerfat.com/'
}
跟着视频走到这里的时候,虽然scott哥说了每个的含义,不过还是没咋懂啊!直到后来看到api我说的那一坨,哦吼,每个都有对应的解释啊。
具体我就不多说了,英文也不难,大家一看就懂了
parse进阶
输入:url.parse(‘http://www.flowerfat.com‘, true)
第二个参数的目的:解析query时,是否用QueryString这个module。
这个设置为true的时候,解析到的query就成了键值对的形式。
输入:url.parse(‘//www.flowerfat.com’, true)
出问题了,host都得不到
输入:url.parse(‘//www.flowerfat.com’, true, true)
结果正确了,第三个参数默认是false,这里设置成true ,就能正确解析了。
这里我没懂,scott哥也没说这个参数是干啥的。不过我们来看api中:slashesDenoteHost是第三个参数的名字,百度了下,网上的说法是它会去认//与/,这两个中间的当作host。
具体我也不造理解的对不,又懂得朋友可以批评指教。
format
作用:与parse相反,即把上面解析输出的结果丢到这个函数里,返回url输入
输入:url.format( {protocol: ‘http:’,……,path: ‘/’,href: ‘http://www.flowerfat.com/’ } );
输出:’http://www.flowerfat.com’
resolve
作用:我理解是拼接,有一定规则的拼接
详情正如api里的Example:
url.resolve('/one/two/three', 'four') // '/one/two/four'
url.resolve('http://example.com/', '/one') // 'http://example.com/one'
url.resolve('http://example.com/one', '/two') // 'http://example.com/two'
Query Strings
懂的人都知道,我们用get方法跟服务器交流的时候,’?’后面的请求参数很重要。那么这个问号后面的请求参数就是我们parse后的query的值
对应api地址:https://nodejs.org/api/querystring.html
对应慕课网视频地址:http://www.imooc.com/video/6711
stringify
序列化:把键值对变成网址的形式
parse ###
反序列化:相当于前面我们提到的url.parse方法中的第二个参数,这是为true
escape、unescape
转义和反转义
HTTP源码
这可是个大工程,视频里在这部分说了一堆,我表示我睡着了。。。
中间部分都是一些需要了解的概念和知识,这些有助于我们后面关于HTTP源码的了解,这里就不赘述了。
对应api地址:https://nodejs.org/api/http.html
对应慕课网视频地址:http://www.imooc.com/video/7963
直接来看源码部分(源码来自Github!but!我在github上找不到视频里的那个工程啊,什么鬼,于是就选了个下面的这个,朋友们海涵)
nodejs对应源码地址:https://github.com/nodejs/node
然后在github页面按下t, 就是工程的搜索功能!卧槽,这个有点厉害 然后搜索http.js,就是我们要的HTTP的源码了哈
var http = require('http')
http
.createServer(function(req, res) {
res.writeHead(200, {'Content-Type':'text/plain'})
res.write('Hello Ming')
res.end()
})
.listen(2015)
我表示这段真没啥好说的。视频里针对上面代码的由来,追踪了下github上的源码。十几分钟的视频下来我是懵圈了,根本不明所以。朋友们你们加油,不说了,都是泪。
HTTP 爬虫
作为一个干活分享者,显然上面的乱七八糟的不是我的风格,这里继续copy视频里的好东西。
对应视频地址:http://www.imooc.com/video/7965
目的
所谓爬数据,我理解就是把我们需要的东西get到。(其实爬网页对html也要有一定了解)
执行1
为了方便爬,我们按照作者的意思,安装一个插件 :npm install cheerio ,目的是快速找到我们要爬的数据
在网页上审查元素,找到我们想要的:
// <div class="mod-chapters">
// <div class="chapter chapter-active">...</div> 后面的active表示这个item是否展开
// <div class="chapter chapter-active">...</div>
// <div class="chapter">...</div>
// <div class="chapter">...</div>
// <div class="chapter">...</div>
// </div>
主要代码(不要问我res.on(‘data’, function(data)里的data是哪儿来的,下篇文章见):
var http = require('http')
var cheerio = require('cheerio')
var url = 'http://www.imooc.com/learn/348'
// 相当于main 我们在这里解析html
function filterChapters(html){
var $ = cheerio.load(html)
// 这个跟视频里的learnchapter不同,可能是慕课网改了吧
// 通过这个方法就拿到了类名
var chapters = $('.chapter')
// 打印数组的长度
console.log('打印 '+chapters.length)
}
http.get(url, function (res) {
var html = ''
res.on('data', function(data) {
html += data
})
res.on('end', function(){
filterChapters(html)
})
}).on('error', function() {
console.log('获取网站数据出错!')
})
我们引入了cheerio,并用它来更好的get对应的数据
这里我们看,跟之前的代码比较,就多了个函数:filterChapters
在接收完毕网页后,把网页数据传到这个函数里,进行整理。
在cdm中执行上面的代码:
node crawierPlus.js
打印结果如下:
打印 5
执行2
显然一个数组长度不是我们想要的,继续,嘿咻嘿咻!
由执行1看到,chapters这个“数组”就是我们要的内容了。我们继续解析,如何拿到标题呢?
看网页的相关审查元素:
chapters.each(function(item){
var chapter = $(this)
var chapterTitle = chapter.find('strong').text()
console.log(chapterTitle + '\n')
})
通过each方法,得到每个chapter。通过find的方法,得到strong,在.text()得到strong里的text
再来看对应video的获取:
从图上能看出,video下有两个对应的条目
chapters.each(function(item){
var chapter = $(this)
var chapterTitle = chapter.find('strong').text()
console.log(chapterTitle + '\n')
var videos = chapter.find('.video').children('li')
videos.each(function(item){
var video = $(this).find('.studyvideo')
var videoTitle = video.text()
var id = video.attr('href').split('video/')[1]
console.log('【'+id+'】 '+videoTitle)
})
})
对比上面的find方法,我们发现’strong’和’.video’有个不同点,’.video’前面有个’.’,大胆假设,因为video是一个class,而strong不是。故而有此区别
跑一遍上面的code,我们就能看到一个很好看的结果了。
我们是打log,而视频里作者是把数据都封装到了一起,用的是push的方法,具体我也不懂,就不瞎bb了。
Code
var http = require('http')
var cheerio = require('cheerio')
var url = 'http://www.imooc.com/learn/348'
function filterChapters(html){
var $ = cheerio.load(html)
var chapters = $('.chapter')
var courseData = []
chapters.each(function(item){
var chapter = $(this)
var chapterTitle = chapter.find('strong').text()
var videos = chapter.find('.video').children('li')
var chapterData = {
chapterTitle: chapterTitle,
videos:[]
}
videos.each(function(item){
var video = $(this).find('.studyvideo')
var videoTitle = video.text()
var id = video.attr('href').split('video/')[1]
chapterData.videos.push({
title:videoTitle,
id: id
})
})
courseData.push(chapterData)
})
return courseData
}
function printCourseInfo(courseData){
courseData.forEach(function(item){
var chapterTitle = item.chapterTitle
console.log(chapterTitle + '\n')
item.videos.forEach(function(video){
console.log(' 【'+video.id+'】 '+ video.title + '\n')
})
})
}
http.get(url, function (res) {
var html = ''
res.on('data', function(data) {
html += data
})
res.on('end', function(){
var courseData = filterChapters(html)
printCourseInfo(courseData)
})
}).on('error', function() {
console.log('获取网站数据出错!')
})
个人博客
欢迎来访我的干货个人博客:http://www.flowerfat.com