飞道的博客

20. 一秒一个Token甩到前台,吓死在座的各位爬虫工程师

310人阅读  评论(0)

本篇博客是爬虫训练场中的基础反爬案例,核心实现通过动态 token 验证限制爬虫
学习过程重点是反爬思维学习

基础结构搭建

本案例依旧采用学校列表数据实现,核心要修改的文件未 school/index.py ,然后在 templates/school 目录下拷贝 ajax_list.html 进行后续修改。

index.py 文件首先编写视图函数,用于页面首次加载。

@s.route('ajax_list2')
def ajax_list2():
    page = 1  # 初始化第一页数据

    pagination = pagination_object(page)
    return render_template('school/ajax_list2.html', pagination=pagination)

此时基础结构已经搭建完毕,下面重点是前台JS代码生成 Cookie 部分逻辑。

当然,正式阅读本文前,需要梳理一下逻辑。

  1. 我们在前端通过JS生成两个 cookie 值,分别是 timestamptoken
  2. timestamp 通过 JS 获取时间戳,tokentimestamp 进行 md5 加密
  3. timestamptoken 都要发送到 Python Flask 端;
  4. Python 端校验 token 值和使用 md5 之后 timestamp 是否一致,相同返回数据,不相同返回 403。

前端 JS 生成 Cookie

JavaScript 可以使用 document.cookie 属性来设置、获取和删除 cookie。

设置 cookie 的语法如下:

document.cookie = "name=value; expires=date; path=path; domain=domain; secure";
  • name=value:这是 cookie 的名称和值。名称和值之间用等号分隔。
  • expires=date:这是 cookie 的过期日期。如果省略这个参数,那么这个 cookie 将在浏览器关闭时过期。
  • path=path:这是 cookie 可用的路径。如果省略这个参数,那么这个 cookie 在整个站点内都可用。
  • domain=domain:这是 cookie 可用的域。如果省略这个参数,那么这个 cookie 在整个站点内都可用。
  • secure:这是一个布尔值,表示这个 cookie 只能通过 HTTPS 协议传输。

下面是一个示例,设置一个名为 username 的 cookie,值为 Ca,过期日期为 7 天之后:

var expires = new Date();
expires.setTime(expires.getTime() + (7 * 24 * 60 * 60 * 1000));
document.cookie = "username=Ca; expires=" + expires.toUTCString() + "; path=/";

你还可以使用 encodeURIComponent 函数来对 cookie 的值进行编码,以便在存储时保留特殊字符:

var value = "梦想橡皮擦";
document.cookie = "username=" + encodeURIComponent(value) + "; expires=" + expires.toUTCString() + "; path=/";

要获取 cookie 的值,可以使用 getCookie 函数:

function getCookie(name) {
   
  let value = "; " + document.cookie;
  let parts = value.split("; " + name + "=");
  if (parts.length == 2) {
   
    return decodeURIComponent(parts.pop().split(";").shift());
  }
}

上述函数使用 ; 作为分隔符,将 document.cookie 分割成一个数组。然后,使用 split() 函数将每个 cookie 的名称和值分割开来。最后,使用 decodeURIComponent() 函数将值解码并返回。

删除 cookie,可以将其过期日期设置为过去的某个日期:

document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";

获取时间戳

基于这些内容,我们在 ajax_list2.html 文件中,建立一个创建 cookie 的函数。

// js 设置 cookie 值
function setCookie(key,value,day){
   
    var cookie=key+'='+encodeURIComponent(value);
    if(day>0){
   
         var date=new Date();
         date.setDate(date.getDate()+day);
         cookie+=';expires='+date;
    }
    document.cookie=cookie;
}

然后开始写入 cookie,首先获取时间戳,在 JavaScript 中,可以使用 Date.now() 方法来获取当前时间戳。

var timestamp = Date.now();

你也可以使用 performance.now() 方法来获取更高精度的时间戳。这个方法返回从页面加载开始的毫秒数。

var timestamp = performance.now();

如果你想将时间戳转换为标准日期格式,可以使用 new Date() 方法。

var date = new Date(timestamp);

这样就可以使用 date 对象的各种方法(如 getFullYeargetMonth 等)来访问年份、月份、日期等信息。

使用 CryptoJS 库来实现 MD5 哈希,生成 token

在 JavaScript 中,可以使用 CryptoJS 库来实现 MD5 哈希。

首先,需要在 HTML 中引入 CryptoJS 库:

<script src="https://cdn.jsdelivr.net/npm/crypto-js@4.0.0/crypto-js.min.js"></script>

然后,可以使用 CryptoJS.MD5() 方法来计算 MD5 哈希值。

var message = "Hello, XiangPiCa!";
var hash = CryptoJS.MD5(message);

这样就可以得到一个 CryptoJS 对象,可以使用它的各种方法(如 toStringtoHex 等)来访问哈希值。

var hashString = hash.toString();
var hashHex = hash.toHex();

接下来就可以生成 token 值,将上述内容应用到爬虫训练场案例中,示例代码如下:

// 每次间隔10秒设置 Cookie 值
setInterval(function(){
   
    // 获取当前时间戳
    var timestamp = Date.now();
    // 设置时间戳
    setCookie("timestamp",timestamp,1);
    //加密 token,由时间戳加密
    var token = CryptoJS.MD5(timestamp.toString());
    setCookie("token",token,1);
},10*1000);

代码还使用了 setInterval() 定时器函数,每间隔 10 秒写入 Cookie 值。

两个值都写入完毕,就可以在前台编写数据发送代码,发送过程要求携带 timestamptoken

    function get_data(page){
   
        // 获取存储的 cookie 值
        timestamp = getCookie("timestamp");
        token = getCookie("token");

        $.ajax({
   
            type: "get",
            url: "/ss/api_token",
            data: {
   
                page: page,
                timestamp:timestamp,
                token:token
            },
            success: function(response) {
   
                // ajax 请求成功
                render_data(response);
                // 修改分页数据
                $('.prev').attr('page',response["prev_page"]);
                $('.next').attr('page',response["next_page"]) ;
                console.log("AJAX request succeeded!");
            },
            error: function(error) {
   
                console.log("AJAX request failed: " + error);
            }
         });
    }

 

然后就是后台接口解析参数代码的编写了

Python Flask 解析参数

school/index.py 文件中,添加如下代码。

@s.route('api_token')
def token_list_school():
    page = int(request.args.get("page", 1))
    token = request.args.get("token", None)
    timestamp = request.args.get("timestamp", None)

    if token is None or timestamp is None:
        return "请求出错", 403

    # 加密 timestamp,与 token 比较
    hash = hashlib.md5()
    hash.update(timestamp.encode())
    p_token = hash.hexdigest()
    print(p_token)
    if token != p_token:
        return "请求出错", 403

    pagination = pagination_object(page)

    return jsonify(pagination)

 

其中重点要说明是的 python 生成 md5 值部分。

首先,需要导入 hashlib 模块:

import hashlib

然后,可以使用 hashlib.md5() 函数创建一个 MD5 哈希对象。

hash.update(b"Hello, XiangPiCa!")

接下来,可以使用 update()方法将数据传入哈希对象。

hash.update("Hello, XiangPiCa!".encode())

最后,可以使用 hexdigest() 方法计算哈希值。

hashValue = hash.hexdigest()

本案例到此结束,已更新到 爬虫训练场 欢迎大家访问学习。
项目同步到代码仓库 https://gitcode.net/hihell/spider_playground

📢📢📢📢📢📢
💗 你正在阅读 【梦想橡皮擦】 的博客
👍 阅读完毕,可以点点小手赞一下
🌻 发现错误,直接评论区中指正吧
📆 橡皮擦的第 818 篇原创博客

从订购之日起,案例 5 年内保证更新


转载:https://blog.csdn.net/hihell/article/details/128474930
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场