爬虫基础知识

时间:2022-12-03 07:20:32

一、Scrapy

1、cookie设置

目前cookie的设置不支持在headers进行设置, 需要通过以下三种方式进行设置:
第一种:setting文件中设置cookie

  • COOKIES_ENABLED是注释的时候,scrapy默认没有开启cookie。
  • COOKIES_ENABLED没有注释设置为False的时候,scrapy默认使用了settings里面的cookie。
  • COOKIES_ENABLED设置为True的时候,scrapy就会把settings的cookie关掉,使用自定义cookie。

注意:

  • 当使用settings的cookie的时候,又把COOKIES_ENABLED设置为True,scrapy就会把settings的cookie关闭,而且也没使用自定义的cookie,会导致整个请求没有cookie,导致获取数据失败。
  • 如果使用自定义cookie就把COOKIES_ENABLED设置为True
  • 如果使用settings的cookie就把COOKIES_ENABLED设置为False

第二种:middlewares中设置cookie
在middlewares中的downloadermiddleware中的process_request中配置cookie,配置如下:

request.cookies=
{'Hm_lvt_a448cb27ae2acb9cdb5f92e1f0b454f3': '1665643660', 
' _ga': 'GA1.1.755852642.1665643660'
}

注意:cookie内容要以键值对的形式存在
第三种:在spider爬虫主文件中,重写start_request方法,在scrapy的Request函数的参数中传递cookies
重载start_requests方法

   def start_requests(self):
       headers = {
                   "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) Gecko/20100101 Firefox/44.0"
                   }
       # 指定cookies
       cookies = 
       {
       'Hm_lvt_a448cb27ae2acb9cdb5f92e1f0b454f3': '1665643660', 
       ' _ga': 'GA1.1.755852642.1665643660'
       }

2、Get请求带参数

yield scrapy.FormRequest(
    url=url,
    method='GET',
    formdata=params,
    callback=self.parse_result
)

3、 item数据只有最后一条

只显示主页数据中爬到的最后一条数据,其他都正常
爬虫基础知识
这是我对标签进行遍历时,将item对象放置在了for循环的外部。修改代码就好
修改前:
爬虫基础知识
修改后:
爬虫基础知识
成功
爬虫基础知识
scrapy中的yield scrapy.Request 在传递item 的注意点, 或者使用deepcopy

4、start_requests或者start_urls多个请求只请求第一个

默认情况下,scrapy防止重复请求。由于在起始url中只有参数不同,scrapy会将起始url中的其余url视为第一个url的重复请求。这就是为什么你的spider在获取第一个url后停止。为了解析其余的url,我们在scrapy请求中启用了dont_filter标志。
修改前:

    def start_requests(self):
        for i in range(10):
            yield scrapy.Request('https://baidu.com', self.parse, meta={"seq": i})

修改后:

    def start_requests(self):
        for i in range(10):
            yield scrapy.Request('https://baidu.com', self.parse, meta={"seq": i}, dont_filter=True)

5、数据流

爬虫基础知识
Scrapy中的数据流是由执行引擎控制的,它是这样的:

  1. Engine <component-engine>方法获取要来自Spider <component-spiders>爬取的初始请求。
  2. Engine <component-engine> 将请求交给Scheduler <component-scheduler> 调度,并向Scheduler <component-scheduler> 索取下一个抓取请求。
  3. Scheduler <component-scheduler> 从队列中返回下一个请求给Engine <component-engine>
  4. Engine <component-engine> 通过Downloader middleware <component-download -middleware将请求发送给Downloader <component-downloader>
  5. 一旦页面完成下载,Downloader <component-downloader> 生成一个响应(带有该页面)并将其发送给引擎,传递给Downloader middleware <component-download -middleware
  6. Engine <component-engine> Downloader <component-downloader> 接收响应,并将其通过Spider Middleware <component- Spider Middleware发送到Spider <component- Spider > 进行处理。
  7. Spider <component- Spider > 处理响应,并通过Spider Middleware <component- Spider MiddlewareEngine <component-engine>返回抓取items和新请求。
  8. Engine <component-engine> 将已处理的items发送到Item pipeline <component-pipeline > ,然后将已处理的请求发送到Scheduler <component-scheduler> ,并请求可能的下一个请求进行爬取。
  9. 该过程重复(从步骤3开始),直到不再有来自Scheduler <component-scheduler> 的请求。

6、组件

Scrapy Engine
引擎负责控制系统所有组件之间的数据流,并在某些操作发生时触发事件。

Scheduler
scheduler <topics-scheduler> 从引擎接收请求,并将它们入队列,以便在引擎请求它们时稍后提供它们(也提供给引擎)。

Downloader
Downloader负责获取网页并将其提供给引擎,而引擎又将其提供给spiders。

Spiders
spider是由Scrapy用户编写的自定义类,用于解析响应并从中提取items <topics-items>或要发送的其他请求。

Item Pipeline
The Item Pipeline负责处理被spiders提取(或刮取)的items。典型的任务包括清理、验证和持久化(比如将items存储在数据库中)。

Downloader middlewares
下载器中间件是位于引擎和下载器之间的特定钩子,当请求从引擎传递到下载器时处理请求,并处理从下载器传递到引擎的响应。
如果需要执行以下操作之一,请使用Downloader中间件:

  • 在请求被发送到Downloader之前处理它(即在Scrapy将请求发送到网站之前)。
  • 发送给spider之前更改响应。
  • 发送一个新的Request,而不是将收到的响应传递给spider
  • 在不获取网页的情况下将响应传递给爬行器
  • 默默地放弃一些请求。

Spider middlewares
Spider middlewares是位于引擎和Spiders之间的特定钩子,能够处理spider输入(responses)和输出(items 和 requests)。
如果有以下需要,可以使用Spider中间件:

  • spider回调输出的后处理,更改、增加、删除请求或items。
  • start_requests的后处理。
  • spider的异常处理。
  • 根据响应内容为某些请求调用errback而不是回调。

二、代码断点

1、网站代码运行的时间轴

加载html、加载js --> 运行js初始化 --> 用户触发了某个事件 -->调用某断js --> 明文数据–> 加密函数 -->加密数据–>给服务器发信息(XHR-SEND)–>接收到服务器数据 -->解密函数–>刷新网页渲染

2、常用断点

  • DOM
    • 定位比较准
    • 执行比较靠前
    • 加密函数比较远
    • 我们无法根据栈快速定位
  • DOM事件
    • 如果DOM断点不能下,就可以用DOM事件,和DOM端点特性一致。可以根据事件,例如:搜索、提交按钮定位js代码
  • XHR
    • 执行比较靠后,距离加密函数相对较近,可以根据栈快速定位
    • 非xhr发送的就无法断点
  • 代码行
  • 代码中debugger
  • 全局事件(浏览器事件)
  • 异常捕获
    • 处理try的时候

三、加解密

1、流程

抓包 -> 调试 -> 扣取js ->改写 -> 本地运行值

2、常见的加密方式

2.1 取盐校验(不可逆)

- md5、md2、md4、带密码的md5(hmac)
	- 	md5:16位、32位、40位
- sha1、sha256、sha512
	- sha  :40位、64位、128位

2.2 对称加密 (可逆)

(1)AES

  • 预备知识

    AES加密 — 详解
    在线解密or加密地址

  • 代码测试:
    js实现AES加密
    安装:npm i crypto-js

    let str = '****';// 需要加密的字符串
    let keyStr = '****';// 密钥
    let ivStr = '****';// iv偏移量
    const key = CryptoJS.enc.Utf8.parse(keyStr);  // 十六位十六进制数作为密钥
    const iv = CryptoJS.enc.Utf8.parse(ivStr);   // 十六位十六进制数作为密钥偏移量
    let srcs = CryptoJS.enc.Utf8.parse(str);
    let encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
    let appKey = encrypted.toString();//加密后的信息
    
  • 线上测试
    加密
    爬虫基础知识
    解密
    爬虫基础知识

(2)DES
(3)3DES

2.3 非对称加密 (可逆)

- RSA (公钥和私钥)同一个明文可以生成不同的密文

3、常见JS混淆

  • eval
  • 混淆AA和OO
  • 混淆JJ
  • 混淆FuckJS

四、Webpack

1、什么是 chunk-vendors.js 文件?

chunk-vendors.js,顾名思义,是所有不属于您自己,而是来自其他方的模块的捆绑包 。它们被称为第三方模块,或 vendor 模块。通常,它意味着(仅和)来自您项目的 /node_modules 目录的所有模块。在 webpack 3 中,你必须自己做,你必须做一些样板文件才能拥有至少 2 个 block :一个用于您自己的代码,一个用于 /node_modules中的模块目录。
在 webpack 4 中,这很简单:你使用 optimization.splitChunks默认的 options:

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          chunks: 'async',
          minSize: 30000,
          maxSize: 0,
          minChunks: 1,
          maxAsyncRequests: 5,
          maxInitialRequests: 3,
          automaticNameDelimiter: '~',
          name: true,
          cacheGroups: {
            vendors: {
              test: /[\\/]node_modules[\\/]/, // this is what you are looking for
              priority: -10
            },
            default: {
              minChunks: 2,
              priority: -20,
              reuseExistingChunk: true
            }
          }
        }
      }
    };

五、js基础知识

1、闭包

(function (i)
{
    console.log(i)
})(1)

参考: js 【详解】闭包

2、内部函数外部调用

var outer;
(function ()
{   
    function inner(){
        console.log("inner method")
    }
    outer = inner
})()
console.log(outer())

思路: 在外面定义全局变量,将内部函数赋值给全局变量。
用途:很多加密函数可能会在函数内部,需要在外部调用

参考资料

https://www.jianshu.com/p/de3e0ed0c26b
https://blog.csdn.net/holmes369/article/details/104477183/
https://github.com/scrapy/scrapy/blob/master/docs/topics/architecture.rst
https://www.jianshu.com/p/8824623b551c
https://blog.csdn.net/zhaoyanjun6/article/details/120285594
https://www.coder.work/article/6855114
https://blog.csdn.net/qq_41293573/article/details/122697084