首页
旅行足迹
友链
留言
关于
壁纸
Search
1
小米12Pro为例,新版小米手机安装magisk获取root教程
2,738 阅读
2
在html中通过vue3-sfc-loader引用.vue文件
1,906 阅读
3
vscode+docker开启Xdebug3功能调试PHP
1,841 阅读
4
目前贼拉好用的ChatGPT应用
1,500 阅读
5
Windows系统删除资源管理器侧边的3D对象等
1,455 阅读
玩机教程
软件设计师
前端
Vue
JavaScript
后端
Python
java
Search
标签搜索
python
flask
Django
爬虫
软件设计师
数据结构
Scrapy
玩机教程
PHP
LNMP
Ubuntu
Hexo
算法
ROOT
刷机
前端
JavaScript
webhook
自动化部署
binscor
累计撰写
43
篇文章
累计收到
4
条评论
首页
栏目
玩机教程
软件设计师
前端
Vue
JavaScript
后端
Python
java
页面
旅行足迹
友链
留言
关于
壁纸
搜索到
23
篇与
的结果
2019-08-19
第7节、model01以及拆分MVT
一、Modelflask作为一款MVT的框架,也具有ORM模型的操作,通过扩展库(flask-sqlalchemy)来实现。随着项目越来越大,采用原生sql的话,就会出现大量的原生sql语句。ORM模型的好处:SQL语句重复使用率低,越复杂的sql语句,语句就越长,会出现很多相似的sql语句很多sql语句都是根据业务逻辑拼接出来的,如果数据库发生了修改,那么这些逻辑就需要重写 这样就会漏掉某些sql的更改原生SQL容易漏掉,对sql语句安全性的考虑工作原理:ORM 是对象关系的映射,我们可以通过类的方式去操作数据库,不再使用原生的SQL语句了。ORM中的类映射数据库中的每个表,类中的每个属性映射成表中的每个字段。ORM最终还是会将开发者操作的增删改查的代码转换成sql语句,再去操作数据库。好处:可以使用简短的代码写出比较复杂的SQL语句可以减少重复sql语句的概率可移植性好,只需要更改settings.py的配置sqlite,mysql等二、原生SQL(1) 创建数据库 python1807create database if not exists python1807 character set utf8;(2) 安装pymysql模块pip install pymysql(3) 安装flask-sqlalchemypip install flask-sqlalchemy(4) 配置链接数据库的URI地址#配置链接数据库的URI地址 HOST = '127.0.0.1' USER = 'root' PASSWORD = '123456' PORT = '3306' NAME = 'python1807' DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USER,PASSWORD,HOST,PORT,NAME)实例from sqlalchemy import create_engine #配置链接数据库的URI地址 HOST = '127.0.0.1' USER = 'root' PASSWORD = '123456' PORT = '3306' NAME = 'python1807' DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USER,PASSWORD,HOST,PORT,NAME) #创建sqlalchemy操作数据库引擎 engine = create_engine(DB_URI) with engine.connect() as con: con.execute('drop table user ') con.execute('create table user(id int,username varchar(10))') con.execute('drop table user ') #在windows下 库,表名 不区分大小写 linux下 严格区分大小写三、flask-sqlalchemy Model(1) 导入from flask-sqlachemy import SQLAlchemy(2) 配置URI地址app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@127.0.0.1:3306/python1807' #配置链接数据库的地址四、model的字段 可选项(1) 字段类型类型名python类型说明Integerint整形 2(10)SmallIntegerint小整形BigerIntegerint长整形Floatfloat浮点形Stringstringvarchar类型 0-255Textstringtext 类型 0-65535BooleanboolTrue FalseDatedatetime.date日期Timedatetime.time时间DateTimedatetime.datetime日期和时间(2) 约束条件选项说明primary_key主键索引unique唯一索引index常规索引nullable是否为空 默认Truedefault默认值五、创建模型配置from flask import Flask from flask_script import Manager from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@127.0.0.1:3306/python1807' #配置链接数据库的地址 app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) manager = Manager(app)实例 创建user模型#创建模型 class User(db.Model): id = db.Column(db.Integer,primary_key=True) username = db.Column(db.String(20),index=True) sex = db.Column(db.Boolean,default=True) age = db.Column(db.Integer,default=20)创建表@app.route('/create_table/') def create_table(): db.create_all() return '创建表'删除表@app.route('/drop_table/') def drop_table(): db.drop_all() return '删除表'注意:创建表和删除表都是使用当前模型名创建模型的,表删除模型同名的所有的表六、数据添加 修改 删除 查询的操作(1) insert_one 添加一条数据#添加一条数据 @app.route('/insert_one/') def insert_one(): u = User(username='张三',sex=False,age=18) db.session.add(u) db.session.commit() return 'insert_one'(2) insert_many 添加多条数据#添加多条数据 @app.route('/insert_many/') def insert_many(): try: u1 = User(username='李四') u2 = User(username='王五') db.session.add_all([u1,u2]) db.session.commit() except: db.session.rollback() return 'insert_many'(3) 数据的查询@app.route('/select/') def select(): u = User.query.get(1) # print(u) print(u.username) print(u.sex) print(u.age) return '查询id值'(4) 数据的修改@app.route('/update/') def update(): u = User.query.get(1) u.username = '张三123' u.age = 30 db.session.add(u) db.session.commit() return '修改'(5) 数据的删除#删除 @app.route('/delete/') def delete(): u = User.query.get(1) db.session.delete(u) db.session.commit() return '删除'注意:ORM开启了事物处理 在执行增 删 改 的时候 要提交或者 回滚db.session.commit()db.session.rollback()七、拆分MVT目录层级project/ App/ templates/ 模板 common/ base.html static/ 静态 upload/ models/ 模型 __init__.py views/ 视图 __init__.py forms/ 表单 __init__.py extensions.py 加载扩展库 settings.py 配置文件 email.py 邮件 __init__.py 包的初始化 migrations/ #迁移目录 manage.py #启动
2019年08月19日
558 阅读
0 评论
0 点赞
2019-08-19
第5节、Flask表单
一、原生表单1. 添加模板文件login.html,内容如下:<form method="post" action="{{ url_for('check') }}"> 用户名:<input name="username" type="text" /> <input type="submit" value="立即登录" /> </form>2. 视图函数,如下:# 登录 @app.route('/login/') def login(): return render_template('login.html') P # 校验 @app.route('/check/', methods=['POST']) def check(): print(request.form.get('username')) return 'Hello %s !' % request.form['username']3. 将登录页面和校验的路由合并,如下:@app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': return render_template('login.html') else: return 'Hello %s !' % request.form['username']一个路由处理时,表单的action属性不用书写,默认提交到当前路由。二、flask-wtf处理表单说明:flask-wtf是一个用于表单处理的扩展库,提供了CSRF、校验等功能,使用非常方便附:flask-wtf教程1.跨站请求伪造保护(csrf)附:浅谈CSRF攻击方式Flask-WTF 能保护所有表单免受跨站请求伪造(Cross-Site Request Forgery,CSRF)的攻击。恶意网站把请求发送到被攻击者已登录的其他网站时就会引发 CSRF 攻击。为了实现 CSRF 保护,Flask-WTF 需要程序设置一个密钥。Flask-WTF 使用这个密钥生成加密令牌,再用令牌验证请求中表单数据的真伪。#视图中 设置 Flask-WTF app = Flask(__name__) app.config['SECRET_KEY'] = 'hard to guess string'#字典可用来存储框架、扩展和程序本身的配置变量。 #为了增强安全性,密钥不应该直接写入代码,而要保存在环境变量中。 #模板中使用 {{ form.hidden_tag() }} #或 {{ form.csrf_token }}2.关闭csrf@app.route('/form/',methods=['post','get']) def newform(): form = NameForm(csrf_enabled = False)3.flask-wtf常见字段类型和验证器常见字段类型字段类型说明StringField普通文本字段SubmitField提交按钮PasswordField密码文本字段HiddenField隐藏文本字段TextAreaField多行文本字段DateField文本字段,datetime.date格式DateTimeField文本字段,datetime.datedatime格式IntegerField文本字段,值为整数FloatField文本字段,值为小数BooleanField复选框,值为True或FalseRadioField单选框SelectField下拉框FileField文件上传常见验证器类验证器说明DataRequired确保字段有值 必填项Email邮箱地址 验证邮箱IPAddressIP地址Length规定字符长度 有min和max两个值进行限制。NumberRange输入数值的范围EqualTo验证两个字段的一致性URL有效的URLRegexp正则验证info = TextAreaField('个人信息',render_kw={'style':'resize:none;'}) #render_kw 给当前的标签添加属性表单类每个 Web 表单都由一个继承自Form的类表示。这个类定义表单中的一组字段(表单的内容与类的字段是一一对应的),每个字段都用对象(表单中的对象)表示。字段对象可附属一个或多个验证函数。4.定义表单类# 导入表单基类 from flask_wtf import FlaskForm # 导入字段类型 from wtforms import StringField, SubmitField # 导入验证器类 from wtforms.validators import DataRequired #必填字段 # CSRF需要使用 app.config['SECRET_KEY'] = '123456' # 定义表单类 class NameForm(FlaskForm): #name 为表单的name名称 name = StringField('用户名', validators=[DataRequired()]) submit = SubmitField('提交')5.添加视图函数:@app.route('/') def index(): # 创建表单对象 form = NameForm() # 分配到模板中进行渲染 return render_template('form.html', form=form)6.模板文件中渲染表单:Form 类有一个 hidden_tag 方法, 它在一个隐藏的 DIV 标签中渲染任何隐藏的字段,包括 CSRF 字段:{# 原生渲染 #} <form> {# CSRF的隐藏字段 #} {{ form.hidden_tag() }} #或 {{ form.csrf_token }} {# name字段,可以指定id、class等属性,定制显示效果 style='color:red 设置文本颜色 #} {{ form.name.label() }}{{ form.name(id='xxx', class='yyy',style='color:red) }} {{ form.name.errors }} #错误提示 {# submit字段 #} {{ form.submit() }} </form>7.在视图中使用bootstrap的wtf快速渲染表单#使用bootstrap快速渲染 其它代码不变 from flask_bootstrap import Bootstrap app.config['BOOTSTRAP_SERVE_LOCAL'] = True #加载本地的js文件 bootstrap = Bootstrap(app) {% extends 'bootstrap/base.html' %} {% import 'bootstrap/wtf.html' as wtf %} {{ wtf.quick_form(form) }}模板中更改表单提交地址和表单排列样式wtf.quick_form(form,form_type='horizontal',action= url_for('login') )查看都有哪些参数可以查看 wtf.html 里面的 quick_form 宏{# bootstrap渲染 #} {% extends 'bootstrap/base.html' %} {# 导入渲染工具 #} {% import 'bootstrap/wtf.html' as wtf %} {# 渲染表单 调用宏方法 wtf.quick_form#} {% block content %} <div class="container">{{ wtf.quick_form(form,action=url_for('upload')) }}</div> {% endblock %}8.表单校验@app.route('/', methods=['GET', 'POST']) def index(): # return '表单使用' name = None # 创建表单对象 form = NameForm() # 表单校验 #validate_on_submit 会便捷地检查该请求是否是一个 POST 请求以及是否有效。 if form.validate_on_submit(): name = form.name.data form.name.data = '' # 分配到模板中进行渲染 return render_template('form.html', form=form, name=name)9.自定义表单验证器自定义字段验证:就是写一个validate_字段名'的函数,如下:# 定义表单类 class NameForm(FlaskForm): name = StringField('用户名', validators=[DataRequired()]) submit = SubmitField('提交') #如果字段中也存在Length对象的验证 那么这俩个验证会重复叠加 #userName = StringField('用户名',validators=[DataRequired(),Length(3, 6, message='请输入正确的长度')]) # 自定义字段验证函数,格式是写一个'validate_字段名'的函数 def validate_name(self, field): if len(field.data) < 6: raise ValidationError('用户名长度不能少于6个字符')10.所有的字段和验证器的使用class Form(FlaskForm): hidde = HiddenField() username = StringField('用户名') userpass = PasswordField('密码') confirm = PasswordField('确认密码',validators=[EqualTo('userpass',message='密码和确认密码不一致')]) info = TextAreaField('个人信息',render_kw={'style':'resize:none;'}) birth = DateField('出生年月',format='%Y/%m/%d') birthday = DateTimeField('生日日期') age = IntegerField('age',validators=[NumberRange(min=6,max=99,message='年龄范围6~99')]) money = FloatField('money') rember = BooleanField('记住我') sex = RadioField('sex',choices=[('m','男'),('w','女')]) address = SelectField('address',choices=[('1001','北京'),('1002','上海'),('1003','深圳')]) photo = FileField('photo') email = StringField('email',validators=[Email(message='请输入合法的邮箱地址')]) ip = StringField('ip',validators=[IPAddress(message='输入合法的ipv4地址')]) url = StringField('url',validators=[URL(message='请输入正确的url')]) phone = StringField('手机号码',validators=[Regexp("[1][3-8][0-9]{9}$",flags=re.I|re.M|re.S,message='输入正确的手机号码')]) # re.I 不区分大小写 # re.S 使.匹配换行符 # re.M 改变 ^ 和 $ 作用 使之可以多行匹配 submit = SubmitField('submit') #自定义表单验证器 validate_ 死的 + 验证的属性名 当点击的时候 就会执行当前的自定义表单验证器 def validate_username(self,field): if self.username.data == 'zhangsan': raise ValidationError('当前用户已存在')
2019年08月19日
493 阅读
0 评论
0 点赞
2019-08-13
第4节、模板引擎02
一、macro 宏的使用概述: 类似于python中的函数(1)主体结构{ % macro 宏名称([参数...]) % } ... { % endmacro % } {{ 宏名称([参数...]) }}实例{ % macro form(textname,text='text',name='',value='') % } <p>{{ textname }}<input type="{{ text }}" name="{{ name }}" value="{{ value }}"></p> { % endmacro % } <form action=""> {{ form('用户名:',name='username') }} {{ form('密码:','password','userpass') }} {{ form('','submit',value='submit') }} </form>(2)导入macrocommon/public_macro.htmlfrom ... import ... as ..{ % from 'common/public_macro.html' import form % } { % from 'common/public_macro.html' import form as f % } #起别名fimport ... as{ % import 'common/public_macro.html' as mymacro % }注意:宏的调用 必须在定义的下方来调用如果有形参且没有默认值则可以不传实参参数默认从左到右依次对应形参默认值 遵循默认值规则 (有默认值的放在右侧)关键字参数的使用 一样当导入的包名字过长,或者是当前文件中存在同名的变量或者函数,类名 为防止重名覆盖 使用 as 起别名二、模板继承1. extends格式:{ % extends '模板路径/模板名称.html' % }2. block对于父模板的代码的替换实例base.html(父模板)<!DOCTYPE html> <html lang="en"> <head> { % block head % } <meta charset="UTF-8"> { % block meta % } { % endblock % } {# <title>{ % block title % }{{ title|default('base') }}{ % endblock % }</title>#} <title>{ % block title % }base{ % endblock % }</title> <style> { % block style % } header,footer{ width:100%; height:40px; border:1px solid #000; background-color: #000; color: #fff; } div{ width:100%; height:400px; background-color: red; } { % endblock % } </style> { % block link % } { % endblock % } { % block script % } { % endblock % } { % endblock % } </head> <body> <header>导航</header> <div> { % block con % } { % endblock % } </div> <footer>底部栏</footer> </body> </html>child.html(子模板){ % extends 'common/base.html' % } { % block title % } child { % endblock % } { % block style % } { { super() } } a{display:block;width:200px;height:200px;color:white;background-color:yellow;} a:hover{background-color:blue;} div{background-color:green;} { % endblock % } { % block con % } 我是子模板的内容部分 <a href="">点击去百度</a> { % endblock % }注意: 如果子模板继承了父模板后代码缺失或者样式不起作用,查看是否调用了{ { super () } },super调用父模板中被替换掉的代码和样式三、在flask中使用bootstrap(flask-bootstrap)(1)创建bootstrap模板对象from flask_bootstrap import Bootstrap app.config['BOOTSTRAP_SERVE_LOCAL'] = True #加载本地的bootstrap样式 否则从网络请求 bootstrap = Bootstrap(app)(2)使用flask-bootstrap的base模板{ % block doc -% } <!DOCTYPE html> <html{ % block html_attribs % }{ % endblock html_attribs % }> { %- block html % } <head> { %- block head % } <title>{ % block title % }{{title|default}}{ % endblock title % }</title> { %- block metas % } <meta name="viewport" content="width=device-width, initial-scale=1.0"> { %- endblock metas % } { %- block styles % } <!-- Bootstrap --> <link href="{{bootstrap_find_resource('css/bootstrap.css', cdn='bootstrap')}}" rel="stylesheet"> { %- endblock styles % } { %- endblock head % } </head> <body{ % block body_attribs % }{ % endblock body_attribs % }> { % block body -% } { % block navbar % } { %- endblock navbar % } { % block content -% } { %- endblock content % } { % block scripts % } <script src="{{bootstrap_find_resource('jquery.js', cdn='jquery')}}"></script> <script src="{{bootstrap_find_resource('js/bootstrap.js', cdn='bootstrap')}}"></script> { %- endblock scripts % } { %- endblock body % } </body> { %- endblock html % } </html> { % endblock doc -% }(3)自定义base 继承flask-bootstrap的base实例: 引用bootstrap的导航栏{ % extends 'bootstrap/base.html' % } { % block navbar % } <nav class="navbar navbar-inverse" style="border-radius: 0px;"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#"><span class="glyphicon glyphicon-fire" aria-hidden="true"></span></a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">首页<span class="sr-only">(current)</span></a></li> <li><a href="#">发表博客</a></li> </ul> <ul class="nav navbar-nav navbar-right"> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <li><a href="#">欢迎:...</a></li> <li><a href="#">登录</a></li> <li><a href="#">注册</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">个人中心<span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">退出登录</a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> { % endblock % } { % block content % } <div class="container"> { % block pagecontent % } 就是主体内容 { % endblock % } </div> { % endblock % }(4)子模板继承自定义的base模板{ % extends 'common/base.html' % } { % block title % } 首页 { % endblock % } { % block pagecontent % } <h1>首页</h1> { % endblock % }继承过程:子模板-----继承----->自定义的base -----继承---->flask-bootstrap的base模板四、自定义错误模板manage.py #捕获404 @app.errorhandler(404) def page_not_found(e): return render_template('error/error.html',title='404 NOT_FOUND',h1con='404页面找不到...',error=e) #捕获500 @app.errorhandler(500) def server_error(e): return render_template('error/error.html',title='500 SERVER_ERROR',h1con='当前服务繁忙 请稍后再次访问...')error/error.html{ % extends 'common/base.html' % } { % block title % } {{ title }} { % endblock % } { % block pagecontent % } <h1>{{ h1con }}</h1> { % if error % } <div class="alert alert-danger" role="alert">{{ error }}</div> { % endif % } { % endblock % }五、静态文件加载概述: 上传文件,比如网站用到的图片,视频,音频,js,css...目录结构project/ templates/ #模板目录 static/ #静态资源目录 img/ js/ css/ upload/ manage.py加载静态资源实例: 设置页面图标{ % extends 'common/base.html' % } { % block title % } 首页 { % endblock % } { % block head % } { { super () } } <link rel="icon" href="{{ url_for('static',filename='img/timg.jpeg',_external=True) }}"> { % endblock % } { % block pagecontent % } <h1>首页</h1> <img src="{{ url_for('static',filename='img/timg.jpeg') }}" alt=""> <link rel="stylesheet" href="{{ url_for('static',filname='css/index.css') }}"> { % endblock % }注意:static视图函数是flask为我们提供的,作用是构造出到static静态文件夹的路径,想加载哪个文件就使用参数filename='路径/文件名称'_external=True 显示绝对路径{{ url_for('static',filename='img/timg.jpeg',_external=True) }}六、视图函数传递参数到模板的方法(1) 直接在render_template()中传递@app.route('/') def index(): return render_template('index.html',title='title',....)(2) 通过字典的方式@app.route('/') def index(): return render_template('index.html',data={'title':'title',....})模板中调用{{ data.title }} (3) 使用 locals() 函数@app.route('/test/') def test(): name = '张三' age = 18 print(locals()) return render_template('index.html',**locals()) #将字典变成关键字参数模板中使用{{ name }} {{ age }}
2019年08月13日
665 阅读
0 评论
0 点赞
2019-08-08
第3节、模板引擎01
一、模板简介概述: 模板就是按照一定的规则书写的负责展示的html页面,模板引擎提供特定规则、替换的工具。模板引擎:jinja2目录结构project/ templates/ #推荐使用该文件名,使用其他的名称需重新配置 manage.py模板渲染使用的方法(1)render_template(template_name,**context)响应一个html模板(2)render_template_string响应一段html代码 (适合响应简短的样式的响应)二、模板中语法的分类1. 变量 {{ 变量名称 }}视图传递给模板的数据遵循变量/标识符的命名规则关键字参数实例 可以给render_template 添加关键字参数,进行变量的传递@tem.route('/test/') def test(): h1con = '模板的变量' return render_template('test.html',h1=h1con) #渲染模板响应给用户 模板中使用 <h1>{{ h1 }}</h1>注意: 如果给定的变量不存在则什么都不插入(什么都没有)2. 标签 {% 标签名称 %}就是python中的逻辑的判断循环/if...三、过滤器(相当于python中的函数)过滤器使用管道符 | 添加上函数和值进行使用abs 返回一个数值的绝对值default 默认值 注意: 默认只有当前变量不存在才执行默认值,将参数boolean改为True,则bool和undefined都执行默认值实例{{ bool|default('默认值') }} {{ bool|default('默认值',boolean=True) }} boolean默认为Falsefirst 返回序列中的第一个元素last 返回序列中的最后一个值format 格式化输出{{ "我叫%s 我今年%d岁了 我的存款为%.2f元"|format('张三',18,123) }}length 值长度join 拼接{{ ['a','b','c']|join('') }} {{ data.str|join('x') }}safe 对视图传递的html代码进行转义解析 (默认不解析 转义掉)int 转换整形float 浮点string 字符串list 转换成列表upper 转换成大写lower 转换成小写replace 替换 {{ 'abcd'|replace('a','x') }}striptags 取出html标签trim 去除两侧空格四、标签语法格式:{% %} 注意: 标签有开始,就要有结束> < >= <= == != in not in and or(1) if elif else{% if 90<=data.grade<=100 %} 优秀 {#{% elif 80<=data.grade<=89 %}#} {% elif 80<=data.grade %} 良 {#{% elif 70<=data.grade<=79 %}#} {% elif 70<=data.grade %} 中 {% else %} 还可以 {% endif %}(2) for 循环{% for ... %} ...{% endfor %}迭代字典{% for k,v in data.items() %} <p>{{ k }}----{{ v }}</p> {% endfor %} {% for i in range(10) %} <p>{{ i }}</p> {% endfor %}搭配else{ % for i in abc % } <p>{{ i }}</p> { % else % } <h1>执行else了</h1> { % endfor % }注意: 当迭代的变量不存在则执行else获取当前迭代的状态变量说明loop.index当前迭代的索引 从1开始loop.index0当前迭代的索引 从0开始loop.first是否为第一次迭代loop.last是否为最后一次迭代loop.length迭代的长度注意: 没有break 和 continue五、注释多行注释{# 注释的内容 #}注意: 多行注释不能嵌套多行注释六、文件的包含 include概述:include语句可以把一个模板导入到另外的一个模板的指定位置,就相当于把另外的模板中的代码粘贴到了你的指定位置结构:{% include 路径/模板名称.html %}实例文件目录 project/ templates/ commom/ header.html footer.html index.html manage.pymanage.py@app.route('/') def index(): return render_template('index.html') #跳到首页模板common/header.html<header>导航</header>common/footer.html<footer>底部栏</footer>index.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> header,footer{ width:100%; height:40px; border:1px solid #000; background-color: #000; color: #fff; } div{ width:100%; height:400px; background-color: red; } </style> </head> <body> {% include 'common/header.html' %} <div></div> {% include 'common/footer.html' %} </body> </html>
2019年08月08日
664 阅读
0 评论
0 点赞
2019-08-07
第2节、Flask基础02
一、flask-script扩展库简介:是一个flask终端运行的解析器,因为在项目完成以后 所有的代码都不应该有任何的修改 因为一旦有修改 就有可能带来bug导入: from flask_script import Manager使用from flask_script import Manager manager = Manager(app) ... if __name__ == '__main__': manager.run()启动的参数参数参数说明-h帮助-h主机-p端口号-d调试 显示出现的错误信息-r代码加载--threaded开启多线程在控制台输入启动命令运行程序python3 manage.py runserver -hpython3 manage.py runserver -h0.0.0.0 -p5000 -d -r --threaded #全部开启python3 manage.py runserver -d -r #开启调试和代码加载二、蓝本/蓝图(blueprint)概述:当项目的代码越来越多的时候 把所有代码 都放到一个文件中 是不合理的 要根据不同功能的视图函数 进行划分到不同的模块文件中使用新建一个user.pyfrom flask import Blueprint #导入蓝本 user = Blueprint('user',__name__) #参数1 当前蓝本的名字 参数2 所在模块 @user.route('/loign/') def login(): return 'login'在manage.py中注册蓝本,使之与当前的flask框架关联起来from user import user #从user.py模块中 导入user蓝本对象 app.register_blueprint(user) #注册蓝本 #http://127.0.0.1:5000/login/ app.register_blueprint(user,url_prefix='/user') #添加一个路由前缀 http://127.0.0.1:5000/user/login/蓝本之间的重定向from flask import Blueprint,url_for,redirect user = Blueprint('user',__name__) #实例化蓝本对象 参数1 为蓝本的名字 参数2为所在的模块 @user.route('/login/') def login(): # return '蓝本登录' return redirect(url_for('posts.send_posts')) #指定跳转到对应的蓝本的视图函数中三、当前flask对象的代理对象(current_app)获取app对象上的所有的配置app = Flask(__name__) #添加配置俩种方式 app.config['SECRET_KEY'] = '123' #给flask 添加了一个配置 secret_key app.name = 'zhangsan' #给flask 添加了一个配置 secret_key manager = Manager(app) #实例化并加载app获取配置信息from flask import Blueprint,current_app posts = Blueprint('posts',__name__) #获取配置的两种方式 @posts.route('/send_posts/') def send_posts(): # return '发帖子{}'.format(current_app.config['SECRET_KEY']) #获取secret_key的值 return '发帖子{}'.format(current_app.name) #获取name的值四、cookie 和 session附:cookie和session的区别和用法1.cookie原因: http协议 无状态协议在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。(1) 设置cookieResponse.set_cookie( key, 键 value,值 max_age=None, #存活的时间 单位是秒 expires=None,#过期时间 path = '/',# cookie的有效路径 )实例#cookie的操作 @user.route('/set_cookie/') def set_cookie(): response = make_response('设置cookie') #构造响应 response.set_cookie('name','张三') #设置cookie 没有设置过期时间 # return '设置了cookie' #错误的响应 没有将cookie响应给用户 return response注意: 如果没有设置cookie的存活时间 则cookie的过期时间为 当前浏览会话结束(关闭浏览器)(2) 设置cookie 并设置过期时间#设置cookie并设置过期时间 @user.route('/set_cookie_timeout/') def set_cookie_timeout(): response = make_response("设置cookie并设置过期时间") #max_age 设置过期时间 response.set_cookie('name','zhangsan',max_age=10) #设置活10秒 #expires 设置过期时间 lifttime = time.time()+20 response.set_cookie('name','lisi',expires=lifttime) return response(3) 获取cookie#获取cookie @user.route('/get_cookie/') def get_cookie(): print(request.cookies) return 'cookie的值为{}'.format(request.cookies.get('name'))(4) 删除cookie#删除cookie @user.route('/del_cookie/') def del_cookie(): response = make_response('删除cookie') # response.delete_cookie('name') #删除key为 name的cookie response.set_cookie('name','',max_age=0) return response2.session概述:服务器要区分不同的用户请求 要通过浏览器的cookie来实现 在浏览器访问服务器的时候 会给当前的用户设置一个唯一的id号(sessionid) 用户每次在请求的时候 只需要携带着sessionid来请求我 就可以 服务器就可以根据不同的唯一sessionid来区分不同用户的请求注意: 要生成sessionid 就需要给加密种子(密钥)secret_key导入: from flask import session(1) 设置session#设置session @mysession.route('/set_session/') def set_session(): session['id'] = 1 session['username'] = '张三' return '设置session'(2) 设置session并设置过期时间#设置session并设置过期时间 @mysession.route('/set_session_timeout/') def set_session_timeout(): session.permanent = True #设置session持久化存储 current_app.permanent_session_lifetime = timedelta(seconds=100) #设置过期时间为100秒 session['id'] = 1 session['username'] = '张三' return '设置session及过期时间'(3) 获取session#获取session @mysession.route('/get_session/') def get_session(): print(session) return 'id值为:{} username为:{}'.format(session.get('id'),session.get('username'))(4) 删除session#删除session @mysession.route('/del_session/') def del_session(): # session.pop('username') # session.pop('id') session.clear() return '删除了session值'五、钩子函数概述: 介于请求和响应之间,过滤掉不安全或者无意义的请求。作用: 使用钩子函数进行过滤。如果没有登录,但是访问了需要登录的路由地址的时候,这时就禁止访问或自动跳转到登录页,否则就可以正常访问。1.在启动文件(manage.py)中使用钩子函数钩子函数功能描述before_first_request第一次请求之前before_request每次请求之前after_request每次请求之后teardown_request每次请求之后 即使请求有异常出现实例#钩子函数 第一次请求之前 @app.before_first_request def before_first_request(): print('before_first_request') #每次请求之前 @app.before_request def before_request(): print(request.path) print(request.host) print(request.headers.get('User-Agent')) if request.host != '127.0.0.1:5000' or not request.headers.get('User-Agent'): abort(500) print('before_request') #请求之后 @app.after_request def after_request(r): print('after_request') return r #请求之后 @app.teardown_request def teardown_request(r): print('teardown_request') return r2.在蓝本中使用钩子函数钩子函数功能描述before_app_first_request第一次请求之前before_app_request每次请求之前after_app_request每次请求之后teardown_app_request每次请求之后 即使请求有异常出现实例#钩子函数 第一次请求之前 @middle.before_app_first_request def before_first_request(): print('before_first_request') #每次请求之前 @middle.before_app_request def before_request(): print(request.path) print(request.host) print(request.headers.get('User-Agent')) if request.host != '127.0.0.1:5000' or not request.headers.get('User-Agent'): abort(500) print('before_request') #请求之后 @middle.after_app_request def after_request(r): print('after_request') return r #请求之后 @middle.teardown_app_request def teardown_request(r): print('teardown_request') return r
2019年08月07日
947 阅读
0 评论
0 点赞
2019-08-06
第1节、Flask基础01
Flask框架学习的整体内容1.Flask基础2.模板引擎3.flask表单4.文件上传5.邮件发送6.模型(model)7.拆分MVT8.项目的需求分析(博客)9.Flask项目10.flask部署11.flask-resfulFlask web框架分为MVCM: 模型 (数据的操作)V : 视图C : 控制器python中 MVTM: 模型 (数据的操作)V : 控制器T: 视图web 架构B/S浏览器/服务器C/S客户端/服务器Flask模块概述: flask是一个非常小的python web框架,被称为微型框架,只提供了一个强健的核心 ,其它功能都是通过第三方扩展库来实现的。组成: 路由、模板、模型、控制器、wsgi系统、jinja2模板引擎一、完整的运行(1) 实例from flask import Flask #导入Flask app = Flask(__name__) #实例化flask类 __name__ 必传参数 当前执行的模块 #路由地址 请求当前的路由 127.0.0.1:5000 @app.route('/') def index(): #执行请求的函数 控制器 return 'hello flask' #响应 响应一段字符串 if __name__ == '__main__': #执行的模块 只在主程序执行 app.run() #运行flask(2) 路由地址@app.route('/地址/')def 函数名称([参数...]): pass请求地址为:http://ip地址:端口号/地址/(3) app.run参数参数参数说明debug是否开启调试模式 默认False 开启以后自动重新加载代码threaded开启多线程 默认是不开启的 Truehost主机名 默认是127.0.0.1 在其它反问的时候 127.0.0.1-127.255.255.254 本地ip 0.0.0.0本地,网络都可以请求port端口号 默认5000实例:if name == 'main': #执行的模块 只在主程序执行 app.run( host='0.0.0.0',port=5001,debug=True,threaded=True) #运行flaskhttp://10.0.121.138:5001/http://127.0.0.1:5001/二、视图函数(1) 无参路由@app.route('/') def index(): pass(2) 带一个参数的路由#传递一个参数的路由 @app.route('/args/<page>/') def args(page): print(type(page)) return 'page的值为{}'.format(page)注意: 路由值都为字符串类型(3) 传递多个参数#传递多个参数 类型1: #http://127.0.0.1:5000/manyarg/1/2/ @app.route('/manyarg/<arg1>/<arg2>/') def manyArg(arg1,arg2): print(type(arg1),type(arg2)) return 'arg1的值为{} arg2的值为{}'.format(arg1,arg2) #传递多个参数 类型2: #http://127.0.0.1:5000/manyarg/1_2/ @app.route('/manyarg/<arg1>_<arg2>/') def manyArg(arg1,arg2): print(type(arg1),type(arg2)) return 'arg1的值为{} arg2的值为{}'.format(arg1,arg2) #运行结果:arg1的值为1 arg2的值为2(4) 限制参数的类型intstringpathfloat@app.route('/argtype/<int:arg>/') #只能传递整形 @app.route('/argtype/<string:arg>/') #字符串 默认就是字符串 @app.route('/argtype/<path:arg>/') #路径 将/不再认为是分隔符 而是值的一部分 其实也是字符串类型 @app.route('/argtype/<float:arg>/') #浮点形 def argType(arg): print(type(arg)) print(arg) return '参数类型'注意:路由地址末尾的‘/’ 建议都加上,如果在访问需要‘/’的路由的时候没有添加‘/’的话,浏览器会自动添加上‘/’参数写在<>内,<>内的参数和前面的路由地址构造出一个全新的路由地址参数类型默认为 string三、响应 response(1) 指定响应的状态码实例@app.route('/') def index(): return '值',404 #code状态码 必须是标准库中的(2) 通过make_response 构造响应(make_response)#make_response 构造响应 @app.route('/response/') def res(): # response = make_response('make_response构造响应') response = make_response('make_response构造响应',500) #将响应的状态码 设置为 500 return response四、重定向( url_for,redirect)(1) redirect 的使用redirect不带参数的跳转@app.route('/') def index(): return 'index' @app.route('/login/') def login(): return redirect('/') #参数为跳转的路由地址redirect带参数的跳转@app.route('/test/<arg1>/<arg2>/') def test(arg1,arg2): return 'test' @app.route('/login/') def login(): return redirect('/test/1/2/') #参数为跳转的路由地址(2) url_for 根据 视图函数名称 反向构造出路由地址@app.route('/'): #不带参数 return url_for('index') # / return url_for('indexx') #当前indexx视图函数不存在 #Could not build url for endpoint 'indexx'. Did you mean 'index' instead? #带参数 return url_for('test',arg1=1,arg2=2) # /test/1/2/ return url_for('test',arg1=1,arg2=2) # 如果 arg1和arg2是路由地址的参数 则拼凑的地址为 /test/1/2/ 如果不是则 /test/?arg1=1&arg2=2(3) redirect和url_for的组合重定向@app.route('/test/') def test(): return redirect(url_for('index')) # 跳转到 首页视图 /注意: 如果视图函数不存在则会报错HTTP状态码所代表的含义消息成功重定向请求错误服务器错误五、abort 抛出http标准状态码中的错误(abort)@app.route('/test/') def test2(): print('404') abort(404)注意: 类似raise 上面的代码正常执行 下面代码不再执行捕获http状态码的错误#捕获404状态码的错误 @app.errorhandler(404) def page_not_found(e): #e为错误的信息 return '404-------{}'.format(e)六、请求(request)作用:获取用户请求所带的数据概述:浏览器发送到服务器的所有请求被flask接收以后,创建出request对象,request对象用在视图函数中,用于获取请求的数据request对象由flask创建,想要获取请求数据,直接导入模块即可request属性:url 获取完整请求的url地址 print('获取完整请求的url地址',request.url)base_url 去掉get传参的urlprint('去掉get传参的url',request.base_url)host_url 只有主机地址和端口号 print(' 只有主机地址和端口号',request.host_url)path 请求的路由地址print('请求的路由地址',request.path)method 请求的方法 print('请求的方法',request.method)args 请求的get传参print(' 请求的get传参',request.args) print(' 请求的get传参',request.args['name'])#当返回的args中不存在name时报错 print(' 请求的get传参',request.args.get('name')) #当返回的args中不存在name时不报错 print(' 请求的get传参',request.args.getlist('name'))#args存在多个name时,该方法返回所有的name对应的值--列表form 获取表单post传递过来的数据 print('获取完整请求的url地址',request.form)files 文件上传 print('获取完整请求的url地址',request.files)headers 获取请求的头信息 想要获取哪个 使用request.headers.get(key)进行获取print('请求头信息',request.headers.get('User-Agent')) print('请求头信息',request.headers.get('Host'))cookies 获取cookieprint('获取请求过来的cookie',request.cookies) print('获取请求过来的cookie',request.cookies.get('sessionid'))json 获取请求过来的json数据print('获取请求过来的json数据',request.json)实例@app.route('/') def index(): print('获取完整请求的url地址',request.url) print('去掉get传参的url',request.base_url) print(' 只有主机地址和端口号',request.host_url) print('请求的路由地址',request.path) print('请求的方法',request.method) print('请求的get传参',request.args) print('请求的get传参',request.args['name']) print('请求的get传参',request.args.get('name')) print('请求的get传参',request.args.getlist('name')) print('请求的get传参',request.args['age']) print('请求的get传参',request.args.get('age')) print(' 获取表单post传递过来的数据',request.form) print('获取文件上传',request.files) print('请求头信息',request.headers.get('User-Agent')) print('请求头信息',request.headers.get('Host')) print('获取请求过来的cookie',request.cookies) print('获取请求过来的cookie',request.cookies.get('sessionid')) print('获取请求过来的json数据',request.json) return 'index'
2019年08月06日
670 阅读
0 评论
0 点赞
2019-07-31
8.用Scrapy框架进行爬取的案例
title: 8.用Scrapy框架进行爬取的案例date: 2019-07-31 14:15:50tags:爬虫Scrapycategories: Pythoncopyright: false只有一个页面,无需跳转的爬取案例文件下载创建项目: scrapy startproject 项目名scrapy startproject myFirstScrapy创建爬虫: scrapy genspider 爬虫名 域名scrapy genspideer intersting u148.cn
2019年07月31日
891 阅读
0 评论
0 点赞
2019-07-31
7.Scrapy框架
Scrapy概述:是一个爬虫框架,提取结构性的数据。其可以应用在数据挖掘,信息处理等方面。提供了许多的爬虫的基类,帮我们更简便使用爬虫。基于Twisted首先安装依赖库Twistedpip install (依赖库的路径)在这个网址http://www.lfd.uci.edu/~gohlke/pythonlibs#twisted 下面去寻找符合你的python版本和系统版本的Twisted然后在安装scrapy框架pip install scrapy【注意】路径名不能有中文,不能用管理员进入cmd,电脑系统用户路径不能是中文框架简介该框架是一个第三方的框架,许多功能已经被封装好(比如:下载功能)由五部分构成:引擎、下载器、爬虫、调度器、管道(item和pipeline)以上五部分我们只需要关心其中的两部分:爬虫和管道spiders:蜘蛛或爬虫,我们分析网页的地方,我们主要的代码写在这里管道:包括item和pipeline,用于处理数据其他部分:了解引擎:用来处理整个系统的数据流,触发各种事务(框架的核心)下载器:用于下载网页内容,并且返回给蜘蛛(下载器基于Twisted的高效异步模型)调度器:用来接收引擎发过来的请求,压入队列中等处理任务简单用法(1)创建项目指令:scrapy startproject 项目名 (2)项目目录结构 firstSpider firstSpider spiders 爬虫目录(写代码位置) __init__.py myspider.py 爬虫文件,以后的爬虫代码写在这里 __init__.py items.py 定义数据结构地方 middlewares.py 中间件(了解) pipelines.py 管道文件 settings.py 项目配置文件 scrapy.cfg 项目创建处理,里面是没有爬虫的,我们需要通过指令来创建一个爬虫:cd firstSpider/firstSpider scrapy genspider qiubai “www.qiushibaike.com" 以上指令完事后,就会在firstSpider/firstSpider/spiders里面自动创建一个qiubai.pyqiubai.py文件:name: 爬虫的名字,启动的时候根据爬虫的名字启动项目allowed_domains:允许的域名,就是爬取的时候这个请求要不要发送,如果是该允许域名之下的url,就会发送,如果不是,则过滤掉这个请求,这是一个列表,可以写多个允许的域名start_urls:爬虫起始url,是一个列表,里面可以写多个,一般只写一个def parse(self, response): pass #这个函数非常重要,就是你以后写代码的地方,parse函数名是固定的, #当收到下载数据的时候会自动的调用这个方法,该方法第二个参数为 #response,这是一个响应对象,从该对象中获取html字符串,然后解析之 #【注】这个parse函数必须返回一个可迭代对象(3)定制item.py, 其实就是您的数据结构,格式非常简单,复制粘贴即可(4)撰写蜘蛛打印response对象,简单跑一把指令:cd firstSpider/firstSpider/spidersscrapy crawl qiubai 【注意】第一次抓取的时候如果出错,则 pip install pypiwin32根据response获取网页内容response.text 字符串类型response.body 二进制类型(5)运行scrapy crawl qiubai -o qiubai.json 保存为json文件crapy crawl qiubai -o qiubai.xml 保存为xml文件scrapy crawl qiubai -o qiubai.csv 保存为csv文件用Scrapy写爬虫的一步骤:1)创建项目 scrapy startproject 项目名2)创建爬虫 scrapy genspider 爬虫名 域名3)根据需求编写item4)在spiders里面解析数据5)在管道中处理解析完的数据6)运行: scrapy crawl 爬虫名 [-o xx.json/xml/csv]原理
2019年07月31日
528 阅读
0 评论
0 点赞
2019-07-31
6.request请求的简单使用
概述:requests框架基于urllib封装的一个请求框架,、几乎包含urllib所有的请求功能,在其基础上进行了深度的拓展安装requestspip install requestsrequests的响应类res = requests.get(url) #res即为resquests的响应类属性说明encodingrequests从响应的header自动猜测出响应页面编码方式,该值默认为ISO-8859-1apparent_encodingrequests从响应页面猜测响应页面编码方式url响应的urlstatus_code响应的http状态码cookies响应的cookieselapsed发送请求到收到响应消耗的时间headers响应的headershistory请求历史headers响应的headerscontent页面源码,二进制的页面源码text也是页面源码,unicode,requests自动解码,返回str源码请求方法:requests.get(url, params=None, **kwargs) params={'':''}requests.post(url, data=None, json=None, **kwargs) data = {'':''}requests.head(url, **kwargs)requests.put(url, data=None, **kwargs)requests.patch(url, data=None, **kwargs)requests.delete(url, **kwargs)requests.request(method, url, **kwargs)以上就是requests全部的访问方法,并且全部都返回Request对象请求参数**kwargs参数说明params自动构建url,get请求时使用data提交表单,post请求时使用headers请求headerscookies请求cookiestimeout超时时间proxiesip代理json发送jsonfile发送文件(Multipart-Encoded)allow_redirectsauthverifystreamcert实例1:import requests # requests本身就是一个请求对象 res = requests.get("http://www.baidu.com/") print(res) #<Response [200]> url = "https://www.baidu.com/s?" # 加请求头 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'} # 创建参数 data = { "wd":"日本美女" } # 用requests对象发起请求 res = requests.get(url=url,headers=headers,params=data) # res是响应对象,包含响应头和响应体 # print(res.text) # 用字符串的格式提取出响应体 print(res.content) print(res.headers) # requests也不能解析js实例2:古诗文登录import requests from lxml import etree # 登录 # post请求 账户密码 两个token值 验证码 # 用登录页把验证码和token值获取出来 login_url = "https://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx?type=m" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36', 'Referer': 'https://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx?type=m' } # 访问登录页 # login_html = requests.get(url=login_url,headers=headers) # requests无法保存cookie s = requests.Session() # requests框架中会话信息用Session对象来保存 login_html = s.get(url=login_url,headers=headers) # 解析出来验证码和token html_tree = etree.HTML(login_html.text) # 提取两个token值 a = html_tree.xpath("//input[@id='__VIEWSTATE']/@value")[0] b = html_tree.xpath("//input[@id='__VIEWSTATEGENERATOR']/@value")[0] print(a,b) # 提取验证码 img_url = "https://so.gushiwen.org" + html_tree.xpath("//img[@id='imgCode']/@src")[0] img = s.get(img_url) with open("./yanzhengma.png","wb") as fp: fp.write(img.content) # 验证码处理、人工智能识别、人工手动输入 code = input("请输入验证码:") print(code) # 登录 post_url = "https://so.gushiwen.org/user/login.aspx?from=http%3a%2f%2fso.gushiwen.org%2fuser%2fcollect.aspx%3ftype%3dm " data = { '__VIEWSTATE': a, '__VIEWSTATEGENERATOR':b, 'from':'http://so.gushiwen.org/user/collect.aspx?type=m', 'email':'fanjianbo666@163.com', 'pwd':'123456', 'code': code, 'denglu':'登录' } res = s.post(url=post_url,headers=headers,data=data) print(res.text)实例3:ChinaUnix登录import requests from bs4 import BeautifulSoup # 设置代理服务器列表 proxies = {"https":"122.4.29.15:27074"} s = requests.Session() login_page = "http://bbs.chinaunix.net/member.php?mod=logging&action=login&logsubmit=yes" # 加请求头 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'} # 反爬:用户名和密码 设置隐藏域 post接口中某些参数是动态生成 # 请求登录页 # r = s.get(url=login_page,headers=headers,proxies=proxies) r = s.get(url=login_page,headers=headers) soup = BeautifulSoup(r.text,'lxml') # 动态post接口 login_params = soup.select("form.cl")[0].attrs.get("action") print(login_params) # 解决formhash的动态生成 formhash = soup.select("[name=formhash]")[0].attrs.get("value") print(formhash) # 构造请求体 data = { 'formhash': formhash, 'referer':'http://bbs.chinaunix.net/', 'username':'MrFan666', 'password':'f12345678', 'loginsubmit':'true', 'return_type':'' } # 登录接口 login_url = "http://bbs.chinaunix.net/" + login_params # 发起post请求登录 res = s.post(url=login_url,headers=headers,data=data) print(res.text)
2019年07月31日
655 阅读
0 评论
0 点赞
2019-07-26
5.懒加载及自动化测试框架
懒加载技术:用的时候再加载懒加载的要点如下:图片进入可视区域之后请求图片资源;对于电商等图片较多,页面很长的业务场景很适用;可以减少无效资源的加载;并发加载的资源过多会阻塞js的加载,影响网站的正常使用;常见的图片懒加载形式:src == src2案例:http://sc.chinaz.com/tupian/xingganmeinvtupian.html 获取图片,保存本地import urllib.request import urllib.parse from lxml import etree import os headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36', } def get_request(url,page): #1.处理url:url中需要携带页码值(第一页和非第一页的url是不同的) if page==1: url=format(url%'') else: pn='_'+str(page) url=format(url%pn) return urllib.request.Request(url,headers=headers) def download_images(image_url_list): dir_name='性感美女集' #在当前目录创建一个文件夹 if not os.path.exists(dir_name): os.mkdir(dir_name) for image_url in image_url_list: #通过url获取了图片的二进制数据值 request=urllib.request.Request(image_url,headers=headers) image_data=urllib.request.urlopen(request).read() image_name=os.path.basename(image_url) path=os.path.join(dir_name,image_name) with open(path,'wb') as fp: fp.write(image_data) start_page=int(input('enter start page num:')) end_page=int(input('enter end page num:')) url='http://sc.chinaz.com/tupian/xingganmeinvtupian%s.html' for page in range(start_page,end_page+1): request=get_request(url,page)#获取一个自定义的请求对象 response=urllib.request.urlopen(request) content=response.read().decode()#获取响应回来的网页源码数据 tree=etree.HTML(content) image_url_list=tree.xpath('//div[@id="container"]//img/@src2') download_images(image_url_list)#下载图片selenium(浏览器自动化测试框架)selenium是什么? 是一个Python的一个第三方库,对外提供的接口可以操作你的浏览器,然后让浏览器完成自动化的操作使用selenium安装:pip install selenium操作谷歌浏览器,首先必须有谷歌浏览器的一个驱动除了谷歌,该模块也支持其他的一些主流浏览器,比如IE,Firefox等,但是需要对应的驱动谷歌驱动chromedriver下载地址1谷歌驱动chromedriver下载地址2谷歌驱动和谷歌浏览器版本关系映射表chromedriver版本支持的Chrome版本v2.41v67-69v2.40v66-68v2.39v66-68v2.38v65-67v2.37v64-66v2.36v63-65v2.35v62-64v2.34v61-63v2.33v60-62v2.32v59-61v2.31v58-60v2.30v58-60v2.29v56-58v2.28v55-57v2.27v54-56v2.26v53-55v2.25v53-55v2.24v52-54v2.23v51-53v2.22v49-52v2.21v46-50v2.20v43-48v2.19v43-47v2.18v43-46v2.17v42-43v2.13v42-45v2.15v40-43v2.14v39-42v2.13v38-41v2.12v36-40v2.11v36-40v2.10v33-36v2.9v31-34v2.8v30-33v2.7v30-33v2.6v29-32v2.5v29-32v2.4v29-32代码操作from selenium import webdriver browser = webdriver.Chrome(path) #path为驱动文件所在路径 browser.get(url)使用下面的方法,查找指定的元素进行操作即可find_element_by_id 根据id找节点find_elements_by_name 根据name找find_elements_by_xpath 根据xpath查找find_elements_by_tag_name 根据标签名找find_elements_by_class_name 根据class名字查找find_elements_by_css_selector 根据选择器查找find_elements_by_link_text 根据链接内容查找案例:打开百度,搜索美女,点击某一张图片,关闭浏览器from selenium import webdriver import time # 模拟创建一个浏览器对象,然后通过对象去操作浏览器 path = 'chromedriver.exe' browser = webdriver.Chrome(executable_path=path) url = 'http://www.baidu.com/' #使用浏览器发起指定请求 browser.get(url) time.sleep(3) # 查找input输入框 my_input = browser.find_element_by_id('kw') # 往框里面写文字 my_input.send_keys('美女') time.sleep(3) # 查找搜索按钮 button = browser.find_elements_by_class_name('s_btn')[0] button.click()#点击指定按钮 time.sleep(3) # 找到指定图片点击 #image = browser.find_elements_by_class_name('op-img-address-link-imgs')[2] #image.click() a=browser.find_elements_by_link_text('http://www.baidu.com/link?url=Zx3hGmvjjtOKPqT4FPQhDx-wPTWdM1BMh3tCEYrYKUGMKM67M7vV9LxRU74lo9KJ')[0] a.click() time.sleep(3) # 关闭浏览器,退出浏览器 browser.quit()PhantomJS(无界面浏览器)自动化框架用法参照seleniumPhantomJS官方下载地址案例1:from selenium import webdriver import time path = r'C:\Users\Administrator\Desktop\爬虫授课\day05\ziliao\phantomjs-2.1.1-windows\bin\phantomjs.exe' browser = webdriver.PhantomJS(executable_path=path) url='https://www.baidu.com' browser.get(url) time.sleep(3) #browser.page_source #返回当前网址的页面源代码 browser.save_screenshot('./baidu1.png') my_input = browser.find_element_by_id('kw') # 往框里面写文字 my_input.send_keys('美女') time.sleep(3) browser.save_screenshot('./baidu2.png') # 查找搜索按钮 button = browser.find_elements_by_class_name('s_btn')[0] button.click()#点击指定按钮 time.sleep(3) browser.save_screenshot('./baidu3.png') # 找到指定图片点击 image = browser.find_elements_by_class_name('op-img-address-link-imgs')[2] image.click() time.sleep(3) browser.save_screenshot('./baidu4.png') # 关闭浏览器,退出浏览器 browser.quit()selenium+phantomjs 就是爬虫终极解决方案:有些网站上的内容信息是通过动态加载js形成的,所以使用普通爬虫程序无法回去动态加载的js内容。案例2:下拉滚动条到底部(豆瓣电影下拉)from selenium import webdriver import time url='https://movie.douban.com/typerank?type_name=%E6%81%90%E6%80%96&type=20&interval_id=100:90&action=' #发起请求前,可以让url表示的页面动态加载出更多的数据 path = r'C:\Users\Administrator\Desktop\爬虫授课\day05\ziliao\phantomjs-2.1.1-windows\bin\phantomjs.exe' #创建无界面的浏览器对象 bro=webdriver.PhantomJS(path) #发起url请求 bro.get(url) time.sleep(3) #截图 bro.save_screenshot('1.png') #执行js代码(让滚动条向下偏移n个像素(作用:动态加载了更多的电影信息)) js='document.body.scrollTop=2000' bro.execute_script(js)#该函数可以执行一组字符串形式的js代码 time.sleep(4) bro.save_screenshot('2.png') time.sleep(2) #使用爬虫程序爬去当前url中的内容 bro.quit()
2019年07月26日
688 阅读
0 评论
0 点赞
1
2
3