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

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

[复制链接]
- U/ l: U5 `9 Y' w6 H

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

9 O7 m% S& k7 t* ?0 ~- O( U& s9 b

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

+ }/ k) z2 N6 q

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

. M" e+ |. z6 J$ j+ \# a' P

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

' j4 g; ~8 Q8 l8 e

1.koa

, Q- \5 C' R( ~5 m

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

7 |& h& a% u0 X2 {

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

实例化对象: const app = new koa; * i7 R- j5 V- y- ]! p; q" Z7 q

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

7 D o2 R0 g( h2 y# O0 p

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

6 }9 c' m7 ~% B" d* r2 x" N

其中有两个参数:

2 S8 p" F( M* D# p3 f

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

g1 C$ H3 N6 L+ V, ~1 P6 w

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

8 G1 g; p) F8 Y* _) ` f

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

- G p7 f/ N* C8 d+ z

1. next参数的使用demo

# p- n" z# n6 @+ b+ M
`const Koa = require(``"koa"``);`% U, N& J# u$ [& v9 ? `const koa =` `new` `Koa();`. a- t( U1 p* A `//中间件1`7 Y8 J; B1 q, }% p. z6 P `koa.use(async (ctx, next) => {`; Y) \4 a$ d! }. B8 q `console.log(``"1 , 接收请求控制权"``);`2 u1 U. g! Z/ |4 [3 L ~ `await next();` `//将控制权传给下一个中间件` , L7 ]* z# ?" h# f( a `console.log(``"1 , 返回请求控制权"``);` ' n/ V7 c. C/ l1 F3 n; d `});` `//将中间件注册到koa的实例上` & X' I) y, X8 e" F4 x `//中间件2`' h- @" Z& b7 W( D, { `koa.use(async (ctx, next) => {` 5 q' b" J3 j( ]" O3 p `console.log(``"2 , 接收请求控制权"``);`4 V; l1 h2 `% O# s await next();` 1 i0 k3 k1 ]3 C6 ?1 P% H `console.log(``"2 , 返回请求控制权"``);`/ t" A. v+ P, L$ P/ G+ d `});` 9 R6 U) g4 P1 i3 e3 \ `//中间件3` / t$ r- D0 W; ^! Y( s `koa.use(async (ctx, next) => {`. K! h# `4 s0 l7 c7 I9 a. ^8 J3 @& C; H `console.log(``"3 , 接收请求控制权"``);`( g3 @( m. Y' Z `console.log(``"3 ,返回请求控制权"``);` - Y! E2 i8 X. I) y4 R; K+ B \ `});` " [/ \# c% F2 g! j" X `koa.listen(3000, ()=>{` : F5 X# c' M2 d- S- A8 k `console.log(``"开始监听3000端口"``);` ; V# u1 O1 P6 F6 f0 U `});`
: ~" n6 f x( S; p6 Z

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

+ ~ z+ T$ e" v1 J% s

访问localhost:3000的效果图;

8 y; m( {9 |! d4 D- y9 @
: A, y5 i N$ F4 N: ?% Q

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

9 n- X6 m( Z( n* Y! J/ l! E" V

2.ctx参数的使用demo

R( g6 t( ?# ]* G
`const Koa = require(``"koa"``);`. X$ S6 Q' l' W P7 U `const koa =` `new` `Koa();`8 ~/ B' l2 X J- S' N7 n `koa.use(async (ctx, next)=>{` 0 b" y8 i* `1 f& b5 @1 g `ctx.body =` `"body可以返回数据,"``;`% q; x1 `7 j; F! I+ | `ctx.body +=` `"可以多次调用,"``;`* a8 j7 c1 O+ Q r" e. R6 g `ctx.body +=` `"不需要end()"``;`7 x* ], z0 P6 P; ?. s! F `});`& g+ i4 N1 p$ _: ] `koa.listen(3000, ()=>{`. T) y8 ^: ^1 e" H `console.log(``"监听开始"``);` ' W6 A0 V8 k' n+ ~3 T `});`
8 R m0 ]* J8 m# s5 Q$ ^! y* E

效果:

% C/ ]$ I2 K' T* V6 Q
( A1 J! ?& ?2 a$ j3 b2 |' c

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

9 Q1 \4 a& D6 @ r: `
`const Koa = require(``"koa"``);` , ]- u5 T- A: t7 c/ z1 b `const koa =` `new` `Koa();` 9 t3 w8 I: Q" L7 y- C1 F1 [ `koa.use(async (ctx, next)=>{` ; L: A0 y4 C3 ]$ K8 K `ctx.body = ctx.url;`9 F) [$ ^5 E9 p. j/ F+ i `ctx.body = ctx.path;` ' [9 a4 {2 L' n; {/ O" P `ctx.body = ctx.query;` $ v- A# r( t2 d. @. N O) O8 b `ctx.body = ctx.querystring;` + l/ q( l w# d- L5 s `});` # [# Q6 w/ D3 _ `koa.listen(3000, ()=>{`5 ]' W6 B+ _" v! z4 u/ Y2 S1 e `console.log(``"监听开始"``);`& F" j. H: Z+ k; L `});`
0 Z6 V L" W1 v E5 {

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

0 Y5 \) z3 g, h' M) x) ^# M

1. url: 整个路径

% q" B# Z- o* e
; A6 Z# f# G2 Z3 C

2. path: 非查询部分

: |# X5 Y& w& Z: x2 J5 f% x
# e1 G7 w; `& h9 m* H5 x& T+ ?1 B

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

5 g" N; E6 k# L9 J4 y
% O: v4 D/ ?! b- b

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

0 Z* d- f+ H' {7 ], M
?! P5 P4 L* k, S9 `

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

+ M- S9 X; a7 p2 {' {

2.简单爬虫练习

. ?7 Q) p# ^: J( {. {( j

安装request,cheerio模块

( E2 k0 i3 p6 M5 _" L5 l# J( _
`npm i -S request: 请求模块`# @/ b2 v1 e* K+ G; x- e `npm i -S cheerio: 抓取页面模块(JQ核心)`
) A# h. e! |2 |% F6 O/ w

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

& {& g. z* u {- h
`//导入模块` 9 h& A: j& _9 R7 P, K5 ^ `const request = require(``"superagent"``);` `//导入请求模块` 5 ^5 E, U5 z# q1 c; t/ w `const cheerio = require(``"cheerio"``);`* U* e. Q8 Q" P1 c2 R `const {join} = require(``"path"``);`! d# x, r) Y0 N, k/ h' A `const fs = require(``"fs"``);` % i7 }& ~$ \* ]2 c" D) r `let arr = [],` `//存放数据`. a% s3 u/ u& t6 B: K `reg = /\n|\s+/g,` `//replace中使用`) l$ `# v+ u1 H, j `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/)"``;`7 Y5 `# m3 F) }, Z$ C' v" G `request` U" }* m3 M# s( e F: r. x `.get(url)`% {$ N2 @) V$ L0 \4 C `.end((err, res) => {`8 t7 V, t0 U: G) f9 v `const $ = cheerio.load(res.text);` `//把字符串内的标签当成dom来使用` ; T+ q& b( w2 M9 D0 Y3 M `$(``".course-item"``).each((i, v) => {` " n; f/ f6 V+ c! w8 O `// v当前进来的dom,根据网页的布局结构来找到准确的dom节点`5 `$ h# v0 z/ e# [, w. F7 D `const obj = {` ! B0 N, _$ t5 T `imgSrc : $(v).find(``"img"``).prop(``"src"``),`) n T# \& C' [# i `price : $(v).find(``".fr span"``).text().replace(reg,` `""``),` * H; [ \, d2 F% d2 O9 s7 r `total : $(v).find(``".item-txt"``).text().replace(reg,` `""``),`% r. l+ G2 L& w' f4 L+ f+ b `href : join(url + $(v).find(``".cimg"``).prop(``"href"``))` 3 t5 G0 ~3 ?6 b6 D$ f+ _ `};`8 j9 [% G" d s3 m% p) }5 G5 p i `console.log(join(url + $(v).find(``".cimg"``).prop(``"href"``)));` `//拼接`* y) r* B. `8 b/ ~2 g/ d' T+ h `arr.push(obj);` `//把对象放进数组里` 3 r/ D" j7 a; D* \7 L `});` 5 }; b, x* m* u9 s+ R, b$ u `fs.writeFile(``"./sjl.json"``, JSON.stringify(arr));` `//将爬到的数据写入文档中`* o2 T/ H( Y" Y `});`
; s* B( Q7 e) @' y ?

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

$ j! w9 N# [; H. e! x3 s3 K 9 y5 |- s) n) @6 t B- J/ ^ , h, L) Y4 e! b& D+ } / m c5 K/ X+ r4 Y2 U6 w5 z: E* \# U4 O3 B
回复

举报 使用道具

相关帖子

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