node-05 RESTful、爬虫
一、扩展node的路由
res.statusCode = 200
, 设置状态码res.statusMessage = 'ok'
; 设置状态描述res.setHeader('content-type','text/html')
;告诉浏览器接收的内容是什么类型的;
还可以设置响应里面的内容;
text/plain 纯文本;
上面三种都是res.writeHead的分开写法;
二、扩展express的路由
res.json()
;输出json对象;res.send(JSON.stringify())
;输入json字符串;res.set()
;设置浏览器文件类型;res.status()
;设置状态码;可以直接链式调用send;
三、静态资源托管
app.use([path],express.static(path))
;第二个写要开放的目录,建议写绝对路径,可以自动查询index.html;
第一个可选,可以写一个路由,访问后面的目录需要带上这个路由;
app.use((req,res)=>{})
; 等同于app.all('*')
;
五、RESTful API
传统设计路由的形式: 形容词+名词
get /addbook get /book get /doaddbook get /dodelbook get /doupdatebook
RESTful: 这个东西就是去描述 路由应该如何设计
RESTful这个标准 把一些路由当中的形容词给去了。用 method请求方法表示
GET:读取(Read)
get /book/get
POST:新建(Create)
post /book/post
PUT:更新(Update)
put /book/put
PATCH:更新(Update),通常是部分更新
patch /book
DELETE:删除(Delete)
delete /book /book?id=1 /book/1
六、中间件
每一个中间都有自己的一些含义
在express所有的回调函数,都可以称为中间件,中间件可以理解为工厂当中的车间。
内置中间件
第三方的
自定义中间件
其实我们定义的路由都可是中间件
app.get('/book')
app.post('/user')
... 都是中间件使用中间件特定的语法
jsapp.use((req, res, next) => { // 这里可以做一些处理 next() // 必须调用next函数,否则不会往下面走了 })
使用中间件和定义路由很相像,只要匹配成功并且send了,就不会再往下匹配 。
七、OS
os.cpus()
获取操作系统的CPU信息;os.totalmem()
获取内存的信息os.arch()
查看系统架构,比如x64、x86,手机也不同;os.freemem()
查看剩余内存;os.platform()
查看操作系统平台
八、node爬虫
接口请求工具
axios
需要安装request
需要安装
// body为页面内容或请求内容
// response为响应头信息
request('http://', function(err,response, body){})
axios获取图片存入到本地
const ws = fs.createWriteStream(path)
// 请求注意添加响应信息, 以流的方式返回回来
axios.get(imgUrl, {responseType: 'stream'}).then(res => {
res.data.pipe(ws)
// 流读取完成时关闭
res.data.on('close', () => {
ws.close()
})
})
由于爬虫循环请求数据,容易导致拉黑,建议添加延时函数
function lcWait(milliSeconds){
return new Promise(resolve => {
setTimeout(resolve, milliSeconds)
})
}
注意在等待时给定延时,需要是不同的时间,否则就是一起等待了;
获取dom工具(类似jquery)
- jsdom
- cheerio:中文文档 推荐使用
cheerio基本例子
const cheerio = require('cheerio')
const request = require('request')
let url = 'https://www.1905.com/'
request(url, function(err, response, body){
// 使用load加载dom结构,之后可以使用$符获取;
const $ = cheerio.load(body)
let arr = []
$('div.exclusive-content a').each((index, element) => {
arr.push({name: $(element).attr('alt'), url: $(element).attr('href')})
})
console.log(arr)
})
常用爬虫函数
// 创建文件夹的正则
const reg = /[\\/\:\*\?\"\<\>\|\t\b\r]/g
// 创建写入文件,递归创建
function recursiveFile(dir, name) {
const curPath = path.resolve(process.cwd(), dir)
if(!fs.existsSync(path)) {
fs.mkdirSync(curPath, {recursive: true})
}
return fs.createWriteStream(path.resolve(curPath, name + '.' + extname))
}
九、Puppeteer
介绍
- 生成页面 PDF。
- 抓取 SPA(单页应用)并生成预渲染内容(即“SSR”(服务器端渲染))。
- 自动提交表单,进行 UI 测试,键盘输入等。
- 创建一个时时更新的自动化测试环境。 使用最新的 JavaScript 和浏览器功能直接在最新版本的Chrome中执行测试。
- 捕获网站的 timeline trace,用来帮助分析性能问题。
- 测试浏览器扩展。
安装
教程网站:zhaoqize.github.io/puppeteer-api-zh_CN/#
安装:
npm install puppeteer-core
puppeteer-core
为跳过安装chromium版,通过后面指定executablePath
来打开本地chrome启动demo
jsconst puppeteer = require('puppeteer'); puppeteer.launch({ headless: false, // 设置浏览器视窗大小 defaultViewport: { width: 1400, height: 800 }, // 设置放慢速度,方便调试 slowMo: 250, executablePath: '本地chrome文件exe地址' }).then(async browser => { const page = browser.newPage() // 打开一个新窗口 })
headless:设置为true时不打开浏览器,设置false为打开浏览器,方便调试;
获取控制台内容
使用page对象;
page.on('console', eventMsg => {
// node中打印浏览器控制台输出文字
console.log(eventMsg.text())
})
获取节点内容
page.$是返回ElementHandle用来操作点击事件的;
page.$eval是用来获取页面内容的;
const page = await browser.newPage()
await page.goto('https://www.dygod.net')
let elements = await page.$$eval('#menu li a', elements => {
// 代码在浏览器运行, 不在node中打印;
const contentArr = []
elements.forEach(item => {
contentArr.push({
href: item.getAttribute('href'),
name: item.innerText
})
})
return contentArr
})
console.log(elements)
页面点击事件
const elementHandle = await page.$$('#menu li a')
elementHandle[2].click()
搜索事件
const iptEl = await page.$('.searchl .formhue') // 找到搜索框
await iptEl.focus() // 聚焦事件:focus
await page.keyboard.type('哆啦A梦') // 输入对象:keyboard
const btnEl = await page.$('.searchr input[type="Submit"]') // 获取搜索按钮并点击
await btnEl.click()
await iptEl.dispose() // 关闭当前句柄,否则会报错丢失;
await btnEl.dispose()
或者使用:
await page.goto('https://www.baidu.com')
await page.type('#head_wrapper .soutu-env-nomac #form #kw', 'puppeteer')
await Promise.all([
page.waitForNavigation(),
page.click('#head_wrapper .s_btn', )
])
拦截network请求
由于请求一些数据导致页面加载更慢,可以中断一些请求。开启请求拦截器需要设置为true:page.setRequestInterception(true)
await page.setRequestInterception(true)
page.on('request', interceptedRequest => {
console.log(interceptedRequest.url())
if(interceptedRequest.url().endsWith('.png')){
// 中断请求
interceptedRequest.abort()
} else {
// 继续请求
interceptedRequest.continue()
}
})
await page.goto('https://chat.heny.vip')
页面内执行方法
page.evaluate(pageFunction[,...args])
:代码执行返回字符串
page.evaluateHandle(pageFunction[,...args])
:代码执行返回JSHandle
const aHandle = await page.evaluateHandle(() => document.body);
const resultHandle = await page.evaluateHandle(body => body.innerHTML, aHandle);
console.log(await resultHandle.jsonValue());
await resultHandle.dispose();
监听下载完成
下载完成相当于是一个请求完成的操作
page.on('requestfinished', request => {})
好用的api
page.close()
:关闭当前页面browser.close()
:关闭当前浏览器page.waitForSelector(selector)
:等待元素出现之后再进行操作(由于前端渲染页面,比如单页面应用,需要使用该方法等待元素出现)page.mouse
:用于移动鼠标的当前位置,可以用来选中某个区域;page.mouse.down
page.mouse.up
page.mouse.move
page.mouse.click