反爬案例:不登录不给,要数据请先登录我的站点

举报
梦想橡皮擦 发表于 2023/05/26 17:46:53 2023/05/26
【摘要】 登录之后,可以查看数据,是部分站点常用规则,本篇博客将在爬虫训练场中实现该需求。 安装必备模块实现 Python Flask 项目的登录,最需要的模块是 flask-login,除此之外,还需要用到以下三个模块:flask-wtf:该模块用于在 Flask 应用程序中处理 Web 表单的功能。wtf:用于跟踪和报告程序崩溃的功能;werkzeug:Web 服务器和 Web 应用程序的功能,包...

登录之后,可以查看数据,是部分站点常用规则,本篇博客将在爬虫训练场中实现该需求。

安装必备模块

实现 Python Flask 项目的登录,最需要的模块是 flask-login,除此之外,还需要用到以下三个模块:

  • flask-wtf:该模块用于在 Flask 应用程序中处理 Web 表单的功能。
  • wtf:用于跟踪和报告程序崩溃的功能;
  • werkzeug:Web 服务器和 Web 应用程序的功能,包括 HTTP 处理和 WSGI 支持。

模块全部安装完毕,首先要做的准备工作是在 MySQL 数据库中建立 users 表,结构相对简单,仅包含 2 个字段即可。

建立 models

数据库表建立完毕,可以在 app 目录下创建 login_model.py 文件,并输入模型代码。

from werkzeug.security import generate_password_hash, check_password_hash

from flask_login import UserMixin
from app import db


class User(UserMixin, db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True)
    password_hash = db.Column(db.String(128))

    @property
    def password(self):
        # 设置密码的属性为只写
        raise AttributeError('密码不能读取')

    @password.setter
    def password(self, password):
        # 当类初始化时自动调用,把 password 的值转换为 hash 值
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password) -> bool:
        # 登录时验证密码
        return check_password_hash(self.password_hash, password)

这里用到的几个核心函数说明如下:

flask_login 中 UserMixin 类说明

UserMixin 类可以被用户类继承。 这个类包含了一些必要的属性和方法,以便于 Flask-Login 来管理登录状态,如 is_authenticated, is_active, is_anonymous 以及 get_id。用户需要实现的只需要继承 UserMixin,然后实现它的函数 get_id() 即可。

werkzeug.security 中的两个函数 generate_password_hash(), check_password_hash()

Werkzeug.security 模块提供了两个主要的函数,用于生成和验证密码哈希:

  • generate_password_hash(password, method='sha256', salt_length=8):这个函数用于生成密码哈希。参数 password 是需要加密的明文密码, method 参数用于指定使用的哈希算法, 默认为 'sha256',salt_length 为指定盐的长度;
  • check_password_hash(hashed_password, password):这个函数用于检查给定的明文密码和哈希值是否匹配。参数 hashed_password 是上面 generate_password_hash() 函数生成的哈希值,password 是需要校验的密码。

建立 login_form 表单文件

app 目录建立 login_form.py,然后输入如下代码。

from flask_wtf import FlaskForm
from wtforms.validators import DataRequired, Length
from wtforms import StringField, SubmitField, PasswordField

# 定义的表单都需要继承自FlaskForm
class UserForm(FlaskForm):

    username = StringField('用户名', validators=[DataRequired(), Length(3, 15)])
    password = PasswordField('密码', validators=[DataRequired(), Length(5, 15)])
    submit = SubmitField('登录')

由于 flask_wtf 模块用于处理表单,所以我们自定义一个表单。

上述代码涉及的知识点如下所示。

flask_wtf 中 FlaskForm 类

Flask-WTF 是 Flask 框架中的一个扩展库,主要用于构建和处理 HTML 表单。在 Flask-WTF 中,FlaskForm 类是一个非常重要的类,它是所有表单类的基类。

FlaskForm 类提供了一些基础的功能,包括验证,渲染,和 CSRF 保护等功能。通常,我们会定义一个继承于 FlaskForm 的自定义表单类来处理特定的表单。

例如上述代码,我们集成 FlaskForm 创建了一个表单对象,用于处理用户的登录信息,并且通过在类中使用 Flask-WTF 内置的字段类和验证器来验证用户的输入。

除此之外,还可以在模板中可以使用 {{form.csrf_token}} 生成隐藏的 csrf_token

建立登录视图函数

打开 routes.py 文件,在其中添加登录视图函数,首先将 UserForm() 实例化的对象传递到模板中,后续可以在 login.html 中直接进行渲染。

@app.route("/login", methods=['GET', 'POST'])
def login():
    form = UserForm()
    if form.validate_on_submit():
        # 查询用户信息
        user = User.query.filter_by(username=form.username.data).first()
        if user is not None:
            if user.verify_password(form.password.data):
                flash('登录成功')
                login_user(user)  # login_user 的参数为要登录的用户
                return redirect(request.args.get('next') or url_for('school.login_list_school'))
        flash('登录失败')
    return render_template('login.html', form=form)

既然已经开始修改 routes.py 文件,那再这里需要首先实例化 LoginManager 类 ,该类用于管理用户登录状态。

然后使用 init_app() 函数将 LoginManager 类对象绑定到指定 Flask 应用上。


from flask_login import LoginManager,login_user

# use login manager to manage session
login_manager = LoginManager(app)
login_manager.login_view = 'login'  # 设置登录页面


# 回调函数,用来加载用户
@login_manager.user_loader  #
def load_user(id):
    '''用于加载用户'''
    return User.query.get(int(id))

除此之外,还需要增加 load_user() 函数,该函数用于加载用户,关于 Flask-Login 的详细用法,可以参考下述博客。
Python flask 框架使用 flask-login 模块,来学习一下吧

配置 login.html 页面

打开 login.html 文件,输入如下代码,完成最后收尾工作。

{% extends "base.html" %} {% block style %}
<style type="text/css">
  .required:after {
    content: "*";
    color: red;
  }
</style>
{% endblock style %} {% block script %}
<script
  type="text/javascript"
  src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.6.0.min.js"
></script>
<script type="text/javascript">
  $(document).ready(function () {
    $('[data-toggle="tooltip"]').tooltip();
  });
</script>

{% endblock script %} {% block content %}
<div class="container">
  <div class="row justify-content-center">
    <div class="col-md-6 mt-5 mb-5 p-5 border border-success shadow-lg  ">
      <h1 class="text-primary">登录窗口</h1>
      <form action="{{ url_for('login') }}" method="POST" class="mt-4">
        <div class="form-group">
          <span class="required"> {{ form.username.label }} </span>:
          {{form.username(class="form-control",placeholder="请输入用户名",data_toggle="tooltip",title="测试账号:xiangpica")
          }}
          <small id="username_help" class="form-text text-muted"
            >用户名至少3个字符</small
          >
        </div>

        <div class="form-group">
          <span class="required"> {{ form.password.label }} </span> : {{
          form.password(class="form-control",placeholder="请输入密码",data_toggle="tooltip",title="测试密码:123456")
          }} <br />
        </div>
        <div class="form-group">
          {{ form.submit(class="btn btn-primary" ) }}
        </div>
        {{ form.csrf_token }}
      </form>
    </div>
  </div>
</div>

{% endblock %}

运行代码,得到如下登录窗口。

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

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

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。