美文网首页移动技术
nodejs(2)-如何使用node来向其他服务器发送请求

nodejs(2)-如何使用node来向其他服务器发送请求

作者: 浪流儿 | 来源:发表于2017-11-15 14:47 被阅读0次

    ##### URL模块

    这个模块可以帮助我们解析url地址,从里面提取很多有用的内容供我们使用;

    假设这是一个url地址http://localhost:8080/a/b/c?a=1&b=2#abc,里面包含的部分:

    ```

    protocol: 'http:',

    host: 'localhost:8080',

    port: '8080',

    hostname: 'localhost',

    hash: '#abc',

    search: '?a=1&b=2',

    query: 'a=1&b=2',

    pathname: '/a/b/c',

    path: '/a/b/c?a=1&b=2',

    href: 'http://localhost:8080/a/b/c?a=1&b=2#abc'

    ```

    url.parse(urlString[, parseQueryString[, slashesDenoteHost]])

    会返回一个解析后的对象,第一个参数为要解析的url地址,第二个参数为是否将query字符串解析成对象格式,第二个参数来控制在没有协议的情况下,是否解析域名等内容

    url.format(urlObject)

    将一个url解析后的对象还原成一个url地址

    url.resolve(from, to)

    可以将我们两段url解析成一个url地址

    ```

    console.log(url.resolve('http://www.baidu.com','/api/index.html'))

    //'http://www.baidu.com/api/index.html'

    ```

    ---

    ### queryString

    可以将我们的queryString字符串(a=1&b=2&c=3)解析或反编译

    querystring.stringify(obj[, sep[, eq[, options]]]):

    可以将一个对象(键值对)解析成一个querystring,第二个参数可以设置分割符号(&),第三个参数确定键值对之间的链接符号(=)

    querystring.parse(str[, sep[, eq[, options]]])

    可以将一个qs字符串解析成一个对象,后面的参数是按照某种规则去解析

    querystring.escape(str),querystring.unescape(str)

    可以将我们的中文解析成百分号编码

    ```

    console.log(qs.escape('北京'))//%E5%8C%97%E4%BA%AC

    console.log(qs.unescape('%E5%8C%97%E4%BA%AC'))//北京

    ```

    ---

    #### http小爬虫

    ##### 首先我们先研究一下什么是SEO

    Search Engine Optimization 搜索引擎优化,是一种技术,目的是提高网页在搜索引擎的排行

    如何能提高排行:

    1. 给百度花钱

    2. 找专业的优化团队

    3. 开发过程中注意优化,例如,在不影响页面结构的情况下多使用语义化标签!img的title等也需要设置,title标签必须有,通过meta标签设置description、keywords、author;不需要使用ajax获取的数据就不要获取了,尽量可以使用服务端渲染数据的方式

    ---

    利用http.get方法去获取到某网址的html文件内容,然后利用cheerio工具进行关键内容的提取

    1. 获取到 https://www.lagou.com这个接口的数据(其实就是拉钩的首页文件)

    因为http、https模块可以向其他的服务器发送请求,依靠的是request方法或者其子方法:get、post;

    ```

    let target = 'https://www.lagou.com'

    const https = require('https')

    //发送一个get请求,res是一个返回的对象,里面并没有直接包含数据,需要使用data事件来接收返回的数据

    //且每次返回的只是一个片段,所以会触发多次,因为可能请求到的数据量特大,如果一次性返回的话可能导致服务器崩溃,所以Node采取事件的方式多次返回

    https.get(target, function(res) {

    let result = ''

    res.on("data",(chunk)=>{

    result += chunk

    })

    res.on("end",()=>{//当接收完后触发

    //在这里就可以处理数据result

    })

    })

    ```

    2. 爬取其上面的一级、二级标题的内容

    因为获取到的是一个大的html格式的字符串,所以想要爬取其中某些标签的内容不能直接使用jq,用正则匹配又有些繁琐,所以使用cheerio工具,这个工具可以在服务端将html格式的字符串进行编译后返回一个$对象,这样就可以像使用JQ一样去操作了

    ```

    const cheerio = require("cheerio")

    let spideContent = (result,callback)=>{

    let $ = cheerio.load(result)

    let menus = []

    $(".menu_main").each(function (i) {

    let title = $(this).find('h2').text().trim()

    let navs = Array.prototype.slice.call($(this).find('a')).map((item)=>{

    return $(item).text()

    })

    menus.push({title,navs})

    })

    callback(menus)//通过回调函数来处理解析后的数据

    }

    ```

    3.  再把爬取出的内容存到一个文件里

    ```

    spideContent(result,(menus)=>{

    fs.writeFileSync('./lagou.json',JSON.stringify(menus))

    })

    ```

    ##### JS小知识扩展

    如何将伪数组转换成真正的数组?

    1. 常见的伪数组都有哪些?arguments、通过document.getElements..获取到的内容;

    2. 伪数组有什么特点,具有length属性,也是一个一个的元素组成的,但是构造器不是Array,不能使用数组的方法

    3. 转换为真正数组的方法:

    通过遍历将伪数组里元素放入到一个新的数组里

    ```

    let arg = arguments//这就是一个典型的伪数组

    let arr = []

    for (var i = 0; i < arg.length; i++) {

    arr.push(arg[i])

    }

    console.log(arr)

    ```

    通过call改变数组slice方法里的this指向

    因为我想要让伪数组也能使用数组的方法,为什么伪数组就不能使用数组方法,为什么数组就能使用push方法了

    一个数组都是由它的构造器实例化出来的,var a = []//这是js的语法糖;正规的用法:var a = new Array()

    因为Array是一个构造函数,每一个构造函数都有原型,且构造函数构造出来的实例可以使用原型上的方法,也就是说因为Array的原型上有一些方法,所以每一个数组都可以使用这些push等等的方法

    因为伪数组的构造器不是Array,当然不能使用Array原型上的push方法

    现在数组有一个方法slice,这个方法每次都会返回一个新数组,如果不传参数的话,返回的新数组的元素和原数组的元素是一模一样的

    如果伪数组也能执行这个slice方法的话,那么是不是就会返回一个新的真正的数组,并且元素一样,但是不能直接执行

    所以我们使用偷梁换柱的方法,让一个真正的数据,或者直接从Array.prototype上执行slice方法,但是在执行的时候通过call来将里面的this换成咱们的伪数组,这样的话,就会返回一个元素和伪数组元素一样的真正数组了

    ```

    let arr = [].slice.call(arg) //Array.prototype.slice.call(arg)

    ```

    ---

    ##### requestGet/requestPost

    1. 通过request来get数据(请求的是豆瓣电影的api):

    ```

    let target = 'http://api.douban.com/v2/movie/in_theaters'

    const http = require('http')

    const url_info = require('url').parse(target,true)

    //定义配置选项

    let options = {

    hostname: url_info.hostname,//要请求的接口的域名

    port: url_info.port||80,

    path: url_info.pathname,

    method: 'GET'

    };

    //创建一个请求的对象

    var req = http.request(options, function(res) {//回调函数能接收到响应对象

    //状态码 res.statusCode

    //响应头 res.headers

    res.setEncoding('utf8');//设置字符编码

    let result = ''

    res.on('data', function (chunk) {//通过data事件来接收数据

    result+=chunk

    });

    res.on('end', function () {//接收完成后触发

    fs.writeFileSync('./movie.json',result)

    });

    });

    //绑定error事件,如果出错会执行

    req.on('error', function(e) {

    console.log('problem with request: ' + e.message);

    });

    //标识请求完成

    req.end();

    ```

    2. 通过request的post方法来请求:

    注意,get方法发送的参数是拼接在url上的,post是以formdata存在的,但是发送过去的必须都得是字符串格式

    大部分步骤基本一样,但是需要注意的是,post请求的时候需要设置请求头里的Content-Length,需要通过req.write方法来写入请求信息

    ```

    const target = 'http://post.baibaoyun.com/api/0a953068ff01781ce22c0822c075018c'

    const qs = require('querystring')

    const http = require('http')

    let url_info = require('url').parse(target)

    //定义好要发送的数据

    var postData = qs.stringify({

    'a':'text1',

    'b':'text2'

    });//必须变成这样的格式 'a=text1&b=text2'

    var options = {

    hostname: url_info.hostname,

    port: url_info.port||80,

    path: url_info.pathname,

    method: 'POST',

    headers: {

    'Content-Type': 'application/x-www-form-urlencoded',

    'Content-Length': postData.length//post发送的时候需要将请求头的Content-Length设置为发送数据的leng

    }

    };

    var req = http.request(options, function(res) {

    res.setEncoding('utf8');

    let result = ''

    res.on('data', function (chunk) {

    result+=chunk

    });

    res.on('end', function () {

    console.log(result)

    });

    });

    req.on('error', function(e) {

    console.log('problem with request: ' + e.message);

    });

    //写入请求发送的数据

    req.write(postData);

    req.end();

    ```

    ###### 小作业

    总结POST和GET的区别,每位同学都写一个md文档

    ---

    ##### fileStystem模块

    后端语言都有操作文件系统的能力,在nodejs里我们依靠的是fs模块

    每种操作的方法基本都有同异步的两种不同方法

    1.查看文件信息(多用来判断文件是否存在)exists

    ```

    var fs=require('fs');

    //异步查询文件信息

    fs.stat("../sources/temp.txt",(err,data)=>{

    if(err){

    console.log(err);

    }else{

    console.log(data)

    //判断是否是文件

    console.log(`文件:${data.isFile()}`)

    //判断是否是路径

    console.log(`目录:${data.isDirectory()}`)

    }

    })

    //同步查询

    //fs.statSync("../sources/temp.txt")

    console.log(1)

    ```

    2.创建一个目录

    ```

    //创建一个目录,如果目录已存在的话就会返回错误信息

    fs.mkdir("logs",function(err){

    if(err){

    console.log(err);

    }else{

    console.log('success');

    }

    })

    ```

    3.写入文件

    ```

    //给文件写内容,当文件不存在会创建一个文件,第二个参数为写入的内容,每次写入都会覆盖

    fs.writeFile('logs/hello.log','hello everyone\n',function(err){

    if(err){

    console.log(err);

    }else{

    console.log('success')

    }

    })

    //给文件中追加内容

    fs.appendFile("logs/hello.log",'hello world\n',function(err){

    if(err){

    console.log(err);

    }else{

    console.log('success')

    }

    })

    ```

    4.读取文件内容

    ```

    //读取文件内容的方法,第二个参数可选,为读取的编码格式

    fs.readFile("logs/hello.log",'utf-8',function(err,data){

    if(err){

    console.log(err);

    }else{

    console.log(data)

    }

    })

    ```

    5.读取目录内容

    ```

    //读取目录内容,返回一个数组

    fs.readdir("logs",function(err,files){

    if(err){

    console.log(err);

    }else{

    console.log(files)

    }

    })

    ```

    6.文件重命名

    ```

    //重命名方法

    fs.rename("logs/hello.log","logs/world.log",function(err){

    if(err){

    console.log(err)

    }else{

    console.log('success')

    }

    })

    ```

    7.删除目录、文件

    fs.rmdir可以删除目录但是,必须是空目录,fs.unlink可以删除文件,如果我们要删除一个目录及它下面的文件或子目录的话,我们需要先读取出来,删除完成后再进行根目录的删除

    8.小练习:创建一个copy复制文件的函数

    ```

    const fs = require('fs')

    const _path = require('path')

    let copy = (path,target)=>{

    fs.stat(path,(err)=>{

    if(err){

    console.log('要复制的文件不存在')

    }else{

    let content = fs.readFileSync(path)

    fs.writeFile(target+'/'+_path.basename(path).replace('.','-副本.'),content,(err)=>{

    if(err){console.log('目标目录不存在')}else{

    console.log('success')

    }

    })

    }

    })

    }

    copy('./sources/hello.txt','./sources/a')

    ```

    9.fs-extra模块

    这是一个第三方的fs模块,需要下载  npm install fs-extra

    fs模块上的方法它都有,并且还封装了一些很好用的方法,比如:copy、remove..

    [文档地址](https://www.npmjs.com/package/fs-extra)

    ###### ES6小知识

    Object.assign方法可以将一些对象中的属性和方法扩展到某一个对象上

    ```

    var a = {y:2}

    var b ={x:1}

    var c = {z:3}

    Object.assign(a,b,c)

    console.log(a)//{x:1,y:2,z:3}

    ```

    ---

    相关文章

      网友评论

        本文标题:nodejs(2)-如何使用node来向其他服务器发送请求

        本文链接:https://www.haomeiwen.com/subject/rqacvxtx.html