【爬虫开发】爬虫开发从0到1全知识教程第8篇:反爬与反反爬,JS的解析【附代码文档】_数据

本教程的知识点为:爬虫概要 爬虫基础 爬虫概述 知识点: 1. 爬虫的概念 requests模块 requests模块 知识点: 1. requests模块介绍 1.1 requests模块的作用: 数据提取概要 数据提取概述 知识点 1. 响应内容的分类 知识点:了解 响应内容的分类 Selenium概要 selenium的介绍 知识点: 1. selenium运行效果展示 1.1 chrome浏览器的运行效果 Selenium概要 selenium的其它使用方法 知识点: 1. selenium标签页的切换 知识点:掌握 selenium控制标签页的切换 反爬与反反爬 常见的反爬手段和解决思路 学习目标 1 服务器反爬的原因 2 服务器常反什么样的爬虫 反爬与反反爬 验证码处理 学习目标 1.图片验证码 2.图片识别引擎 反爬与反反爬 JS的解析 学习目标: 1 确定js的位置 1.1 观察按钮的绑定js事件 Mongodb数据库 介绍 内容 mongodb文档 mongodb的简单使用 Mongodb数据库 介绍 内容 mongodb文档 mongodb的聚合操作 Mongodb数据库 介绍 内容 mongodb文档 mongodb和python交互 scrapy爬虫框架 介绍 内容 scrapy官方文档 scrapy的入门使用 scrapy爬虫框架 介绍 内容 scrapy官方文档 scrapy管道的使用 scrapy爬虫框架 介绍 内容 scrapy官方文档 scrapy中间件的使用 scrapy爬虫框架 介绍 内容 scrapy官方文档 scrapy_redis原理分析并实现断点续爬以及分布式爬虫 scrapy爬虫框架 介绍 内容 scrapy官方文档 scrapy的日志信息与配置 利用appium抓取app中的信息 介绍 内容 appium环境安装 学习目标

完整笔记资料代码: https://gitee.com/yinuo112/Backend/tree/master/爬虫/爬虫开发从0到1全知识教程/note.md

感兴趣的小伙伴可以自取哦~

全套教程部分目录:

【爬虫开发】爬虫开发从0到1全知识教程第8篇:反爬与反反爬,JS的解析【附代码文档】_python_02

【爬虫开发】爬虫开发从0到1全知识教程第8篇:反爬与反反爬,JS的解析【附代码文档】_python_03


部分文件图片:

【爬虫开发】爬虫开发从0到1全知识教程第8篇:反爬与反反爬,JS的解析【附代码文档】_爬虫_04

反爬与反反爬

本阶段主要学习爬虫的反爬及应对方法。

JS的解析

学习目标:
  1. 了解 定位js的方法
  2. 了解 添加断点观察js的执行过程的方法
  3. 应用 js2py获取js的方法
1 确定js的位置

对于前面人人网的案例,我们知道了url地址中有部分参数,但是参数是如何生成的呢?

毫无疑问,参数肯定是js生成的,那么如何获取这些参数的规律呢?通过下面的学习来了解

1.1 观察按钮的绑定js事件

【爬虫开发】爬虫开发从0到1全知识教程第8篇:反爬与反反爬,JS的解析【附代码文档】_python_05

通过点击按钮,然后点击Event Listener,部分网站可以找到绑定的事件,对应的,只需要点击即可跳转到js的位置

1.2 通过search all file 来搜索

部分网站的按钮可能并没有绑定js事件监听,那么这个时候可以通过搜索请求中的关键字来找到js的位置,比如livecell

【爬虫开发】爬虫开发从0到1全知识教程第8篇:反爬与反反爬,JS的解析【附代码文档】_后端_06

点击美化输出选项

【爬虫开发】爬虫开发从0到1全知识教程第8篇:反爬与反反爬,JS的解析【附代码文档】_python_07

可以继续在其中搜索关键字

【爬虫开发】爬虫开发从0到1全知识教程第8篇:反爬与反反爬,JS的解析【附代码文档】_后端_08

2 观察js的执行过程

找到js的位置之后,我们可以来通过观察js的位置,找到js具体在如何执行,后续我们可以通过python程序来模拟js的执行,或者是使用类似js2py直接把js代码转化为python程序去执行

观察js的执行过程最简单的方式是添加断点

【爬虫开发】爬虫开发从0到1全知识教程第8篇:反爬与反反爬,JS的解析【附代码文档】_后端_09

添加断点的方式:在左边行号点击即可添加,对应的右边BreakPoints中会出现现有的所有断点

添加断点之后继续点击登录,每次程序在断点位置都会停止,通过如果该行有变量产生,都会把变量的结果展示在Scoope中

在上图的右上角有1,2,3三个功能,分别表示:

- 1:继续执行到下一个断点
- 2:进入调用的函数中
- 3:从调用的函数中跳出来
  • 1.
  • 2.
  • 3.
3 js2py的使用

在知道了js如何生成我们想要的数据之后,那么接下来我们就需要使用程序获取js执行之后的结果了

3.1 js2py的介绍

js2py是一个js的翻译工具,也是一个通过纯python实现的js的解释器,[github上源码与示例](

3.2 js的执行思路

js的执行方式大致分为两种:

  1. 在了解了js内容和执行顺序之后,通过python来完成js的执行过程,得到结果
  2. 在了解了js内容和执行顺序之后,使用类似js2py的模块来执js代码,得到结果

但是在使用python程序实现js的执行时候,需要观察的js的每一个步骤,非常麻烦,所以更多的时候我们会选择使用类似js2py的模块去执行js,接下来我们来使用js2py实现人人网登录参数的获取

3.3 具体的实现

定位进行登录js代码

formSubmit: function() {
        var e, t = {};
        $(".login").addEventListener("click", function() {
            t.phoneNum = $(".phonenum").value,
            t.password = $(".password").value,
            e = loginValidate(t),
            t.c1 = c1 || 0,
            e.flag ? ajaxFunc("get", " "", function(e) {
                var n = JSON.parse(e).data;
                if (0 == n.code) {
                    t.password = t.password.split("").reverse().join(""),
                    setMaxDigits(130);
                    var o = new RSAKeyPair(n.e,"",n.n)
                      , r = encryptedString(o, t.password);
                    t.password = r,
                    t.rKey = n.rkey
                } else
                    toast("公钥获取失败"),
                    t.rKey = "";
                ajaxFunc("post", " t, function(e) {
                    var e = JSON.parse(e).logInfo;
                    0 == e.code ? location.href = localStorage.getItem("url") || "" : toast(e.msg || "登录出错")
                })
            }) : toast(e.msg)
        })
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
从代码中我们知道:
  1. 我们要登录需要对密码进行加密和获取rkey字段的值
  2. rkey字段的值我们直接发送请求rkey请求就可以获得
  3. 密码是先反转然后使用RSA进行加密, js代码很复杂, 我们希望能通过在python中执行js来实现
实现思路:
  1. 使用session发送rKey获取登录需要信息

    • url: [
    • 方法: get
  2. 根据获取信息对密码进行加密 2.1 准备用户名和密码

2.2 使用js2py生成js的执行环境:context

2.3 拷贝使用到js文件的内容到本项目中

2.4 读取js文件的内容,使用context来执行它们

2.5 向context环境中添加需要数据

2.6 使用context执行加密密码的js字符串

2.7 通过context获取加密后密码信息

  1. 使用session发送登录请求

    • URL: [
    • 请求方法: POST
    • 数据:

    phoneNum: xxxxxxx
    password: (加密后生产的)
    c1: 0
    rKey: rkey请求获取的

    
    
    
    
    
    
    
    
    ##### 具体代码
    
    
    
    
    需要提前下载几个js文件到本地:
    > 
    BigInt.js
    
    RSA.js
    
    Barrett.js
    
    ```python
    import requests
    import json
    import js2py
    
    
    
    # - 实现思路:
    
    
    
    
    #   - 使用session发送rKey获取登录需要信息
    
    
    
    
    #     - url: 
    
    
    
    
    #     - 方法: get
    
    
    
    
    #  获取session对象
    
    
    session = requests.session()
    headers = {
     "User-Agent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Mobile Safari/537.36",
     "X-Requested-With": "XMLHttpRequest",
     "Content-Type":"application/x-www-form-urlencoded"
    }
    
    
    # 设置session的请求头信息
    
    
    session.headers = headers
    
    response = session.get("
    
    
    # print(response.content.decode())
    
    
    n = json.loads(response.content)['data']
    
    
    
    #   - 根据获取信息对密码进行加密
    
    
    
    
    #     - 准备用户名和密码
    
    
    phoneNum = "131..."
    password = "****"
    
    
    #     - 使用js2py生成js的执行环境:context
    
    
    context = js2py.EvalJs()
    
    
    #     - 拷贝使用到js文件的内容到本项目中
    
    
    
    
    #     - 读取js文件的内容,使用context来执行它们
    
    
    with open("BigInt.js", 'r', encoding='utf8') as f:
     context.execute(f.read())
    
    with open("RSA.js", 'r', encoding='utf8') as f:
     context.execute(f.read())
    with open("Barrett.js", 'r', encoding='utf8') as f:
     context.execute(f.read())
    
    
    
    
    # - 向context环境中添加需要数据
    
    
    context.t = {'password': password}
    context.n = n
    
    
    #     - 执行加密密码的js字符
    
    
    js = '''
        t.password = t.password.split("").reverse().join(""),
        setMaxDigits(130);
        var o = new RSAKeyPair(n.e,"",n.n)
         , r = encryptedString(o, t.password);
       '''
    context.execute(js)
    
    
    # - 通过context获取加密后密码信息
    
    
    
    
    # print(context.r)
    
    
    password = context.r
    
    
    #   - 使用session发送登录请求
    
    
    
    
    #     - URL: 
    
    
    
    
    #     - 请求方法: POST
    
    
    
    
    #     - 数据:
    
    
    
    
    #       - phoneNum: 15565280933
    
    
    
    
    #       - password: (加密后生产的)
    
    
    
    
    #       - c1: 0
    
    
    
    
    #       - rKey: rkey请求获取的
    
    
    data = {
     'phoneNum': '131....',
     'password': password,
     'c1':0,
     'rKey':n['rkey']
    }
    
    
    
    # print(session.headers)
    
    
    response = session.post(" data=data)
    print(response.content.decode())
    
    
    
    # 访问登录的资源
    
    
    response = session.get("
    print(response.content.decode())
    
    • 1.
    • 2.
    • 3.
    • 4.
    • 5.
    • 6.
    • 7.
    • 8.
    • 9.
    • 10.
    • 11.
    • 12.
    • 13.
    • 14.
    • 15.
    • 16.
    • 17.
    • 18.
    • 19.
    • 20.
    • 21.
    • 22.
    • 23.
    • 24.
    • 25.
    • 26.
    • 27.
    • 28.
    • 29.
    • 30.
    • 31.
    • 32.
    • 33.
    • 34.
    • 35.
    • 36.
    • 37.
    • 38.
    • 39.
    • 40.
    • 41.
    • 42.
    • 43.
    • 44.
    • 45.
    • 46.
    • 47.
    • 48.
    • 49.
    • 50.
    • 51.
    • 52.
    • 53.
    • 54.
    • 55.
    • 56.
    • 57.
    • 58.
    • 59.
    • 60.
    • 61.
    • 62.
    • 63.
    • 64.
    • 65.
    • 66.
    • 67.
    • 68.
    • 69.
    • 70.
    • 71.
    • 72.
    • 73.
    • 74.
    • 75.
    • 76.
    • 77.
    • 78.
    • 79.
    • 80.
    • 81.
    • 82.
    • 83.
    • 84.
    • 85.
    • 86.
    • 87.
    • 88.
    • 89.
    • 90.
    • 91.
    • 92.
    • 93.
    • 94.
    • 95.
    • 96.
    • 97.
    • 98.
    • 99.
    • 100.
    • 101.
    • 102.
    • 103.
    • 104.
    • 105.
    • 106.
    • 107.
    • 108.
    • 109.
    • 110.
    • 111.
    • 112.
    • 113.
    • 114.
    • 115.
    • 116.
    • 117.
    • 118.
    • 119.
    • 120.
    • 121.
    • 122.
    • 123.
    • 124.
    • 125.
    • 126.
    • 127.
    • 128.
    • 129.
    • 130.
    • 131.
    • 132.
    • 133.
    • 134.
    • 135.
    • 136.
    • 137.
    • 138.
    • 139.
    • 140.
    • 141.
    • 142.
    • 143.
    • 144.
    • 145.
    • 146.
    • 147.
    • 148.
    • 149.
    • 150.
    • 151.
    • 152.
    • 153.
    • 154.
    • 155.
    • 156.
    • 157.
    • 158.
    • 159.
    • 160.
    • 161.
    • 162.
    • 163.
    • 164.
    • 165.
    • 166.
    • 167.
    • 168.
    • 169.
    • 170.
    • 171.
    • 172.
    • 173.
    • 174.
    • 175.
    • 176.
    • 177.
    • 178.
    • 179.
    • 180.
    • 181.
    • 182.
    • 183.
    • 184.
    • 185.
    • 186.
    • 187.
    • 188.
    • 189.
    • 190.
    • 191.
    • 192.
    • 193.
    • 194.
    • 195.
    • 196.
    • 197.
    • 198.
    • 199.
    • 200.
    • 201.

    小结
    1. 通过在chrome中观察元素的绑定事件可以确定js

    2. 通过在chrome中search all file 搜索关键字可以确定js的位置

    3. 观察js的数据生成过程可以使用添加断点的方式观察

    4. js2py的使用

      • 需要准备js的内容
      • 生成js的执行环境
      • 在执行环境中执行js的字符串,传入数据,获取结果

    Mongodb数据库

    介绍

    在前面的中我们学习了mysql这种关系型数据库,那么接下来,我们会来学习一种非关系型数据库mongodb,mongodb数据库主要用于海量存储,常被用在数据采集项目中。

    内容

    • mongodb的介绍和安装
    • mongodb的简单使用
    • mongodb的增删改查
    • mongodb的聚合操作
    • mongodb的索引操作
    • mongodb的权限管理
    • mongodb和python交互(pymongo模块)

    mongodb文档

    [

    Mongodb的介绍和安装

    学习目标
    1. 了解 非关系型数据库的优势
    2. 了解 mongodb的安装

    1. mongodb的介绍
    1.1 什么是mongodb
    • mongodb 是一个功能最丰富的NoSQL非关系数据库。由 C++ 语言编写。
    • mongodb 本身提供S端存储数据,即server;也提供C端操作处理(如查询等)数据,即client。
    1.2 SQL和NoSQL的主要区别
    • 在SQL中层级关系: 数据库>表>数据
    • 而在NoSQL中则是: 数据库>集合>文档
    1.2.1 数据之间无关联性
    • SQL中如何需要增加外部关联数据的话,规范化做法是在原表中增加一个外键,关联外部数据表。
    • NoSQL则可以把外部数据直接放到原数据集中,以提高查询效率。缺点也比较明显,对关联数据做更新时会比较麻烦。
    • SQL中在一个表中的每条数据的字段是固定的。而NoSQL中的一个集合(表)中的每条文档(数据)的key(字段)可以是互不相同的。
    1.2.2 拓展阅读

    [

    1.3 mongodb作为非关系型数据库相较于关系型数据库的优势

    易扩展: NoSQL数据库种类繁多, 但是一个共同的特点都是去掉关系数据库的关系型特性。 数据之间无关系, 这样就非常容易扩展

    大数据量,高性能: NoSQL数据库都具有非常高的读写性能, 尤其在大数据量下表现优秀。 这得益于它的非关系性,数据库的结构简单

    灵活的数据模型: NoSQL无需事先为要存储的数据建立字段, 随时可以存储自定义的数据格式。 而在关系数据库中, 增删字段是一件非常麻烦的事情。 如果是非常大数据量的表, 增加字段简直就是一个噩梦

    2. mongodb的安装

    以ubuntu18.04为例

    mongodb具有两种安装方式:命令安装 或 源码安装

    2.1 命令安装

    在ubuntu中使用apt-get工具安装

    sudo apt-get install -y mongodb-org
    
    • 1.

    或参考官方文档 [

    2.2 源码安装
    2.2.1 选择相应版本和操作系统并下载

    [

    2.2.2 解压

    tar -zxvf mongodb-linux-x86_64-ubuntu1804-4.0.3.tgz

    2.2.3 移动到/usr/local/目录下

    sudo mv -r mongodb-linux-x86_64-ubuntu1804-4.0.3/ /usr/local/mongodb

    2.2.4 在shell的初始化脚本.bashrc中添加mongodb可执行文件到环境变量PATH中

    a. 进入.bashrc文件中

    cd ~
    sudo vi .bashrc
    
    • 1.
    • 2.

    b. 在.bashrc文件的最后添加:

    export PATH=/usr/local/mongodb/bin:$PATH
    
    • 1.
    3. mongodb的官方文档

    [


    小结

    1. 了解 非关系型数据库的优势

      • 易扩展
      • 高性能
      • 灵活的数据字段
    2. 了解 mongodb的安装

      • sudo apt-get install -y mongodb-org