收藏本站 劰载中...网站公告 | 吾爱海洋论坛交流QQ群:835383472

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

[复制链接]
4 B' X* K3 O2 j. S% f

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

% u J2 D& H6 f

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

- M0 ~# ~: j2 T; y! E# y v

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

, f/ P$ l- U; v

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

- {% i- q: w# ^3 f5 B& I7 v

1.koa

# I) G2 I; w: b/ D

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

8 k/ i9 E$ b2 b8 e6 G3 h4 U

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

实例化对象: const app = new koa; ' S+ h. o1 v( Y+ ]5 e- r. @, ~9 y% W

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

" p. P' `* R- ^2 K! _6 A

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

, h# p0 \! {% ~! k- N9 Z1 V; |

其中有两个参数:

& i9 B4 s; U/ b0 @( l H

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

% ~ q, O3 i& p

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

/ l1 v2 u- k4 j9 s% o' O

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

) E$ A* a J4 I ?' T

1. next参数的使用demo

+ V- p2 U$ @$ }! [3 b6 r$ F4 U
`const Koa = require(``"koa"``);` - v, J# ^+ P8 s* e `const koa =` `new` `Koa();`7 g1 h. C$ K/ C9 X) J0 g, D+ | `//中间件1` & R7 ]3 e6 T$ W8 o) D; g: L- i `koa.use(async (ctx, next) => {` ! S3 f3 W/ |- v. m. X: L8 L( q# M7 ` `console.log(``"1 , 接收请求控制权"``);` 7 {8 u% P! C8 n% Y2 V- b9 s! u0 @ `await next();` `//将控制权传给下一个中间件` , o' W- J+ i1 G! ~8 B `console.log(``"1 , 返回请求控制权"``);`. W: C# ] h; e( @ `});` `//将中间件注册到koa的实例上`8 \0 A1 @% p7 \7 `! F/ v `//中间件2` & \$ f) n3 r; H! o8 _ `koa.use(async (ctx, next) => {` 8 z6 Q" W8 y) ?5 k6 R* H `console.log(``"2 , 接收请求控制权"``);` / r) O6 c! n0 z' J7 i await next();` 9 ^9 h$ U2 K e; B* ~3 E' o `console.log(``"2 , 返回请求控制权"``);` ) ^; D' I& m, ]# w2 h- I `});` $ v& |; J/ x0 b8 Z `//中间件3`7 ]6 S1 s( a f5 O. O* ? `koa.use(async (ctx, next) => {`" U9 J; M# }6 w& E5 m9 b `console.log(``"3 , 接收请求控制权"``);` , [9 {1 n8 m( l' o; i. y- y `console.log(``"3 ,返回请求控制权"``);` % W6 s; p4 K% ^: R, z0 G `});`/ q: N) S( ?" F* e7 u `koa.listen(3000, ()=>{` . {, ]) M! T b* `4 d8 O, I& A- P `console.log(``"开始监听3000端口"``);`$ Q* ^# n# j) w `});`
/ c3 v# f1 Z9 ^3 ?# ~

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

$ J, A9 H4 i( [+ P! N

访问localhost:3000的效果图;

0 M# s# T4 B; L2 t/ v
& g. U8 m1 Y& S% i8 Y

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

( X8 {- {- k4 g& i" C

2.ctx参数的使用demo

5 T* s7 o( k+ Z$ {0 k9 g/ U4 T
`const Koa = require(``"koa"``);`" R# l2 t* B7 h9 {3 ?9 D `const koa =` `new` `Koa();`. E6 v$ G$ E$ F; ^ `koa.use(async (ctx, next)=>{` / b, R% N" Q z. i5 m `ctx.body =` `"body可以返回数据,"``;` 1 c2 b" X | p, M! @ `ctx.body +=` `"可以多次调用,"``;`: B8 b* o% m+ y `ctx.body +=` `"不需要end()"``;`- {" w9 O4 R, _; h% M7 _8 [2 y) f `});` % G' M) ?. r1 X2 t `koa.listen(3000, ()=>{` - @) b9 Q2 m$ w+ P `console.log(``"监听开始"``);` * Z' I7 b. {; O3 e a$ f5 |7 q' y% A& @( ] `});`
! K! U: a/ U# d

效果:

+ [+ Q- K7 F, n; [$ q$ o9 s0 Z
/ x( v$ j# i* L3 T3 V! d: O

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

1 E# h. E: d1 c6 w+ M; Z
`const Koa = require(``"koa"``);`2 D: M: \$ X, m; @9 Q0 ^ `const koa =` `new` `Koa();`+ P L& R5 f+ t- m0 }- _ `koa.use(async (ctx, next)=>{`: K9 w( A9 W9 a( f9 A% j `ctx.body = ctx.url;`8 H% [8 u4 _6 P. n; ^ `ctx.body = ctx.path;` * t" _3 s1 C/ B) \* L) k `ctx.body = ctx.query;` 6 i* {- a; H/ \/ _2 a: B `ctx.body = ctx.querystring;`" k" Z3 {# g2 L# y: ~& S& t `});`' b. A8 z p; C7 u `koa.listen(3000, ()=>{` 8 N* X( c; b" e% \4 F: K+ R `console.log(``"监听开始"``);` 7 M" e# y1 C0 e' n! \6 J8 V! i `});`
/ V' X8 e. m1 V, h

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

+ U' t+ a0 T/ {2 P* M

1. url: 整个路径

/ Z" i! ~) v5 d X' A$ }3 `9 ]$ X
, x9 W' S% {+ e, h

2. path: 非查询部分

" `8 a6 e! H8 Z6 Z+ g
3 e3 h9 c& b2 D( h9 e

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

( w, j/ S) u1 S$ Z& s/ ~7 I) v
- |' j" [6 l% m5 o

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

3 B- O q& p6 ?0 ~4 D
@; \# e6 Y% K& F, @

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

; C( S; c, K' h" i, w# Z% A; w

2.简单爬虫练习

/ G: E$ v+ S3 X7 D- v. {

安装request,cheerio模块

8 A( y' u! a5 z0 @4 M3 a$ d! E0 d* v% B
`npm i -S request: 请求模块` 4 E, q8 X6 W0 V+ w `npm i -S cheerio: 抓取页面模块(JQ核心)`
' H8 F1 H: I: h7 K0 V8 z

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

: t% r7 y8 _3 a$ a
`//导入模块` 4 ~, @+ G1 F$ [9 R1 I5 t `const request = require(``"superagent"``);` `//导入请求模块` 2 m* B& P' _* ?2 s7 i% C5 |. H& \ `const cheerio = require(``"cheerio"``);` & g4 R4 c2 r, C `const {join} = require(``"path"``);` 1 B+ r3 Q) k3 Q1 s- X" m& o `const fs = require(``"fs"``);` # e' f8 V" O0 [% O6 H% h/ \ `let arr = [],` `//存放数据`2 r6 n$ `. k# p! V7 Z$ ~) c `reg = /\n|\s+/g,` `//replace中使用`- V& X9 T8 j# k4 ~ `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/)"``;` 5 z1 _' v3 j; T2 Y" J `request` + ~: k8 _; w% F3 |% K& A* I4 ? `.get(url)` 6 v: W$ A- U% y7 F: K* M# V `.end((err, res) => {`' a& N1 @) ]) G `const $ = cheerio.load(res.text);` `//把字符串内的标签当成dom来使用`$ \& ^& \3 T# q9 M4 C6 z9 W9 H `$(``".course-item"``).each((i, v) => {` ) N/ R/ S; w& a7 l `// v当前进来的dom,根据网页的布局结构来找到准确的dom节点`) \$ l9 [' `2 A* G; o! l4 ? `const obj = {` + _* n8 W6 c6 S, t2 }- r `imgSrc : $(v).find(``"img"``).prop(``"src"``),`* Y+ W7 a- o) T0 i4 l, X `price : $(v).find(``".fr span"``).text().replace(reg,` `""``),` i! Q2 _/ U. I/ Z `total : $(v).find(``".item-txt"``).text().replace(reg,` `""``),`3 `; T# ?/ o3 G6 r" N" l& L- b `href : join(url + $(v).find(``".cimg"``).prop(``"href"``))`1 l7 c& `9 m- ?' Q# ~' d5 @ `};` - {0 G1 x4 I0 N+ ]. Y `console.log(join(url + $(v).find(``".cimg"``).prop(``"href"``)));` `//拼接`; w% E" M8 N1 d$ B$ V7 Z9 k `arr.push(obj);` `//把对象放进数组里`! j' ?0 W. C+ q0 j/ z, C `});` C1 k, i$ z* M( z. B0 S, A8 F `fs.writeFile(``"./sjl.json"``, JSON.stringify(arr));` `//将爬到的数据写入文档中` . N; }% x5 j' F+ W6 o& _ `});`
' x* k: g2 {+ p+ x$ b5 K. B- U

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

/ p- U; A! v7 F. z$ ?% z- f. {2 U( O2 [' e( [ $ C1 j% z R p 6 [3 p/ C- B4 ~4 R H; {7 d 6 P+ E0 i- e& H$ [
回复

举报 使用道具

相关帖子

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