002笔记【签名验证反爬虫原理和实现】

一.签名反爬虫:

 签名是根据数据源进行计算或加密的过程,签名的结果是一个具有唯一性和一致性的字符串。签名结果的特性成为数据来源和数据完整的条件,可以有效避免服务器端将伪造的数据或被篡改的数据当成正常数据处理。


二.案例分析

(1).准备工作:
 网址:http://www.porters.vip/verify/sign
 任务:爬取旅游公告页面详情信息

在这里插入图片描述
(2).分析:
 点击‘点击查看详情’,就是公告详情

在这里插入图片描述
  按F12,查看NetWork,分析数据从什么地方读取的。
(其中md5.js和sign.js保存下来方便使用)

在这里插入图片描述
 点击sign.js进行分析

// fetch():鼠标点击事件后激活,使用GET方法向目标URL发起网络请求,并将覆盖content;使用了Ajax请求后端API
function fetch(){
    text=$.ajax({
        type:"GET", async: false,
        // 结合Tornado框架使用进行验证交给后端API处理
        url:"http://localhost:8000/fet/" + uri()
    });
    $("#content").html(text.responseText);
}

function randints(r, n, tof){
	/* 生成随机数字,tof决定返回number类型或者字符串类型
	r 代表数字范围 n 代表数量
	*/
	var result = [];
	if(tof){
		return Math.floor(Math.random()*r);
	}
	for(var i=0;i<n;i++){
		s = Math.floor(Math.random()*r);
		result.push(s);
	}
	return result.join('');
}
function randstrs(n){
	// 生成随机字母,n为随机字母的数量
	var result = [];
	for(var i=0; i<n; i++){
		s = String.fromCharCode(65+randints(25, 1, 1));
		result.push(s);
	}
	return result.join('');
}
function uri(){
	// 生成随机5个小于9的数字
	var action = randints(9, 5, 0);
	// 生成时间戳
	var tim = Math.round(new Date().getTime()/1000).toString();
	// 生个5个随机的大写字母
	var randstr = randstrs(5);
	// 拼接
	var hexs = hex_md5(action+tim+randstr);
	args = '?actions=' + action + '&tim=' + tim + '&randstr=' + 	randstr + '&sign=' + hexs;
	return args;
}



三.Python代码实现

 (1).新建项目文件夹signature,两个子文件夹static, templates
 (2).static下有md5.js和sign.js这两个文件
 (3).templates下有index.html模板(查看网页源代码直接保存)

代码演示:

# coding:utf-8

import os
import hashlib
from tornado.web import RequestHandler, Application
from tornado.ioloop import IOLoop
from time import time
from datetime import datetime


class IndexHandler(RequestHandler):
    def get(self, *args, **kwargs):
        self.render('index.html')
        

def make_app():
    return Application(
        [(r'/',IndexHandler)],
        template_path=os.path.join(os.getcwd(), 'templates'),
        static_path=os.path.join(os.getcwd(), 'static'),
    )


if __name__ == '__main__':
    app = make_app()
    app.listen(8000)
    IOLoop.current().start()

测试一下:
 (4).在浏览器输入http://localhost:8000 测试成功。
在这里插入图片描述

完整代码:

# coding:utf-8

import os
import hashlib
from tornado.web import RequestHandler, Application
from tornado.ioloop import IOLoop
from time import time
from datetime import datetime


class IndexHandler(RequestHandler):
    def get(self, *args, **kwargs):
        self.render('index.html')


class FetHandler(RequestHandler):
    content = """
    <p>参团的游客,应听从领队、导游人员的安全提醒,切莫擅自行动。
        自身的人身、财物安全要注意,购买人身意外险,贵重物品要随身携带,
        不要留在车内或者交由他人保管。参加漂流、摩天轮等高风险项目的时候,
        要认真听从工作人员的安排,切莫求刺激而发生意外。</p>
    <p>以下是本次参团出行需要遵守的规范要求:</p>
    <p>一、跟刺激相比,命更重要,没有命就什么都没了。</p>
    <p>二、旅行中会遇到很多你从未见过的植物和动物,不要轻易打扰它们,有可能有毒。</p>
    <p>三、身体感觉不适,尤其是发烧、乏力和呕吐等情况必须报告随队医护人员。</p>
    <p>四、出发前请跟家人沟通好,避免造成失联错觉。</p>
    <p>五、出发前请按照队长的要求准备好必备衣物和干粮,最重要的是水。</p>
    <p>六、旅行途中必须紧跟队伍,不许在无人知晓的情况下行动。</p>
    <p>七、如不慎走失,请先释放信号弹,半小时后无人联系再想办法报警。</p>
    <p>八、如果不同意以上几条,请在出发前告知队长。</p>
    <p>九、最重要的是:没有命,就什么都没了。</p>
    """

    @staticmethod
    def time_stamp(tp):
        """将前端传递的时间戳与当前时间戳对比并返回差值秒数"""
        tamp = int(tp)
        now = round(time())
        sub_tamp = datetime.fromtimestamp(now) - datetime.fromtimestamp(tamp)
        #  total_seconds()包括天和秒数,获取两时间的总差;seconds():不包括天,只有秒数
        return sub_tamp.total_seconds()

    @staticmethod
    def hex5(value):
        """加密后返回字符串"""
        md_5 = hashlib.md5()
        md_5.update(value.encode('utf-8'))
        # 返回作为16进制数据字符串
        md5_str = md_5.hexdigest()
        return md5_str

    def comparison(self, actions, tim, randstr, sign):
        """根据传递的参数计算MD5值,并与客户端提交的MD5值进行对比"""
        value = actions+tim+randstr
        hexs = self.hex5(value)
        if hexs == sign:
            return True
        return False

    def get(self, *args, **kwargs):
        """返回数据给视图"""

        # 请求获取正文
        params = self.request.arguments
        actions = params.get('actions')[0].decode('utf-8')
        tim = params.get('tim')[0].decode('utf-8')
        randstr = params.get('randstr')[0].decode('utf-8')
        sign = params.get('sign')[0].decode('utf-8')
        # 取差值
        seconds = self.time_stamp(tim)
        if self.comparison(actions, tim, randstr, sign) and seconds < 5:
            # 如果参数值都符合要求,就返回正常内容
            self.write(self.content)
        else:
            # 否则返回异常
            self.set_status(403)


def make_app():
    return Application(
        [(r'/', IndexHandler), (r'/fet/', FetHandler)],
        template_path=os.path.join(os.getcwd(), 'templates'),
        static_path=os.path.join(os.getcwd(), 'static'),
    )


if __name__ == '__main__':
    app = make_app()
    app.listen(8000)
    IOLoop.current().start()

点击‘点击查看详情’,测试成功!
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值