前端社团程序员

Nodejs爬虫——机票查询学习笔记(1).md

2017-03-20  本文已影响148人  ccminn

2017.3.6 - 3.17

学习内容:

详细笔记:

1. 基本想法

nodejs项目通过superagent模块包向网站发起有(或无)参数的get/post请求,获取目标网页的html源代码
——>使用cherrio模块包分析前一步抓取的html,使用方法类似Jquery
——>保存json数据到文本

2. superagent模块接口整理

参考文献:superagent文档 整理稿
一个用于发起get/post请求的https模块包

3. cherrio模块接口整理

一个用于抓取当前页面信息的模块包

4. 简单抓取页面信息的核心代码 ——————挖掘Cnode首页
//通过get请求抓取
router.get('/', function(req, res, next) {
    superAgent.get('https://cnodejs.org/')
      .end(function (err, sres) {
        if(err){
          return next(err);
        }
        // sres.text 里面存储着网页的 html 内容,将它传给 cheerio.load 之后
        // 就可以得到一个实现了 jquery 接口的变量,我们习惯性地将它命名为 `$`
        var $ = cherrio.load(sres.text);
        var items = [];
        $('#topic_list .topic_title').each(function (idx, element) {
          // 对每一个查找到的结果(idx, element),存入items数组Ø中
          var $element = $(element);
          items.push({
                  title: $element.attr('title'),
                  href: $element.attr('href'),
                });
        });
        res.send(items);
      })
});  
5. js变量声明提升,赋值不提升

参考博客:js中的变量提升hoisting
总结:
JavaScript是函数级作用域(function-level scope)。只有在函数中才会创建新的作用域(适用局部变量)。

// 初始代码
var v='Hello World';
(function(){
    alert(v);
    var v='I love you';
})()
// 运行结果  : 弹出 undefined
// 实际运行过程
var v='Hello World';
(function(){
    var v;              //变量声明被提升
    alert(v);
    v='I love you';     //变量赋值未提升
})()
//对于函数级作用域的理解
function foo() {
    var x = 1;
    if (x) {
        (function () {
            var x = 2;
            // some other code
        }());
    }
    // x is still 1.     //匿名函数中的作用域与foo函数的作用域无关
}
6. eventproxy模块包API整理

一个用于监听多个函数并发执行的模块报(类似于计数器,等所有监听事件都冒泡表示完成,在执行callback)
eventproxy——API

7. async模块API整理
8. 定时抓取补充

https://github.com/node-schedule/node-schedule

9. jqury的API

$.map() 遍历
$.trim() 字符串去首位的空格

10. 爬虫相关的模块介绍

爬虫相关模块
express框架详细总结

11. 模拟post请求与get请求 规范整理
//模拟发起get请求
superAgent.get('http://flight.qunar.com/twell/flight/inter/search')
    .query(queryString)
    .set(headers)
    .end(function (err, res) {
        if (res.error)
            throw new Error(res.error);
        console.log(res.body);
    });

****在get请求中需要注意的地方:****  
1. 在chrome检查——network——headers中查到看的request URL要去除查询参数(?search/departCity=XXXXX等)  
2. 在.query中发送查询参数,对应的post方法则是用send(data)的方式发送参数  
//模拟发起post请求
superAgent.post('http://flights.ctrip.com/international/AjaxRequest/SearchFlights/AsyncSearchHandlerSOAII.ashx')
    .set(ctripHeaders)
    .type('form')
    .send(data)
    .end(function (err, res) {
        // res是json对象
        if (err){
            return console.error(err);
        }
        console.dir(res.body);
    })

****在post请求中的注意:****
1. 在chrome检查——network中找准发起请求的URL,并且保证req的参数完整且正确  
2. 在发送数据前通过.type('form') 声明发送数据的格式  
3. 注意返回数据的解析

json文件读写
sublime中的json格式化插件—— pretty json

遇到的问题

Q1:一个json数组在debug时,可以取到其中的值,但是在实际运行中,出现Cannot read property 'href' of undefined
A1:- id重复,找不到dom或找错dom

总结:

  1. 通过一周学习,再次理解了上一学期中易混淆未理解“异步调用”、“get/post请求”的概念
    异步调用,依次开启多个函数入口,并发执行,返回结果顺序与入口执行顺序不一定相同,可以使用async模块包来控制异步与同步的切换。
    get请求:通过添加url中的查询参数,向当前网页发出get请求,获得返回数据,不具备保密性。相当于得到了带参数的url完整路径,就得到了这个网页的数据。
    post请求:通过某个动作(如搜索按钮、提交按钮)向服务器后台发送数据包,再收获相应数据,将得到的数据渲染到当前页面,动态生成页面,如果截取到当前网页的url只能获得一个空的HTML页面框架,不具备有价值的数据。
  1. 对于新工具的学习使用能力还要加强
    这一次的模拟请求,用到了postman这个软件+插件进行网页抓包(抓取客户端向服务器发出的请求数据包,与服务器返回的响应数据包)与发包测试(模拟发出get/post请求),在初次使用中因不太理解请求原理+不熟悉使用方法,导致在盲目测试请求时浪费了很多时间。
  2. 爬虫与反爬虫:通过对反爬虫的了解,反面思考爬虫的设计思路
    现在主流的几个反爬虫技术:
    1、限制查询频率,超过一定频率,采取封号、封IP
    2、通过图片验证码等技术识别机器查询与手工查询
    3、设计cookie值与cookie值的随机有效domain
    4、加密查询的参数
    因此通过爬去携程与去哪儿,了解了两家的反爬虫核心:
    携程
    通过post请求传输参数,发送的参数中包含"transNo"与"searchKey"两个参数,均为随机加密参数,每次查询均独立加密
携程的查询参数

去哪儿
通过get请求传输参数,查询参数中包含"es"随机参数,每一次查询都会产生不同的es参数。
因为缺少这两个加密参数,无法获取加密规则,使得我们无法爬取携程与去哪儿两大门户的机票信息,嗨呀真是太气了……

去哪儿的查询参数
上一篇 下一篇

猜你喜欢

热点阅读