node.js学习笔记之koa框架和简单爬虫练习

[复制链接]
8 f7 c1 W+ q5 N$ {/ C- H

Koa -- 基于 Node.js 平台的下一代 web 开发框架

2 v6 C2 `7 q# k7 T& L# }

koa是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。 使用 koa 编写 web 应用,可以免除重复繁琐的回调函数嵌套, 并极大地提升错误处理的效率。koa 不在内核方法中绑定任何中间件, 它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手。开发思路和express差不多,最大的特点就是可以避免异步嵌套。koa2利用ES7的async/await特性,极大的解决了我们在做nodejs开发的时候异步给我们带来的烦恼。

/ i( g. t7 }, i5 D1 R( T

英文官网:http://koajs.com

" b P6 F b4 G$ a. O6 ]/ K; ^

中文官网:http://koajs.cn

$ Z7 _8 a9 ^0 v: _

1.koa

. r Z& D5 y6 ~3 @# _. `: R

安装koa包: npm i -S koa@latest

- I6 i6 Q2 v. ]+ y! O

引入: const koa = require("koa");

实例化对象: const app = new koa;9 q3 ~8 q8 K, N4 ?; G# Q2 W3 c9 c

通过实例操作,专门用于客户端请求的函数叫做中间件,使用use()注册

. O6 O1 R( b. \+ T

use()函数中必须使用异步 async; use可是调用无数次;

1 x- I0 b& x) Q

其中有两个参数:

& p% \2 Z; D7 ^$ h

a)ctx: 上下文环境,node的请求和响应对象,其中不建议使用node原生的req和res属性,使用koa封装的requset和response属性

c0 [) O5 F7 I' k" M

b)next: next(),将本次控制权交给下一个中间件。

0 p+ A" d7 ~% n* m9 H+ }+ r

最后一个中间件使用next()无意义,执行完控制权返回上一层,直至第一个。

: X1 G6 Q: x7 r! ]; ?- z

1. next参数的使用demo

' ~5 X$ D2 [7 v
`const Koa = require(``"koa"``);` / w5 A0 j: k' R6 R `const koa =` `new` `Koa();`, e8 o$ @0 j, W9 d2 ^ `//中间件1` ! {; P6 ~2 c6 A `koa.use(async (ctx, next) => {`" l, J, u3 W* ] `console.log(``"1 , 接收请求控制权"``);` - j# w% f( _6 O: p2 Z `await next();` `//将控制权传给下一个中间件`3 v \6 r* b- S% w& [ `console.log(``"1 , 返回请求控制权"``);` * o2 u l! h, y `});` `//将中间件注册到koa的实例上`8 g! _0 Z" B" v# F' K `//中间件2`( l8 Y4 y% q+ o- n2 ` `koa.use(async (ctx, next) => {`0 k5 }1 y2 V3 S% I3 Z `console.log(``"2 , 接收请求控制权"``);` 9 ~- ^$ _7 E) K* M await next();`( Z5 |! j+ I" x! V6 w! [ `console.log(``"2 , 返回请求控制权"``);` * B: O5 B! o i0 m% {) h `});` ) _$ u! f# y1 N4 i% Y1 H* W3 o `//中间件3`: n( p; G$ Z' E, s6 `( [ `koa.use(async (ctx, next) => {` + Y' R+ o" ]( T# t$ t! U1 S( E `console.log(``"3 , 接收请求控制权"``);`/ _$ D1 V6 ^: Q `console.log(``"3 ,返回请求控制权"``);` / i: J: o6 V) N7 R$ g0 D `});`" Z& U# o) v* e/ p2 ~! y `koa.listen(3000, ()=>{` # j" A8 Q. r) \1 M `console.log(``"开始监听3000端口"``);` , z6 b4 T" i! a" w- b, k3 c `});`
+ y7 M" O- a; X' F# V; K

注:当中间件中没有next(),不会执行下面的中间件

! X4 L" ^0 M& F& S6 M$ O2 E+ v( |

访问localhost:3000的效果图;

% w6 }1 j- g8 k
, t; ^0 [3 Y6 l1 v. {" @6 I

注:会有两次操作是因为图标icon也会请求一次

/ ?& E- {2 n! X7 H4 u! [- L

2.ctx参数的使用demo

! Y+ G& k3 A. j! S
`const Koa = require(``"koa"``);` ! k' q V3 l/ t I. c) j; b `const koa =` `new` `Koa();`7 N$ o* l' g" L, s* ^ `koa.use(async (ctx, next)=>{` - R7 X" d' l5 r3 V `ctx.body =` `"body可以返回数据,"``;` # @7 {- d k; ?# M! u `ctx.body +=` `"可以多次调用,"``;` - l% ?. Q( Q8 E3 F7 }% l, Q( x `ctx.body +=` `"不需要end()"``;`1 H5 U: _% \$ m% w, w `});`" A$ M1 s/ G1 C% D7 p* S8 H& B `koa.listen(3000, ()=>{` , h9 ?& b& P" m% k S `console.log(``"监听开始"``);` , z4 X4 O4 W: V& }/ Z `});`
5 A+ ]6 }* z4 |$ Z) Q

效果:

1 y* Z2 i2 ~: e% O2 {; P% ~) W9 Y
4 w& i5 T5 H3 t( `/ r

ctx.url ,ctx.path ,ctx.query ,ctx.querystring ,ctx.state ,ctx.type

' c9 ]2 w+ N( m6 l! t
`const Koa = require(``"koa"``);`( V" y1 u' Z, Z: z( ?- A o g `const koa =` `new` `Koa();` : P* W# a2 T4 s4 b `koa.use(async (ctx, next)=>{` 2 P1 r( e9 q# G, M0 z; f% L+ h9 d `ctx.body = ctx.url;` : G; z) H: e& {8 J' d8 `" W- j `ctx.body = ctx.path;`9 p: h8 o: p! A& y- a: f8 _ `ctx.body = ctx.query;`2 F- B" s' c6 w' c& R `ctx.body = ctx.querystring;` ; u9 o$ S* I& o/ v4 y2 g- k `});` 0 ^! v; M) q! a! e `koa.listen(3000, ()=>{`! Q3 A9 n1 U4 Z$ @ U4 L) \ `console.log(``"监听开始"``);` ! j* }" K; P0 R+ D `});`
" L6 x; F* b+ l$ R4 V3 ]0 [( d

访问http://localhost:3000/path?name=sjl&age=18为例,效果图:

- M! y2 G0 `* W

1. url: 整个路径

- g! Q( ^7 J$ d; X5 J% @2 W! L: v
+ d) [" h! X2 z2 ^# ^

2. path: 非查询部分

: f2 k* o- K) ~
( y" Z( F f& R1 v1 n' ]

3. query: 将查询部分转为JSON对象

& v0 j8 a& B5 x( V# i1 u
% n( H2 w+ w) L

4. querystring: 将查询部分转为字符串

; {# X) v$ ~3 @- O+ ]. q9 R1 G
' M6 S- V* R9 X5 C& A( E

5. ctx.state ,ctx.type 表示状态吗和类型

) E+ r( c/ m, n* y

2.简单爬虫练习

8 u& r9 K7 U7 J

安装request,cheerio模块

; D+ c3 A' z% z# z7 O7 \
`npm i -S request: 请求模块` 3 Y5 Y0 F6 q/ h' T6 b `npm i -S cheerio: 抓取页面模块(JQ核心)`
0 P- ?/ R; [+ H( R

抓取网页数据案例(随机网页)

4 ?3 f, \# ]( b. M
`//导入模块`: p P/ E6 g2 {: X5 W2 p `const request = require(``"superagent"``);` `//导入请求模块` $ `; ]$ d4 J ]; K `const cheerio = require(``"cheerio"``);` * ^2 A8 [7 G1 T; H; f0 q6 K# I `const {join} = require(``"path"``);` ( c* O( G! `8 ] `const fs = require(``"fs"``);` ; |+ s) e ~- }% O. E `let arr = [],` `//存放数据` ! Q: J5 K6 F1 ^9 i `reg = /\n|\s+/g,` `//replace中使用`8 K* U7 u8 Q. I. s& U `url =` `"[https://www.shiguangkey.com/course/search?key=%E5%89%8D%E7%AB%AF/](https://www.shiguangkey.com/course/search?key=%E5%89%8D%E7%AB%AF/)"``;` $ \' T) v: ]+ N `request` X7 L$ \4 ~ A% ?/ [ `.get(url)` ! \ Y4 `3 a. X# t4 [' v `.end((err, res) => {`( w! [4 I: F, }6 v `const $ = cheerio.load(res.text);` `//把字符串内的标签当成dom来使用` 9 I( u' O( p" K* J3 p4 [ | `$(``".course-item"``).each((i, v) => {`% x( a, |& {. {. o: X `// v当前进来的dom,根据网页的布局结构来找到准确的dom节点` # m: O- Z# S+ d( e `const obj = {` , ?6 K- J7 V# _; }. W9 t `imgSrc : $(v).find(``"img"``).prop(``"src"``),`% f4 B8 B8 p$ N9 f7 Z8 M) F" r `price : $(v).find(``".fr span"``).text().replace(reg,` `""``),`8 ]7 H: J, ]( m- ?+ { `total : $(v).find(``".item-txt"``).text().replace(reg,` `""``),` % T; s/ b" \, ?+ e3 U: x `href : join(url + $(v).find(``".cimg"``).prop(``"href"``))` # s6 s0 v4 O8 h' g" |0 ?1 z `};`& z9 E8 x0 M: p8 j' y `console.log(join(url + $(v).find(``".cimg"``).prop(``"href"``)));` `//拼接`# }" b' [/ V6 n. }& P `arr.push(obj);` `//把对象放进数组里`2 w4 F5 U H/ }- ` `});` 0 C' y9 V+ Q( @6 @" ~" u1 { `fs.writeFile(``"./sjl.json"``, JSON.stringify(arr));` `//将爬到的数据写入文档中` J- f5 e, s: Y' v( r `});`
4 t$ y; e u5 s, z& j2 G# h6 x

以上就是本文的全部内容,希望对大家的学习有所帮助

7 m- ?& i( i+ _9 j7 c& d 1 d. t' A" O" j2 |, j/ F+ X ; m9 q+ V1 T+ v0 w7 w5 N+ K | 2 o2 R; Q! k p* H4 Z* J" X$ }# _/ n" \
回复

举报 使用道具

相关帖子

全部回帖
暂无回帖,快来参与回复吧
懒得打字?点击右侧快捷回复 【吾爱海洋论坛发文有奖】
您需要登录后才可以回帖 登录 | 立即注册
邢雷
活跃在昨天 18:34
快速回复 返回顶部 返回列表