Scrapy
环境要求
scrapy 使用2.5.1, scrapy-redis 使用0.7.2
pip uninstall scrapy #卸载
pip install scrapy==2.5.1 # 安装指定版本
scrapy version # 提示2.5.1表示版本正确
降低OpenSSL版本
scrapy version --verbose
pip uninstall cyptography
pip install cryptography==36.0.2
创建项目
scrapy startproject 项目名称 #创建项目
cd 项目名称
scrapy genspider 爬虫名字 网站域名 #生成spider
Hong-笔记
1. 创建爬虫项目
和以前的python不一样, scrapy不能直接创建python文件, 需要在命令行内, 使用指令创建项目
命令:
scrapy startproject scrapy_baidu_091
创建的项目需要注意:
项目名字不允许使用数字开头, 不能包含中文
2, 创建爬虫文件
注意:
创建爬虫文件, 需要在spiders文件夹中去创建爬虫文件
scrapy genspider 爬虫文件的名字 要爬取的网页
进入到spider文件夹内, 然后cmd执行命令
如: scrapy genspider baidu www.baidu.com
一般不会写http, 直接写域名
scrapy genspider tc https://bj.58.com/sou/?key=%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91&classpolicy=jianzhi_B
3, 运行爬虫代码
scrapy crawl 爬虫的名字
如: scrapy crawl baidu
项目介绍
- allowed_domains 数组,可以是多个网站, 逗号隔开, 用来屏蔽你爬取的网页上一些广告等功能
- start_urls 爬虫的起始url, 也可以是多个, 逗号隔开
settings.py
- USER_AGENT
全局配置User-Agent, 以后的每一次请求, 都会带这个配置
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.76"
- ROBOTSTXT_OBEY 关闭rebot协议
ROBOTSTXT_OBEY = False
- CONCURRENT_REQUESTS
并发请求数, 默认是异步的, 如果请求服务器过多, 会提示429, 请求过多, 这时可以调整CONCURRENT_REQUESTS的值, 一般不动
CONCURRENT_REQUESTS = 32
- DOWNLOAD_DELAY 访问的延迟, 访问第一个请求之后, 访问第二个请求时, 停1s, 访问第三个请求时, 再停1s,访问第四个请求, 继续停1s....
DOWNLOAD_DELAY = 1
Flask Web框架
中文文档: 欢迎来到 Flask 的世界 — Flask 中文文档 (2.1.2) (dormousehole.readthedocs.io)
库安装到真实环境
pip install flask==2.2.3
Flask 基于Python的Web开发的"微"框架
Flask 依赖三个库
Jinja2 模版引擎{% %} 模版: 静态html+模版语言{% %}
Werkzeug WSGI工具集
Flask的框架流程:
Python创建虚拟环境
#安装虚拟环境
pip install virtualenv virtualenvwrapper-win
#查看虚拟环境
workon
#创建新的虚拟环境
mkvirtualenv flask2env
#删除虚拟环境
rmvirtualenv flask2env
#进入虚拟环境
workon flask2env
第一个Flask项目创建
workon flask2env
#查看当前有那些库
pip list
#安装flask库
pip install flask==2.2.3
#查看自己安装的依赖包有那些
pip freeze
使用IDE创建Flask项目
第一次使用IDE创建Flask项目出现的问题:
1, 新创建的Flask项目, 启动提示: ImportError: cannot import name 'url_quote' from 'werkzeug.urls'
解决:
这个错误是因为你的Werkzeug库版本可能过高,而你的Flask项目使用的是旧的Werkzeug API
pip install Werkzeug==0.16.1
2, 之后又出现了新错误
TypeError: LocalProxy.init() got an unexpected keyword argument 'unbound_message'
解决:
这个错误可能是由于你的 Flask 版本与 Werkzeug 版本不兼容导致的。在 Flask 2.0.0 版本中,移除了对 unbound_message 参数的使用,但在旧版本的 Flask 中,这个参数可能仍在使用。
pip install --upgrade Flask
解决Pycharm启动后, 端口IP修改无效问题
第一种方式:
第二种方式:
Flask - route路由
路由参数
路由:
将从客户端发送过来的请求分发到指定的函数上
路由通过装饰器对应视图函数, 并且可以接受参数, 多以我们只需要在视图函数上使用装饰器即可
语法
#基础路由
@app.route("rule")
def hello():
return "Hello"
#传参路由
@app.route("rule/<id>")
def hello(id):
return "Hello %s" % id
写法
<converter:variable_name>
convert: 参数类型
string 接受任何没有斜杠"/"的文件(默认)
int 整形
float 浮点形
path 接受路径, 可接收斜线"/"
uuid 只接受UUID字符串, 唯一码, 一种生成规则
any 可以同时指定多种路径, 进行绑定
请求方式
默认支持GET, HEAD, OPTIONS, 如果想支持某一请求方式, 需手动添加
@app.route("/rule", methods=['GET','POST'])
def hello():
return 'hello'
method可以指定的方法有:
GET, POST,HEAD,PUT,DELETE
Flask里的全局对象 --- Request
服务器再接受到客户端请求后, 会自动创建Request对象
由Flask框架创建, Request对象不可修改
属性
url 完整请求地址
base_url 去掉Get参数的url
host_url 只有主机和端口号的url
path 路由中的路径
method 请求方法
remote_addr 请求的客户端地址
args Get请求参数
form POST请求参数
files 文件上传
headers 请求头
cookies 请求中的cookies
user_agent 用户代理, 包括浏览器和操作系统信息
ImmutableMultiDict(类字典对象)类型:
类似字典的数据结构,与字典的区别,可以存在相同的键, 类字典对象特点就是: 允许有重复的key
args和form都是ImmutableMultiDict的对象
ImmutableMultiDict中数据获取方式:
dict['uname"] 或 dict.get('uname')
获取指定key对应的所有值:
dict.getlist("uname")
args 和from的区别
args:
- get请求参数的包装, args是一个ImmutableMultiDict对象, 类字典结构对象
- 数据存储也是key-value
- 外层是列表, 列表的元素是元祖, 元祖中左边是key, 右边是value
form:
- 存储结构跟args一致
- 默认是接收post参数
- 还可以接收PUT, PATCH参数
from flask import Blueprint,request
@blue.route('/request/',methods=['GET','POST'])
def get_request():
pass
print(request.method) # 获取Flask框架中的request对象, 注意需要先import
'''
这个request是ImmutableMultiDict类字典对象, 特点是允许有多个重复的key
'''
print(request.args)
print(request.args['name'],request.args['age'])# 如果没有这个key, 会报错!
print(request.args.get('name')) #即使没有这个key也不会报错
print(request.args.getlist('name'))#如果有多个name的key, 应该用 getlist, 不然只会返回一个值
return 'hello'
Flask里的全局对象 --- Response
Response: 服务器返回给客户端的数据
1, 直接返回字符串, 可以返回文本内容, 状态码
2, render_template 渲染模版, 将模版转换成字符串
3, 返回json
4, 自定义响应对象
4.1 使用make_response(data,code)
- data 返回的数据内容
- code 状态码
4.2 使用Response对象
重定向
redirect("http:www.baidu.com")
redirect("/getreponse")
@blue.route('/response/',methods=['POST'])
def get_response():
pass
return 'response ok' #返回字符串
return render_template('index.html',name="张三",age="历史") #模版渲染并传参给模版引擎
data = {'name':'张三','age':'李四'}
return data #返回json数据
return jsonify(data) #返回序列化json数据
#返回自定义的response对象
html = render_template('index.html',name="张三",age="历史")
print(html,type(html))
res = make_response(html,200)
return res
#不使用make_response方法, 自定义response对象
res = Response(html)
return res
Cookies的作用
Flask里的全局对象 --- Session
Session:
服务器端会话技术, 依赖于cookies
特点:
- 服务端的会话技术
- 所有数据都存储在服务器中
- 默认存储在内存中
- 存储结构也是key-value形势, 键值对
- session是离不开cookies的
Flask中的session是全局对象, 类似于之前的request对象
常用操作:
设置session
session['key'] ='value'
获取session
session.get(key,default=None) 根据建获取获取值
删除session
session.pop(key) 删除某一个值
session.clear() 清楚所有
cookies和session的区别:
cookies:
1, 在浏览器中存储
2, 安全性较低
3, 可以减轻服务器的压力
session:
1, 在服务器存储
2, 安全性高
3, 对服务器要求高
4, 依赖cookies
模型相关包安装
#安装flask-sqlalchemy (用于ORM)
pip install flask-sqlalchemy -i https://pypi.douban.com/simple
#安装flask-migrate(用于数据迁移)
pip install flask-migrate -i https://pypi.douban.com/simple
#安装pymysql (Mysql驱动)
pip install pymysql -i https://pypi.douban.com/simple
Flask的ORM
Flask 使用Python自带的ORM: SQLAlchemy
针对于Flask的支持, 安装插件 flask-sqlalchemy
pip install flask-sqlalchemy
连接SQLite
SQLite连接的URI:
DB_URI = sqlite:////sqlite3.db
连接Mysql
USERNAME='root'
PASSWORD='root'
HOSTNAME='localhost'
PORT='3306'
DATABASE='db'
格式:
mysql+pymysql://USERNAME:PASSWORD@HOSTNAME:PORT/DATABASE
配置URL
DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(
USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE
)
在Flask里使用ORM
链接数据需要指定配置:
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI #配置连接数据库的路径
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=False #禁止对象追踪修改
SQLite数据库连接不需要额外驱动, 也不需要用户名和密码
#再Flask项目中的使用
db = SQLAlchemy()
db.init_app(app)
创建模型
class Person(db.Model):
__tablename__='person'
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(16),unique=True)
#模型Model: 就是一个类
#必须继承db.Model, 才是一个模型类, 不然就是一个普通的类
class User(db.Model):
#表名
__tablename__='tb_user'
#定义表字段
id = db.Column(db.Integer, primary_key=True,autoincrement=True)
name = db.Column(db.String(30), unique=True,index=True)
age = db.Column(db.Integer,default=1)
sex = db.Column(db.Boolean,default=True)
'''
db.Column: 字段
db.Integer: 整数
primary_key=True 主键
autoincrement=True 自动递增
db.String(30) varchar(30) 可变字符串
unique=True 唯一约束
index=True 普通索引
'''
字段类型
Integer
Float
String
常用约束:
primary_key
autoincrement
unique
default
代码控制数据库简单操作
代码控制数据库简单操作:
创建数据库,表
db.create_all()
删除表:
db.drop_all()
在事务中处理, 数据插入
db.session.add(object)
db.session.commit()
获取所有数据
Person.query.all()
数据迁移
安装
pip install flask-migrate
初始化
使用app和db进行migrate对象初始化
from flask_migrate import Migrate
migrate = Migrate()
migrate.init_app(app=app,db=db)
数据迁移命令:
再cm或Terminal先进入到项目目录:
然后输入命令:
flask db init 创建迁移文件夹migrates, 只调用一次
flask db migrate 生成迁移文件
flask db upgrade 执行迁移文件的升级
flask db downgrade 执行迁移文件的降级
模型相关实例查看demo8
数据迁移的详细步骤:
1, 安装好数据迁移的包 flask-sqlalchemy和flask-migrate
2, 在exts.py中初始化Migrate和SQLAlchemy
3, 在models中定义好模型
4, 在views.py中一定要导入models模块
from .models import *
5, 配置好数据库(sqlite或者mysql)
6, 执行数据迁移命令:
a, 在cmd或者Terminal进入项目目录(app.py所在目录)
b, 然后输入命令:
flask db init 创建迁移文件夹migrates, 只调用一次
flask db migrate 生成迁移文件
flask db upgrade 执行迁移文件中的升级
flask db downgrade 执行迁移文件中的降级
7, 使用Navicat查看数据库内容
对数据库的操作
.exts.py
第三方的插件都在这里, 比如连接数据库, 或者数据迁移的插件
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
db = SQLAlchemy()
migrate = Migrate()
def init_exts(app):
db.init_app(app=app)
migrate.init_app(app=app,db=db)
models.py
对数据库的定义都在models.py
from .exts import db
#类 --> 表
# 类属性 --> 表字段
# 对象 --> 表里的一条数据
class User(db.Model):
__tablename__='tb_user'
id = db.Column(db.Integer, primary_key=True,autoincrement=True)
name = db.Column(db.String(30), unique=True,index=True)
age = db.Column(db.Integer,default=1)
views.py
操作数据库
#一定要导入model, 不然model.py不会执行
from . models import *
#表操作
#数据的操作在这里, 表结构的更改, 在models.py里, 然后进行数据迁移
#增: 添加数据
@blue.route('/useradd/')
def user_add():
#添加单条数据
u = User()
u.name = 'ikun'
u.age = 24
# db.session.add(u); #将u对象添加到session中
# db.session.commit(); #同步到数据库中
#添加多条数据
users = [];
for i in range(10,30):
u = User();
u.name = '蔡徐坤' + str(i)
u.age = i;
users.append(u)
try:
db.session.add_all(users)
db.session.commit(); #事务提交
except Exception as e:
db.session.rollback() #回滚
db.session.flush() #清空缓存
return "批量添加数据失败" + str(e);
return "批量添加数据成功";
@blue.route('/userdel/')
def user_del():
u = User.query.first();#查询第一条数据
db.session.delete(u)
db.session.commit();
return '删除成功'
@blue.route('/userupdate/')
def user_update():
u = User.query.first();#查询第一条数据
u.name = '蔡徐坤-修改'
u.age = 1000
#直接修改, 提交就行了
db.session.commit();
return '修改成功'
补充
查询数据
过滤器
filter() 把过滤器添加到原查询上, 返回一个新查询
filter_by() 把等值过滤器添加到原查询上, 返回一个新查询
limit() 使用指定的值限制原查询返回的结果数量, 返回一个新查询
offset() 偏移原查询返回的结果, 返回一个新查询
order_by() 根据指定条件对原查询结果进行排序, 返回一个新查询
group_by() 根据指定条件对原查询结果进行分组, 返回一个新查询
常用查询
all() 以列表形式返回查询的所有结构, 返回列表
first() 返回查询的第一个结构, 如果没有结果, 则返回None
first_or_404() 返回查询的第一个结果, 如果没有, 则终止请求, 返回404错误响应
get() 返回指定主键对应的行, 如果没有对应的行, 则返回None
get_or_404() 返回指定主键对应的行, 如果没有找到指定的主键, 则终止请求,返回404错误响应
count() 返回查询结果的数量
paginate() 返回一个Paginate对象, 它包含指定范围内的结果
查询属性
contains
startswith
endswith
in_
__gt__
__ge__
__lt__
__le__
逻辑运算
与 and_
filter(and_(条件),条件...)
或 or_
filter(or_(条件),条件...)
非 not_
filter(not_(条件),条件...)
实例:
查询:
persons = Person.query.all()# 获取所有
persons = Person.query.filter(Person.age>22)
# filter功能比filter_by强大
persons = Person.query.filter(Person,age==22) # filter(类,属性==值)
persons = Person.query.filter_by(age=22) # filter_by(属性=值)
persons = Person.query.filter(Person.age.__lt__(22)) #<
persons = Person.query.filter(Person.age.__le__(22)) # <=
persons = Person.query.filter(Person.age.__gt__(22)) # >
persons = Person.query.filter(Person.age.__ge__(22)) # >=
persons = Person.query.filter(Person.age.startswith('宝')) # 开头匹
persons = Person.query.filter(Person.age.endswith('宝')) # 结尾匹配
persons = Person.query.filter(Person.age.contains('宝')) # 包含
persons = Person.query.filter(Person.age.in_([11,12,22])) # in_
persons = Person.query.filter(Person.age>=20,Person.age<30) # and
persons = Person.query.filter(and_(Person.age>=20, Person.age<30)) # and_
persons = Person.query.filter(or_(Person.age>=30, Person.age<20)) # or
persons = Person.query.filter(not_(Person.age<30)) # not_
排序:
persons = Person.query.order_by('age') # 升序
persons = Person.query.order_by(desc('age')) # 降序
分页:
persons = Person.query.limit(5) #取前5个
persons = Person,query.offset(5) #跳过前5个
# 获取页码page和每页数量num
page = int(request.args.get('page'))
per_page = int(request.args.get('per_page'))
# 手动做分页
persons = Person.query.offset((page-1) * per_page).limit(per_page)
# 使用paginate做分页
persons = Person.query.paginate(page=page,per_page=per_page,error_out=False).items
paginate对象的属性:
items:返回当前页的内容列表
has_next:是否还有下一页
has_prev: 是否还有上一页
next(error_out=False): 返回下一页的Pagination对象
prev(error_out=False): 返回上一页的Pagination对象
page: 当前页的页码(从1开始)
pages: 总页数
per_page: 每页显示的数量
prev_num: 上一页页码数
next_num: 下一页页码数
query: 返回创建该Pagination对象的查询对象
total: 查询返回的记录总数
实例:
普通sql查询, 参考项目10
#查询
@blue.route('/userget/')
def user_get():
#all() 返回所有的数据, 列表形式
users = User.query.all()
print(users)
print(list(users)) #转换成列表形式
#User.query是一条sql语句, 类型是<class 'flask_sqlalchemy.query.Query'>一个查询对象
print(User.query,type(User.query))
print('----------------------')
#filter(): 过滤, 得到查询集, 类似SQL中的where, 与get()不一样, get()得到的是数据, filter()得到的是数据集
users = User.query.filter()
print(users,type(users))
# users.filter(); #可以继续filter查询
print('----------------------')
#get() 查询对应主键的数据对象
user = User.query.get(12);
# user = User.query.get_or_404(12);
print(user,type(user)) #返回User对象 <class 'App.models.User'>
'''
filter() 类似SQL中的where
filter_by() 用于等值操作的过滤
'''
print('----------------------')
users = User.query.filter(User.age==20)
print(users)
print(list(users))
#使用filter_by
users = User.query.filter_by(age=20)
# users = User.query.filter_by(age>20) #不能使用范围的, 只能使用等值的, 非等值的使用filter()
print(list(users))
print('----------------------')
#first() 第一条数据
#last() 最后一条数据
user = User.query.first()
# user = User.query.filter_by(age = 8888).first_or_404() #第一条数据不存在, 抛出404错误
print('----------------------')
users = User.query.filter();
print(users.count())
print('----------------------')
#limit(): 前几条
#offset(): 跳过前几条
users = User.query.offset(3).limit(4); #跳过前三条, 取之后的第四条数据
print(list(users))
print('----------------------')
users = User.query.order_by('age') #升序
print(list(users))
#降序 需要导包
from sqlalchemy import desc
users = User.query.order_by(desc('age'))
print(list(users))
print('----------------------')
#逻辑运算, and_, or_, not_(取反)
users = User.query.filter(User.age>20, User.age<25) #年龄20 - 25
#使用前 导包
from sqlalchemy import and_,or_,not_
users = User.query.filter(and_(User.age>20,User.age<25))
users = User.query.filter(or_(User.age>25,User.age<20))
users = User.query.filter(not_(or_(User.age>25,User.age<20)))
users = User.query.filter(not_(User.age>25))
print(list(users))
print('----------------------')
#查询属性
#contain('') 模糊查找sql的like
users = User.query.filter(User.name.contains('蔡'))
print(list(users))
#in_
users = User.query.filter(User.age.in_( [10,20,30,40,50,60] ))
print(list(users))
print('----------------------')
#startswith()
users = User.query.filter(User.name.startswith( ['蔡'] ))
print(list(users))
users = User.query.filter(User.name.endswith( ['坤']))
print(list(users))
print('----------------------')
#__gt__: 大于
#__ge__: 大于等于
users = User.query.filter(User.age.__gt__(20))
print('大于20的:',list(users))
return 'success'
分页:参考项目10
1, 手动翻页
offset().limit()
数据, 1,2,3,4,5....
页码: page = 1
每页数量: per_page=5
1-5 offset().limit(5)
6-10 offset(5).limit(5)
11-15 offset(10).limit(5)
16-20 offset(15).limit(5)
...
page=n offset( (page-1) * per_page).limit(per_page)
2, paginate对象
@blue.route('/paginate/')
def get_paginate():
#页码, 默认显示第一页
page = request.args.get('page',1)
#per_page, 每页显示的数据
per_page = request.args.get('per_page',5);
print(page,type(page))
print(per_page,type(per_page))# 5 <class 'int'>
page = int(page)
per_page = int(per_page)
#paginate()
p = User.query.paginate(page=page, per_page=per_page,error_out=False)
'''
返回的paginate对象属性
paginate对象的属性:
items:返回当前页的内容列表
has_next:是否还有下一页
has_prev: 是否还有上一页
next(error_out=False): 返回下一页的Pagination对象
prev(error_out=False): 返回上一页的Pagination对象
page: 当前页的页码(从1开始)
pages: 总页数
per_page: 每页显示的数量
prev_num: 上一页页码数
next_num: 下一页页码数
query: 返回创建该Pagination对象的查询对象 没有这个属性了
total: 查询返回的记录总数
'''
print(p.items)
print(p.has_next)
print(p.has_prev)
print(p.next(error_out=False).items);
print(p.prev(error_out=False).items);
print(p.page)#返回当前的页码
print(p.pages)
print(p.per_page)
print(p.prev_num)
print(p.next_num)
print('-------------------')
# print(p.query) #没有这个属性了
print(p.total)
return render_template('book_index.html',p=p)
Flask 进阶
什么是钩子(中间件Middleware)
钩子或叫钩子函数,是指在执行函数和目标函数之间挂载的函数,框架开发者给调用方提供一个point-挂载点是一种AOP切面编程思想
常用的钩子函数
before_first_request:处理第一次请求之前执行
before_request:在每次请求之前执行,通常使用这个钩子函数预处理一些变量,实现反爬等after_request:涟册一个函数,如果没有未处理的异常抛出,在每次请求之后运行teardown_appcontext: 当APP上下文被移除之后执行的函数,可以进行数据库的提交或者回滚
类似于拦截器, 在架构的各个模块请求中间, 多加了一个方法, 进行拦截, 方便开发人员处理
Flask内置对象
g:
global全局对象
g对象是专门用来保存用户的数据的
g对象在一次请求中的所有的代码的地方,都是可以使用的突破变量存储位置限制,为数据传递添加了新的方式,比如我们在before_request产生一个数据在后面需要使用,可以保存在g对象中,在其他视图函数中就可以使用这个数据
request:
请求对象,可以获取客户端提交过来的所有请求信息
session:
会话技术,服务端会话技术的接口
current app:
app的配置信息,app对象获取,current app
使用获取当前app需要注意,一定要在程序初始化完成之后
修改外部目录的方式
如果想要修改templates模板目录或static静态目录,可以自己配置
在settings.py文件中添加BASE DIR:
import os
BASE DIR = os.path.dirname(os.path,dirname(os.path.abspath( file_)))
在__init__.py文件中添加static路径和templates路径:
static_path = os.path.join(settings.BASE DIR,'static'
template_path = os.path.join(settings.BASE DIR,'templates')
app = Flask(_name , static_folder=static_path,template folder=template path)
在views.py文件中访问模板:
@blue.route('/hello/')
def hello():
return render template('hello.html')
在模板中使用静态资源:
<link rel="stylesheet" href="[[ url for('static', filename='css/hello.css') ])">
Flask-RestFul请求
fields进行定义
marshal with进行使用
特性
显示我们设计的数据结构
默认返回的数据如果在预定义结构中不存在,数据会被自动过滤
如果返回的数据在预定义的结构中存在,数据会正常返回
如果返回的数据比预定义结构中的字段少,预定义的字段会呈现一个默认值
定义字段输出
使用字典进行定义
常用都是基本类型:string,Integer
#格式化字段
user fields = {
'msg': fields.String,
'status': fields.Integer,
'data': fields.String(attribute='private_data'),
'default_data' : fields.String(default='1')
}
定义好的格式通过装饰器进行使用
@marshal with(需要返回的数据格式), return返回字典就ok了
卸载Centos7的python
yum remove python
试了试不管用 不过python2和3可以共存, 就没管
安装python 3.11.5
#下载python源码 ,可以用get, 也可以离线下载, 网址如下
#准备需要的依赖
yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel
上述这些linux基础依赖, 必须都安装好,不然会出现很多问题, 比如下载不下来pip依赖, 启动时候提示缺少类库之类的问题
离线安装Linux yum类库
如果需要离线安装yum的类库, 可以尝试如下方式
#从有网络的本地电脑下载
yum install --downloadonly --downloaddir=./下载文件夹名称 zlib-devel bzip2-devel
openssl-devel ncurses-devel epel-release gcc gcc-c++
#拷贝到离线服务器上安装
rpm -Uvh ./*.rpm --nodeps --force
#验证某些依赖是否安装成功
rpm -qa|grep 软件包名
-------------------------------------------------------------------
#准备好openssl, 否则pip无法下载依赖, 用国内镜像也不行
wget https://www.openssl.org/source/openssl-1.1.1n.tar.gz --no-check-certificate 下载openssl1.1.1
tar -zxf openssl-1.1.1n.tar.gz 解压
cd openssl-1.1.1n
./Configure --prefix=/usr/local/openssl 设置安装目录 可以自定义 但是要记住,后面会用到
make -j && make install 编译并安装
--------------------------------------------------------------------
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
tar -xvf Python-3.11.5.tgz
cd Python-3.11.5
#注意路径对应, openssl的路径是上边安装的路径
./configure --prefix=/data/python/install --with-openssl=/usr/local/openssl --with-openssl-rpath=auto
#注意不要有 prefix不要有空格
make && make install
--------------------------------------------------------
#这时候就安装完了, 创建软连接
ln -s /data/python/install/bin/python3 /usr/bin/python3
ln -s /data/python/install/bin/pip3 /usr/bin/pip3
发布Flask项目
- 到本地项目上, 生成需要的依赖
pip3 freeze >requirements.txt
- 上传项目到服务器
- 安装虚拟环境
# 安装虚拟环境
pip3 install virtualenv
pip3 install virtualenv -i https://mirrors.aliyun.com/pypi/simple/
# 创建虚拟环境 ENV
#可能执行这个失败, 找到安装的路径, 创建软连接即可
cd /data/python/install/bin/
ln -s /data/python/install/bin/virtualenv /usr/bin/virtualenv
cd /data/work/env/
virtualenv ai
virtualenv ENV
# 切换到虚拟环境所在的目录
cd ENV
# 启用虚拟环境
source ./bin/activate
# 安装依赖清单里的库
pip3 install -r requirements.txt
# 列出当前虚拟环境所安装的依赖库
pip3 list
- 启动Flask 应用
python3 start.py
将python服务, 设置为系统自启动
# 这样的命令在ssh终端退出后,python进程也会被杀掉
python xxx.py &
#创建系统服务
vim /usr/lib/systemd/system/robot.service
rebot.service内容如下
ExecStart为服务启动时执行的命令,不能用相对路径, 一定要全路径。
这里也可以将命令写到任意的.sh文件中,这里写.sh文件的全路径也是可以的。
[Unit]
Description=robot
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/python3/bin/ENV/bin/python /usr/local/python3/bin/ENV/p3.py &
PrivateTmp=true
[Install]
WantedBy=multi-user.target
启动服务
systemctl enable robot
systemctl start robot