Django

Django 数据模型

Django 数据模型

Django 数据模型

补充一个django-admin管理后台美化步骤

安装pip install django - simpleui 修改bookpro\settings.pyINSTALLED_APPS

1INSTALLED_APPS = [
2    # ...
3    'simpleui',
4    # ...
5]

重启登录后台, 就可以看到变化

Django 数据库配置

数据库配置字段中 ENGING 常用可选配置为: ‘django.db.backends.sqlite3’,‘django.db.backends.postgresql’,‘django.db.backends.mysql’,或 ‘django.db.backends.oracle’

选择 ‘django.db.backends.sqlite3’ 时 NAME 为 数据库文件路径

1DATABASES = {
2    'default': {
3        'ENGINE': 'django.db.backends.sqlite3',
4        'NAME': BASE_DIR / 'db.sqlite3',
5    }
6}

选择 ‘django.db.backends.postgresql’,‘django.db.backends.mysql’,或 ‘django.db.backends.oracle’ NAME 数据库名称 USER / PASSWORD 数据库用户名及口令 HOST / PORT 数据库地址及端口

 1DATABASES = {
 2    'default': {
 3        'ENGINE': 'django.db.backends.mysql',
 4        'NAME': 'mydatabase',
 5        'USER': 'mydatabaseuser',
 6        'PASSWORD': 'mypassword',
 7        'HOST': '127.0.0.1',
 8        'PORT': '3306',
 9    }
10}

使用Mysql时

1# 在文件中增加
2import pymysql
3pymysql.install_as_MySQLdb()

Django 数据模型

模型都是一个 Python 的类,这些类继承 django.db.models.Model 每个属性都相当于一个数据库的字段 django.db.models.Field 的子类

属性字段

  • AutoField 自增列 = int(11) 没有的话,默认会生成一个名称为id的列,如果要显示的定义一个自增列,必须把该列设置为主键(primary_key=True)
  • BooleanField 布尔类型字段 = tinyint(1) 不能为空,Blank = True
  • BinaryField 二进制
  • BigIntegerField 长整型(有符号的) - 9223372036854775808 ~ 9223372036854775807
  • CharField 字符串类型字段 必须加max_length参数
  • IntegerField 整数列(有符号的) - 2147483648 ~ 2147483647
  • ImageField 图片
  • FilePathField 文件
  • BigIntegerField 长整形
  • DateField 日期字段类型date 参数auto_now = True表示每次更新都会更新这个时间;参数auto_now_add表示只是第一次创建时添加,之后的更新不再改变
  • DateTimeField 日期字段类型datetime 同DateField的参数
  • Decimal 十进制小数类型 = decimal
  • EmailField 字符串类型(正则表达式邮箱) = varchar 对字符串进行正则表达式验证
  • FloatField 浮点类型 = double
  • IPAddressField 字符串类型(ip4正则表达式)
  • GenericIPAddressField 字符串类型(ip4和ip6是可选的) 参数protocol可以是:both、ipv4、ipv6 验证时,会根据设置进行报错
  • NullBooleanField 允许为空的布尔类型
  • PositiveIntegerFiel 正整数 0 ~ 2147483647
  • PositiveSmallIntegerField 正小整数 0 ~ 32767
  • SmallIntegerField 小整数 - 32768 ~ 32767
  • SlugField 字符串类型 提供验证支持 字母、数字、下划线、连接符(减号)
  • TextField 字符串 = longtext
  • TimeField 时间 HH: MM[:ss[.uuuuuu]]
  • URLField 字符串类型,地址正则表达式
  • UUIDField 字符串类型,提供对UUID格式的验证

Django 字段对应 Mysql 属性

AutoField: integer AUTO_INCREMENT BigAutoField: bigint AUTO_INCREMENT BinaryField: longblob BooleanField: bool CharField: varchar( % (max_length)s) CommaSeparatedIntegerField: varchar( % (max_length)s) DateField: date DateTimeField: datetime DecimalField: numeric(% (max_digits)s % (decimal_places)s) DurationField: bigint FileField: varchar( % (max_length)s) FilePathField: varchar( % (max_length)s) FloatField: double precision IntegerField: integer BigIntegerField: bigint IPAddressField: char(15) GenericIPAddressField: char(39) NullBooleanField: bool OneToOneField: integer PositiveIntegerField: integer UNSIGNED PositiveSmallIntegerField: smallint UNSIGNED SlugField: varchar( % (max_length)s) SmallIntegerField: smallint TextField: longtext TimeField: time UUIDField: char(32)

参数类型

  • null = True 数据库中字段是否可以为空
  • blank = True django的Admin中添加数据时是否可允许空值
  • primary_key = False 主键,对AutoField设置主键后,就会代替原来默认的自增id列
  • auto_now和auto_now_add   auto_now 自动创建 - –无论添加或修改,都是当前操作的时间   auto_now_add 自动创建 - –永远是创建时的时间
  • choices GENDER_CHOICE = ( (u’M’, u’Male’), (u’F’, u’Female’), ) gender = models.CharField(max_length=2, choices=GENDER_CHOICE)
  • max_length 最大长度
  • default  默认值
  • verbose_name  Admin中字段的显示名称
  • name | db_column 数据库中的字段名称
  • unique = True  不允许重复
  • db_index = True  数据库索引
  • editable = True  在Admin里是否可编辑
  • error_messages = None  错误提示
  • auto_created = False  自动创建
  • help_text  在Admin中提示帮助信息
  • validators = [] 验证
  • upload - to 文件上传路径

公共参数 null 数据库中字段是否可以为空 db_column 数据库中字段的列名 default 数据库中字段的默认值 primary_key 数据库中字段是否为主键,也是索引,加速查找,列值唯一且不能为空 db_index 数据库中字段是否可以建立索引,只能加速查找 unique 数据库中字段是否可以建立唯一索引,可加速查找,限制列值唯一 unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引 unique_for_month 数据库中字段【月】部分是否可以建立唯一索引 unique_for_year 数据库中字段【年】部分是否可以建立唯一索引

Django 建立一个应用

Django 建立一个应用

Django 建立一个应用

建立第一个应用

python manage.py startapp polls

修改 bookpro/settings.py

1# 添加自己新建的应用
2INSTALLED_APPS = [
3    'polls',
4
5]

通常, INSTALLED_APPS 默认包括了以下 Django 的自带应用:

django.contrib.admin – 管理员站点, 你很快就会使用它。 django.contrib.auth – 认证授权系统。 django.contrib.contenttypes – 内容类型框架。 django.contrib.sessions – 会话框架。 django.contrib.messages – 消息框架。 django.contrib.staticfiles – 管理静态文件的框架。 这些应用被默认启用是为了给常规项目提供方便。

建立请求路径

polls目录中 新建文件 urls.py 内容

 1# 引入
 2from django.urls import path, include
 3from . import views
 4
 5# 建立路径
 6urlpatterns = [
 7    # 请求路径 path("路径字段", 处理函数, 别名)
 8    path("", views.index, name="index"),
 9    path("info", views.infofun, name='info'),
10]

bookpro/urls.py 中添加对polls的路径引用

1from django.urls import path, include
2
3urlpatterns = [
4    path('polls/', include('polls.urls')),
5    path('admin/', admin.site.urls),
6]

建立视图

polls/views.py

 1from django.http import HttpResponse
 2# Create your views here.
 3
 4
 5def index(request):
 6    return HttpResponse("hello index")
 7
 8
 9def infofun(request):
10    return HttpResponse("hello infofun")

建立数据模型

polls/models.py

 1from django.db import models
 2
 3
 4class Question(models.Model):
 5    question_text = models.CharField(max_length=200)
 6    pub_date = models.DateTimeField('date published')
 7
 8
 9class Choice(models.Model):
10    question = models.ForeignKey(Question, on_delete=models.CASCADE)
11    choice_text = models.CharField(max_length=200)
12    votes = models.IntegerField(default=0)

然后迁移至数据库中

1python manage.py makemigrations
2python manage.py migrate

注册模型后台管理

polls/admin.py

1from django.contrib import admin
2
3# Register your models here.
4from . import models
5
6admin.site.register(models.Question)
7admin.site.register(models.Choice)

重启或刷新浏览器访问

Django 初次安装及运行

Django 初次安装及运行

django 初次安装及运行

django初始环境

  • Python版本 python3.10.1
  • Django版本 django4.0.1

django初始化

找一个英文路径的空目录下 django-admin startporject bookpro

修改 bookpro/bookpro/setting.py 配置文件

 1
 2# 允许任意IP访问
 3ALLOWED_HOSTS = ['*', ]
 4
 5# 修改 语言及时区
 6LANGUAGE_CODE = 'zh-hans'
 7TIME_ZONE = 'Asia/Shanghai'
 8
 9# 配置日志
10import time
11LOGGING = {
12    'version': 1,
13    'disable_existing_loggers': False,
14    'formatters': {
15        'standard': {
16            'format': '[%(asctime)s] [%(filename)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s'
17        },
18        'verbose': {
19            'format': '{asctime} {levelname} {filename}:{lineno} {module}{funcName} {process:d} {thread:d} {message}',
20            'style': '{',
21        },
22        'simple': {
23            'format': '{levelname} {message}',
24            'style': '{',
25        },
26    },
27    'filters': {
28        'require_debug_false': {
29            '()': 'django.utils.log.RequireDebugFalse',
30        },
31        'require_debug_true': {
32            '()': 'django.utils.log.RequireDebugTrue',
33        },
34    },
35    'handlers': {
36        # 默认记录所有日志
37        'default': {
38            'level': 'INFO',
39            'class': 'logging.handlers.RotatingFileHandler',
40            'filename': BASE_DIR / 'all-{}.log'.format(time.strftime('%Y-%m-%d')),
41            'maxBytes': 1024 * 1024 * 5,  # 文件大小
42            'backupCount': 5,  # 备份数
43            'formatter': 'verbose',  # 输出格式
44            'encoding': 'utf-8',  # 设置默认编码,否则打印出来汉字乱码
45        },
46        # 输出错误日志
47        'error': {
48            'level': 'ERROR',
49            'class': 'logging.handlers.RotatingFileHandler',
50            'filename': BASE_DIR / 'error-{}.log'.format(time.strftime('%Y-%m-%d')),
51            'maxBytes': 1024 * 1024 * 5,  # 文件大小
52            'backupCount': 5,  # 备份数
53            'formatter': 'verbose',  # 输出格式
54            'encoding': 'utf-8',  # 设置默认编码
55        },
56        # 控制台输出
57        'console': {
58            'level': 'DEBUG',
59            'filters': ['require_debug_true'],
60            'class': 'logging.StreamHandler',
61            'formatter': 'verbose'
62        },
63        # 输出info日志
64        'info': {
65            'level': 'INFO',
66            'class': 'logging.handlers.RotatingFileHandler',
67            'filename': BASE_DIR / 'info-{}.log'.format(time.strftime('%Y-%m-%d')),
68            'maxBytes': 1024 * 1024 * 5,
69            'backupCount': 5,
70            'formatter': 'verbose',
71            'encoding': 'utf-8',  # 设置默认编码
72        },
73    },
74    'loggers': {
75        # 类型 为 django 处理所有类型的日志, 默认调用
76        'django': {
77            'handlers': ['default', 'console'],
78            'level': 'INFO',
79            'propagate': False
80        },
81        'django.request': {
82            'handlers': ['error'],
83            'level': 'ERROR',
84            'propagate': False,
85        },
86    }
87}

python manage.py runserver

此时打开浏览器访问http://127.0.0.1:9000/ 即可看到启动页面

更进一步

1# 生成模型对应的数据库语句
2python manage.py makemigrations
3
4# 将改动迁移到数据库中
5python manage.py migrate
6
7# 建立超级用户
8python manage.py createsuperuser

重启或刷新浏览器访问 http://127.0.0.1:9000/admin/ 即可登录后台

Django Grappelli美化后台界面

Django Grappelli美化后台界面

安装 Django Grappelli

注意: 最新版grappelli支持到django3.2

pip install django-grappelli

配置 Django Grappelli

# 项目的setting文件中
INSTALLED_APPS = [
    'grappelli',
    ...
]

GRAPPELLI_ADMIN_TITLE = "管理后台"
STATIC_ROOT = BASE_DIR / 'static'

然后运行静态资源收集 python manage.py collectstatic

收工, 搞定

Docker

Docker 基础操作

Docker 一些建单的基础操作

docker核心组件如下:docker客户端与服务器、docker镜像、registry、docker容器。对它们详细描述如下:

客户端与服务器

docker是一个c/s架构的程序,docker客户端需要向docker服务器或者守护进程发出请求。服务器或者守护进程完成工作并且返回结果。docker提供了命令行docker和restful api,可以使用他们连接本地或者远程的守护进程。

docker架构

镜像

  镜像是docker世界的基石,用户基于镜像可以构建容器。

registry

  docker使用registry保存用户镜像。Registry分为共有和私有两种,Docker官方registry为Docker Hub。

容器

  容器基于镜像启动,里面可以运行一个或者多个进程。

Docker 安装

 1# 安装
 2yum install docker
 3# 启动并配置自启动
 4service docker start
 5chkconfig docker on
 6
 7# Centos 新语法
 8systemctl start docker.service
 9systemctl enable docker.service
10
11# 配置docker加速
12vi  /etc/docker/daemon.json
13#添加后
14{
15    "registry-mirrors": ["https://registry.docker-cn.com"],
16    "live-restore": true
17}

Docker 常用命令

 1# 拉取镜像
 2docker pull image_name
 3# 查看主机已有镜像
 4docker images
 5# 删除镜像
 6docker rmi  docker.io/tomcat:7.0.77-jre7
 7docker rmi b39c68b7af30
 8# 查看正在运行的容器
 9docker ps
10# 查看所有容器
11docker ps -a
12# 启动,停止,重启容器
13docker start container_name/container_id
14docker stop container_name/container_id
15docker restart container_name/container_id
16# 后台启动容器后想要进入
17docker attach container_name/container_id
18# 删除容器
19docker rm container_name/container_id

Flask

Flask 学习文档

Flask 初步认识(step 1)

Flask的基础认识

Flask 本身相当于一个内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证Flask-Login,数据库Flask-SQLAlchemy), 都需要用第三方的扩展来实现。比如可以用 Flask 扩展加入ORM、窗体验证工具,文件上传、身份验证等。 Flask 没有默认使用的数据库,你可以选择 MySQL,也可以用 NoSQL

安装

当安装 Flask 时,以下配套软件会被自动安装。 Werkzeug 用于实现 WSGI ,应用和服务之间的标准 Python 接口。 Jinja 用于渲染页面的模板语言。 MarkupSafe 与 Jinja 共用,在渲染页面时用于避免不可信的输入,防止注 入攻击。 ItsDangerous 保证数据完整性的安全标志数据,用于保护 Flask 的 session cookie. Click 是一个命令行应用的框架。用于提供 flask 命令,并允许添加 自定义管理命令。 Blinker 提供对于 信号 的支持。

常用扩展

  • Flask-SQLalchemy:操作数据库,ORM;
  • Flask-script:终端脚本工具,脚手架;
  • Flask-migrate:管理迁移数据库;
  • Flask-Session:Session存储方式指定;
  • Flask-WTF:表单;
  • Flask-Mail:邮件;
  • Flask-Bable:提供国际化和本地化支持,翻译;
  • Flask-Login:认证用户状态;
  • Flask-OpenID:认证, OAuth;
  • Flask-RESTful:开发REST API的工具;
  • Flask JSON-RPC: 开发rpc远程服务[过程]调用
  • Flask-Bootstrap:集成前端Twitter Bootstrap框架
  • Flask-Moment:本地化日期和时间
  • Flask-Admin:简单而可扩展的管理接口的框架

Fastapi 安装部署

Fastapi 安装部署

Fastapi 安装部署

环境基础安装

pip install fastapi uvicorn gunicorn supervisor

简单Fastapi代码

 1
 2import uvicorn
 3from loguru import logger
 4import arrow
 5import pymysql
 6import sys
 7
 8from fastapi import FastAPI, Query, Request, Body
 9from pydantic import BaseModel
10from fastapi.encoders import jsonable_encoder
11from fastapi.responses import JSONResponse
12from typing import List, Tuple, Set
13
14
15app = FastAPI(title='订单同步接口', description='订单同步接口')
16
17if "win" in sys.platform:
18    logger.add("./db.log", encoding='utf-8')
19else:
20    logger.add("/path/db.log", encoding='utf-8')
21
22
23curnow = arrow.now()
24nowhour = curnow.format("YYYY-MM-DD HH:mm:ss")
25before3hour = curnow.shift(hours=-3).format("YYYY-MM-DD HH:mm:ss")
26
27
28class Argcls(BaseModel):
29    begintime: str = before3hour
30    endtime: str = nowhour
31    orders: List[str] = []
32
33class DB:
34
35    def __init__(self):
36        try:
37            if "win" in sys.platform:
38                self.db = pymysql.connect(host="127.0.0.1", port=3306, user="root", password="root", db="dbname", charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)
39            else:
40                self.db = pymysql.connect(host="127.0.0.1", port=3306, user="root", password="root", db="dbname", charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)
41        except:
42            logger.error("数据库连接失败!")
43        self.cur = self.db.cursor()
44
45    def query(self, sql):
46        self.cur.execute(sql)
47        return self.cur.fetchall()
48
49    def __del__(self):
50        self.cur.close()
51        self.db.close()
52
53
54
55sql_order = """ select * from user_order where states>0 and %s """
56
57sql_order_subs = """ SELECT * FROM user_order_subs WHERE orders_id='%s'"""
58
59@app.post('/getOrder', summary='指定时间范围内的订单', description='查询指定时间范围内的订单')
60def seach_order(args: Argcls = Body(..., example={"begintime": "查询订单的开始时间 eg 2022-03-04 00:00:00",
61                                                  "endtime": "查询订单的结束时间 eg 2022-03-04 23:59:59",
62                                                  "orders": "List[orderid字符串]"})):
63
64    logger.info("查询参数 {}", args)
65
66    wherestr = "create_time>='%s' and create_time<='%s'" % (args.begintime, args.endtime)
67    if len(args.orders):
68        orderstr = " orders_codes in ('%s')" % "','".join(args.orders)
69        wherestr = "( (%s) or %s)" % (wherestr, orderstr)
70
71    sql = sql_order % (wherestr)
72    logger.info("查询语句 {}", sql)
73
74    db = DB()
75
76    res = db.query(sql)
77    for key, row in enumerate(res):
78        res[key]['sub_orders'] = db.query(sql_order_subs % (row['id']))
79
80    logger.info("返回条数 {}", len(res))
81    return res
82
83
84if __name__ == '__main__':
85    logger.info("启动运行...")
86    uvicorn.run(app='main:app', host="0.0.0.0", port=7296, reload=True, debug=True)

运行代码


# 命令行运行测试
python main.py

# 使用 uvicron 运行
uvicorn main:app --reload --host 0.0.0.0 --port 7296

# 使用 gunicorn 运行
gunicorn main:app -b 0.0.0.0:7296 -w 4 -k uvicorn.workers.UvicornWorker --daemon

Gunicorn 已配置文件方式启动

* 以配置文件的方式启动
gunicorn.conf

import multiprocessing

# 并行工作进程数(multiprocessing.cpu_count()线程数,官方说可以有:核心数*2+1个)
workers = multiprocessing.cpu_count() * 2 + 1
# 指定每个工作者的线程数
threads = 2
# 监听内网端口5000
bind = '127.0.0.1:5000'
# 设置守护进程,推荐将进程交给supervisor管理(以守护进程形式来运行Gunicorn进程,true其实就是将这个服务放到后台去运行,故此处设置false,交给supervisor开守护进程,因为supervisor不支持后台进程)
daemon = 'false'
# 工作模式协程
worker_class = 'gevent'
# 设置最大并发量
worker_connections = 2000
# 设置进程文件目录
pidfile = '/var/run/gunicorn.pid'
# 设置访问日志和错误信息日志路径
accesslog = '/var/log/gunicorn_acess.log'
errorlog = '/var/log/gunicorn_error.log'
# 日志级别,这个日志级别指的是错误日志的级别,而访问日志的级别无法设置
loglevel = 'warning'
# 启动unicorn
gunicorn -c gunicorn.conf main:app

# 获取Gunicorn进程树
pstree -ap|grep gunicorn

# 重启Gunicorn任务
kill -HUP 30080

Supervisor 配置运行

pip install supervisor
默认配置文件:/etc/supervisord.conf
进程管理配置文件放到:/etc/supervisord.d/目录下即可

mkdir -p ~/etc/supervisor/conf.d 
mkdir -p ~/etc/supervisor/var/log

cd ~/etc 
echo_supervisord_conf > supervisord.conf
* 修改 supervisor.conf,让 Supervisor 进程产生的一些文件生成到上面我们创建的目录下,而不是其默认指定的地方。
    * 首先找到 [unix_http_server] 版块,将 file 设置改为如下的值,即让 socket 文件生成在 ~/etc/supervisor/var/ 目录下。
注意 supervisor 不支持将 ~ 展开为用户 home 目录,所以要用绝对路径指定。:
* [unix_http_server]file=/root/etc/supervisor/var/supervisor.sock
    * 类似的修改 [supervisord] 板块下的 logfile 和 pidfile 文件的路径,还有 user 改为系统用户,这样 supervisor 启动的进程将以系统用户运行,避免可能的权限问题:
*
[supervisord]logfile= /root/etc/supervisor/var/log/supervisord.log
pidfile=/root/etc/supervisor/var/supervisord.pid
user=root
    * [supervisorctl] 板块下:
* [supervisorctl]serverurl=unix:///root/etc/supervisor/var/supervisor.sock
    * [include] 版块,将 /home/yangxg/etc/supervisor/conf.d/ 目录下所有以 .ini 结尾的文件内容包含到配置中来,
这样便于配置的模块化管理,和之前 Nginx 配置文件的处理方式是类似的。
* [include]files = /root/etc/supervisor/conf.d/*.ini
* 然后我们到 conf.d 新建应用的配置
(py3.6) [root@iZbp11gqesu0znu7pkmgp7Z conf.d]# cat fig1.ini
[program:api-fastapi]
command=gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --timeout 30 -b 0.0.0.0:8000
directory=/root/api-fastapi/
autostart=true
autorestart=unexpected
user=root
stdout_logfile=/etc/supervisor/var/log/api-fastapi-stdout.log
stderr_logfile=/etc/supervisor/var/log/api-fastapi-stderr.log
各项配置的含义:
  [program:wenda_slmx] 指明运行应用的进程,名为 wenda_slmx。
  
  command 为进程启动时执行的命令。
  
  directory 指定执行命令时所在的目录。
  
  autostart 随 Supervisor 启动自动启动进程。
  
  autorestart 进程意外退出时重启。
  
  user 进程运行的用户,防止权限问题。
  
  stdout_logfile,stderr_logfile 日志输出文件。
* 启动 Supervisor
supervisord -c ~/etc/supervisord.conf
    * -c 指定 Supervisr 启动时的配置文件。
    * 更新新的配置到supervisord
* supervisorctl update
    * 重新启动配置中的所有程序
* supervisorctl reload
* 浏览器输入域名,可以看到服务已经正常启动了。
[unix_http_server]
file=/tmp/supervisor.sock   ;UNIX socket 文件,supervisorctl 会使用
;chmod=0700                 ;socket文件的mode,默认是0700;chown=nobody:nogroup       ;socket文件的owner,格式:uid:gid
;[inet_http_server]         ;HTTP服务器,提供web管理界面
;port=127.0.0.1:9001        ;Web管理后台运行的IP和端口,如果开放到公网,需要注意安全性
;username=user              ;登录管理后台的用户名
;password=123               ;登录管理后台的密码
[supervisord]
logfile=/tmp/supervisord.log ;日志文件,默认是 $CWD/supervisord.log
logfile_maxbytes=50MB        ;日志文件大小,超出会rotate,默认 50MB,如果设成0,表示不限制大小
logfile_backups=10           ;日志文件保留备份数量默认10,设为0表示不备份
loglevel=info                ;日志级别,默认info,其它: debug,warn,trace
pidfile=/tmp/supervisord.pid ;pid 文件
nodaemon=false               ;是否在前台启动,默认是false,即以 daemon 的方式启动
minfds=1024                  ;可以打开的文件描述符的最小值,默认 1024
minprocs=200                 ;可以打开的进程数的最小值,默认 200
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ;通过UNIX socket连接supervisord,路径与unix_http_server部分的file一致;serverurl=http://127.0.0.1:9001 ; 通过HTTP的方式连接supervisord
; [program:xx]是被管理的进程配置参数,xx是进程的名称
[program:xx]
command=/opt/apache-tomcat-8.0.35/bin/catalina.sh run  ; 程序启动命令
autostart=true       ; 在supervisord启动的时候也自动启动
startsecs=10         ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒
autorestart=true     ; 程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启
startretries=3       ; 启动失败自动重试次数,默认是3
user=tomcat          ; 用哪个用户启动进程,默认是root
priority=999         ; 进程启动优先级,默认999,值小的优先启动
redirect_stderr=true ; 把stderr重定向到stdout,默认false
stdout_logfile_maxbytes=20MB  ; stdout 日志文件大小,默认50MB
stdout_logfile_backups = 20   ; stdout 日志文件备份数,默认是10; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile=/opt/apache-tomcat-8.0.35/logs/catalina.out
stopasgroup=false     ;默认为false,进程被杀死时,是否向这个进程组发送stop信号,包括子进程
killasgroup=false     ;默认为false,向进程组发送kill信号,包括子进程
;包含其它配置文件
[include]
files = relative/directory/*.ini    ;可以指定一个或多个以.ini结束的配置文件
子进程配置文件说明:
给需要管理的子进程(程序)编写一个配置文件,放在/etc/supervisor.d/目录下,以.ini作为扩展名(每个进程的配置文件都可以单独分拆也可以把相关的脚本放一起)。如任意定义一个和脚本相关的项目名称的选项组

#项目名[program:blog]#脚本目录
directory=/opt/bin
#脚本执行命令
command=/usr/bin/python /opt/bin/test.py


#supervisor启动的时候是否随着同时启动,默认True
autostart=true#当程序exit的时候,这个program不会自动重启,默认unexpected,设置子进程挂掉后自动重启的情况,有三个选项,false,unexpected和true。如果为false的时候,无论什么情况下,都不会被重新启动,如果为unexpected,只有当进程的退出码不在下面的exitcodes里面定义的
autorestart=false#这个选项是子进程启动多少秒之后,此时状态如果是running,则我们认为启动成功了。默认值为1
startsecs=1


#脚本运行的用户身份
user = test


#日志输出
stderr_logfile=/tmp/blog_stderr.log
stdout_logfile=/tmp/blog_stdout.log
#把stderr重定向到stdout,默认 false
redirect_stderr = true#stdout日志文件大小,默认 50MB
stdout_logfile_maxbytes = 20MB
#stdout日志文件备份数
stdout_logfile_backups = 20
子进程配置示例:
#说明同上
[program:test]
directory=/opt/bin
command=/opt/bin/test
autostart=true
autorestart=false
stderr_logfile=/tmp/test_stderr.log
stdout_logfile=/tmp/test_stdout.log
#user = test  
supervisorctl status        //查看所有进程的状态
supervisorctl stop es       //停止es
supervisorctl start es      //启动es
supervisorctl restart       //重启es
supervisorctl update        //配置文件修改后使用该命令加载新的配置
supervisorctl reload        //重新启动配置中的所有程序
新建文件supervisord.service

#supervisord.service
[Unit]
Description=Supervisor daemon

[Service]
Type=forking
ExecStart=/usr/bin/supervisord -c /etc/supervisord.conf
ExecStop=/usr/bin/supervisorctl shutdown
ExecReload=/usr/bin/supervisorctl reload
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target
------------------------------------------

cp supervisord.service /usr/lib/systemd/system/
启动服务
systemctl enable supervisord
验证一下是否为开机启动
systemctl is-enabled supervisord

Git

Git 自定义常用配置

Git 自定义常用配置

git 自用配置 定义了一些常用的git简写命令

  1[push]
  2    default = current
  3    autoSetupRemote = true
  4[core]
  5    safecrlf = false
  6    trustctime = false
  7    editor = vim
  8    filemode = false
  9    autocrlf = input
 10    quotepath = false
 11    whitespace = cr-at-eol
 12    ignorecase = false
 13
 14[color]
 15    ui = true
 16    status = auto
 17    diff = auto
 18    branch = auto
 19    interactive = auto
 20[merge]
 21    tool = vimdiff
 22[mergetool]
 23    keeptemporaries = false
 24    keepbackups = false
 25    prompt = false
 26    trustexitcode = false
 27[alias]
 28    # 完全删除最后一次提交
 29    rh = reset --hard HEAD^
 30    # 从 本地仓库 中, 撤销 最后一次提交, 将 最后的提交内容 作为 索引目录 中的 改动 (撤销了 commit 操作)
 31    rs = reset --soft HEAD^
 32    # 从 本地仓库 中, 撤销 最后一次提交, 将 最后的提交内容 作为 工作目录 中的 改动 (撤销了 commit 和 add 操作)
 33    rm = reset --mixed HEAD^
 34    # 从 索引目录 中, 撤回 指定文件 到 工作目录, 保留 文件改动 (撤销了 add 操作)
 35    ua = restore --staged 
 36    # 放弃 工作目录 中 指定文件 的更改, 接 指定文件名称
 37    re = restore 
 38    ue = restore 
 39    #-----------------------------------------------------------------------------------------------------------
 40    # 列表所有提交变更文件,增删情况
 41    ls = log --stat
 42    # 展示指定节点的详细变更信息
 43    sw = show
 44    last = log -1 --stat
 45    cp = cherry-pick
 46    ci = commit
 47    st = status
 48    unstage = reset HEAD --
 49    # 检出
 50    co = checkout
 51    # 新建分支
 52    cb = checkout -b
 53    # 提交并添加提交信息
 54    cm = commit -m
 55    # 提交文件并提交信息
 56    ca = commit -a -m
 57    # 修改最后一次提交, 可以修改提交消息, 修改提交文件, 并替换掉最后提交的CommitID
 58    cd = commit --amend
 59    # 清除没有被跟踪的文件和目录
 60    cf = clean -fd
 61    df = diff
 62    ds = diff --staged
 63    dc = diff --cached 
 64    dh = diff HEAD 
 65    br = branch
 66    bd = branch -d
 67    bD = branch -D
 68    pl = pull
 69    ps = push
 70    cl = clone
 71    lg = log --all --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative -25
 72    lst = log -15 --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=short --stat
 73    ra = remote add
 74    mn = merge --no-ff 
 75    ms = merge --squash 
 76    pr = pull --rebase
 77    ff = fetch 
 78    rb = rebase 
 79    # 临时缓存未提交的修改
 80    sh = stash 
 81    # 临时缓存未提交的修改, 可以写简短说明
 82    sm = stash -m 
 83    # 弹出最后一次临时保存的未提交代码
 84    sp = stash pop 
 85    # 列表所有保存的未提交修改
 86    sl = stash list
 87
 88[http]
 89    sslVerify = true
 90    postbuffer = 524288000
 91[gui]
 92    encoding = utf-8
 93[pull]
 94    ff = only
 95[format]
 96    pretty = oneline
 97[credential]
 98    helper = store
 99    autoDetectTimeout = -1
100[https]
101    postBuffer = 1048576000
102[pack]
103    windowMemory = 50m
104[http "https://github.com"]
105    proxy = socks5://127.0.0.1:1081

Gitea 二进制版本 安装配置

使用Gitea的二进制版本在Linux上搭建自己的git服务器

关于Gitea

Gitea 是一个自己托管的Git服务程序。他和GitHub, Bitbucket or Gitlab等比较类似。他是从 Gogs 发展而来

Gitea的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。 采用Go作为后端语言,只生成一个可执行程序即可。

并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构,除了x86,amd64,还包括 ARM 和 PowerPC。

准备工作

 1
 2# .bashrc 中 配置环境变量
 3export GITEA_WORK_DIR=/var/lib/gitea/
 4
 5
 6# 建立执行用户
 7groupadd --system git
 8useradd \
 9   --system \
10   --shell /bin/bash \
11   --comment 'Git Version Control' \
12   --gid git \
13   --home-dir /home/git \
14   --create-home \
15   git
16
17# 建立工作路径
18mkdir -p /var/lib/gitea/{custom,data,log}
19chown -R git:git /var/lib/gitea/
20chmod -R 750 /var/lib/gitea/
21mkdir /etc/gitea
22chown root:git /etc/gitea
23chmod 770 /etc/gitea

gitea 二进制版本安装

1
2wget -O gitea https://dl.gitea.com/gitea/1.20.3/gitea-1.20.3-linux-amd64
3chmod +x gitea
4cp gitea /usr/local/bin/gitea
5
6
7# 首次运行
8su -l git
9GITEA_WORK_DIR=/var/lib/gitea/ /usr/local/bin/gitea web -c /etc/gitea/app.ini

Gitea 服务配置文件

1sudo vim /etc/systemd/system/gitea.service
 1[Unit]
 2Description=Gitea (Git with a cup of tea)
 3After=syslog.target
 4After=network.target
 5
 6[Service]
 7# Uncomment the next line if you have repos with lots of files and get a HTTP 500 error because of that
 8# LimitNOFILE=524288:524288
 9RestartSec=2s
10Type=notify
11User=git
12Group=git
13WorkingDirectory=/var/lib/gitea/
14# If using Unix socket: tells systemd to create the /run/gitea folder, which will contain the gitea.sock file
15# (manually creating /run/gitea doesn't work, because it would not persist across reboots)
16#RuntimeDirectory=gitea
17ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
18Restart=always
19Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
20WatchdogSec=30s
21
22[Install]
23WantedBy=multi-user.target
1sudo systemctl enable gitea
2sudo systemctl start gitea

Git 一些操作

Git 一些操作

Git 一些操作

查看最后一次提交了什么内容

1git show

重新未推送的最后一次提交的信息

1git commit --amend --only -m "new message"

删除提交中的一个文件

1git checkout HEAD^ filename
2git add -A
3git commit --amend

取消最后一次提交

1# 如果没有推送, 使用一下命令, 可以保留撤销的提交变化内容
2git reset --soft HEAD@{1}
3# 如果已推送
4git revert HEAD^
5git push

追加暂存的内容到上一次提交上

1git commit --amend

删除分支

1# 本地分支
2git branch -D/-d branch-name
3# 远程分支
4git push origin :branch-name

git删除文件,保留实体文件

1git rm --cached filename

Git 常用操作

Git 常用操作

远程仓库 操作命令

检出仓库: $ git clone git://github.com/origin_name/origin_name.git
查看远程仓库: $ git remote -v
添加远程仓库: $ git remote add origin_name remote_url
删除远程仓库: $ git remote rm origin_name
修改远程仓库: $ git remote set-url --push origin_name new_remote_url
拉取远程仓库: $ git pull remote_name local_name
推送远程仓库: $ git push remote_name local_name

分支 操作命令

查看本地分支: $ git branch
查看远程分支: $ git branch -r
创建本地分支: $ git branch name

注意新分支创建后不会自动切换为当前分支

切换分支: $ git checkout name
创建新分支并立即切换到新分支: $ git checkout -b name
删除分支: $ git branch -d name

-d选项只能删除已经参与了合并的分支, 对于未有合并的分支是无法删除的。
如果想强制删除一个分支, 可以使用-D选项

合并分支: $ git merge name

将名称为name的分支与当前分支合并

创建远程分支(本地分支push到远程): $ git push origin name
删除远程分支: $ git push origin :heads/name

我从master分支创建了一个own_br分支, 做了一些修改后, 使用git push origin master提交,
但是显示的结果却是Everything up-to-date, 发生问题的原因是git push origin master
在没有track远程分支的本地分支中默认提交的master分支, 因为master分支默认指向了origin master 分支,
这里要使用git push origin own_br:master 就可以把own_br推送到远程的master分支了。

如果想把本地的某个分支test提交到远程仓库, 并作为远程仓库的master分支,
或者作为另外一个名叫test的分支, 那么可以这么做。
$ git push origin test:master
提交本地test分支作为远程的master分支
好像只写这一句, 远程的github就会自动创建一个test分支

$ git push origin test:test
提交本地test分支作为远程的test分支

如果想删除远程的分支呢?类似于上面, 如果:左边的分支为空, 那么将删除:右边的远程的分支。

$ git push origin :test
刚提交到远程的test将被删除, 但是本地还会保存的, 不用担心

克隆远程指定分支

1git init
2git remote add -t br_name_local -f origin remote_origin_url
3git checkout br_name_local

Git 四种撤销操作

Git 4个区: 工作区, 暂存区, 本地仓库, 远程仓库
对应5个状态: 未修改, 已修改, 已暂存, 已提交, 已推送

干净工作区, 新建文件, 处于未跟踪untracked状态

  • 可以删除未跟踪文件, 还原工作区干净状态
  • 可以通过 git add filename 加入git暂存区

干净工作区, 修改文件, 处于已修改状态

  • 可以通过 git checkout -- filename, 撤销修改, 还原干净工作区
  • 可以通过 git add filename, 将修改加入git暂存区

所有通过 git add . 到暂存区的文件

  • 可以通过 git reset ., 撤销add,回复到原修改,新增状态

  • 可以通过 git reset filename, 撤销add,回复到原修改,新增状态

  • 可以通过 git reset HEAD ., 回复到原修改,新增状态

  • 同上的命令 git reset HEAD filename, 撤销暂存区的文件到原状态

  • 可以通过 git commit -m "commit info" , 提交暂存区文件到本地仓库

  • 可以通过 git reset --hard (.|filename), 撤销add操作和修改/新增操作,
    彻底还原干净工作区

上面的命令等于以下两条命令:
git reset (.|filename) 撤销提交到缓存区, 这样缓存区就干净了
git checkout -- (.|filename) 撤销文件的修改, 这样工作区就干净了

对于最后一次commit, 可以通过 git commit --amend 打开最后提交信息修改

对于提交到本地仓库的代码

  • 可以通过 git reset --hard HEAD^, 回退版本到上一个版本

  • 可以通过 git reset --hard 59b1707, 返回到指定的提交版本
    通过 git reflog 查看所有提交 版本信息

  • 回退版本后, 如果再次后悔, 通过git reflog, 找到指定版本id, git reset --hard xxxxx

  • 可以通过 git reset --hard origin/master, 利用远程的版本库,覆盖本地最后一次提交

  • 可以通过 git push origin master , 推送本地版本到远程仓库

如果提交到远程仓库后, 后悔了

  • 可以通过 git reset --hard HEAD^ , 回退本地版本库到上一个版本
    再运行 git push -f, 强制推送一次

Javascript

Leetcode

Leetcode 外观数列

Leetcode 外观数列

外观数列

给定一个正整数 n(1 ≤ n ≤ 30),输出外观数列的第 n 项。

注意:整数序列中的每一项将表示为一个字符串。

「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项如下:

1.     1
2.     11
3.     21
4.     1211
5.     111221

第一项是数字 1

描述前一项,这个数是 1 即 “一个 1 ”,记作 11

描述前一项,这个数是 11 即 “两个 1 ” ,记作 21

描述前一项,这个数是 21 即 “一个 2 一个 1 ” ,记作 1211

描述前一项,这个数是 1211 即 “一个 1 一个 2 两个 1 ” ,记作 111221

示例 1:

输入: 1
输出: "1"
解释:这是一个基本样例。

示例 2:

输入: 4
输出: "1211"
解释:当 n = 3 时,序列是 "21",其中我们有 "2" 和 "1" 两组,"2" 可以读作 "12",也就是出现频次 = 1 而 值 = 2;类似 "1" 可以读作 "11"。所以答案是 "12" 和 "11" 组合在一起,也就是 "1211"。

解题思路

定义变量res=“1”, 当n=1时, 返回res
定义lst=[], 保存过程数据
从2-n开始循环, 每次循环 对res逐一位判断
当lst为空时, lst数组保存[1, 当前位数字]
当lst不为空时, 如果当前位数字和lst最后一个元素相等, 则lst倒数第二位+1, 不相等则 lst扩展[1, 当前位数字]
最后lst中所有元素转为字符, 并连接到一起返回

Answer

 1#
 2# @lc app=leetcode.cn id=38 lang=python3
 3#
 4# [38] 外观数列
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def countAndSay(self, n: int) -> str:
10        res = "1"
11        if n == 1:
12            return res
13        for i in range(2, n+1):
14            lst = []
15            for m in res:
16                if not lst:
17                    lst.extend([1, m])
18                else:
19                    if m == lst[-1]:
20                        lst[-2] = lst[-2] + 1
21                    else:
22                        lst.extend([1, m])
23            res = ''.join([str(r) for r in lst])
24        return res
25# @lc code=end

Accepted

18/18 cases passed (36 ms)
Your runtime beats 97.67 % of python3 submissions
Your memory usage beats 6.67 % of python3 submissions (13.7 MB)

Leetcode 搜索插入位置

Leetcode 搜索插入位置

搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:

输入: [1,3,5,6], 5
输出: 2

示例 2:

输入: [1,3,5,6], 2
输出: 1

示例 3:

输入: [1,3,5,6], 7
输出: 4

示例 4:

输入: [1,3,5,6], 0
输出: 0

解题思路

二分查找
求出最小和最大索引的取整中间值, 判断该索引的value是否等于target, 如果相等返回索引位置
如果value大于target, 则查找的目标在中间索引值左侧, 将现在的最大索引值重置为中间值
如果value小于target, 则查找的目标在中间索引值右侧, 将现在的最小索引值重置为中间值
重新取中间索引值继续比较, 直到找到或找不到退出
则元素应该插入的位置为最后最小索引值+1

Answer

 1#
 2# @lc app=leetcode.cn id=35 lang=python3
 3#
 4# [35] 搜索插入位置
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def searchInsert(self, nums: List[int], target: int) -> int:
10        m = 0
11        n = len(nums)-1
12        while m <= n:
13            k = (m + n) // 2
14            if target == nums[k]:
15                return k
16            elif target > nums[k]:
17                m = k + 1
18            else:
19                n = k - 1
20        return n+1
21# @lc code=end

Accepted

62/62 cases passed (32 ms)
Your runtime beats 97.37 % of python3 submissions
Your memory usage beats 7.14 % of python3 submissions (14.3 MB)

Leetcode 实现 StrStr

Leetcode 实现 StrStr

实现 strStr()

实现 strStr() 函数。

给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。

示例 1:

输入: haystack = "hello", needle = "ll"
输出: 2

示例 2:

输入: haystack = "aaaaa", needle = "bba"
输出: -1

说明:

当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。

对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。

解题思路

如果查找字符串为空或者两个字符串相同,直接返回0
定义两个变量i=needle长度, k=haystack长度0到k-i+1遍历haystack, 以i长度截取字符串对比needle, 如果找到返回当前索引 找不到返回-1

Answer

 1#
 2# @lc app=leetcode.cn id=28 lang=python3
 3#
 4# [28] 实现 strStr()
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def strStr(self, haystack: str, needle: str) -> int:
10        if not needle or haystack == needle:
11            return 0
12        j = len(needle)
13        k = len(haystack)
14        for i in range(k-j+1):
15            if haystack[i:i+j] == needle:
16                return i
17        return -1
18# @lc code=end

Accepted

74/74 cases passed (36 ms)
Your runtime beats 91.04 % of python3 submissions
Your memory usage beats 6.67 % of python3 submissions (13.5 MB)

Leetcode 移除元素

Leetcode 移除元素

移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:

给定 nums = [3,2,2,3], val = 3,

函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。

你不需要考虑数组中超出新长度后面的元素。

示例 2:

给定 nums = [0,1,2,2,3,0,4,2], val = 2,

函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。

注意这五个元素可为任意顺序。

你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

解题思路

定义两个变量i=0, j=0
i指向结果集, j从头到尾遍历数组 如果num[j]<>val, num[i]=num[j] 然后i=i+1, j=j+1
如果num[j]==val, 则j=j+1, 继续判断下一个元素

Answer

 1#
 2# @lc app=leetcode.cn id=27 lang=python3
 3#
 4# [27] 移除元素
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def removeElement(self, nums: List[int], val: int) -> int:
10        i = 0
11        j = 0
12        while True:
13            if j >= len(nums):
14                break
15            if nums[j] == val:
16                j = j + 1
17            else:
18                nums[i] = nums[j]
19                i = i + 1
20                j = j + 1
21        return i
22# @lc code=end

Accepted

113/113 cases passed (36 ms)
Your runtime beats 87.21 % of python3 submissions
Your memory usage beats 7.14 % of python3 submissions (13.8 MB)

Leetcode 删除排序数组中的重复项

Leetcode 删除排序数组中的重复项

删除排序数组中的重复项

给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

示例 1:

给定数组 nums = [1,1,2], 

函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 

你不需要考虑数组中超出新长度后面的元素。

示例 2:

给定 nums = [0,0,1,1,1,2,2,3,3,4],

函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。

你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

解题思路

定义两个变量作为指针 i=0, j=1
i 作为结果指针, j 作为游标指向后面的元素, 用来跟结果比较
如果nums[i]==nums[j], 则j游标后移, 比较结果和下一个元素的值
如果nums[i]<>nums[j], 则nums[i+1] = nums[j], 然后i = i+1 结果集后移一个, j游标后移

Answer

 1#
 2# @lc app=leetcode.cn id=26 lang=python3
 3#
 4# [26] 删除排序数组中的重复项
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def removeDuplicates(self, nums: List[int]) -> int:
10        i = 0
11        j = 1
12        while True:
13            if j >= len(nums):
14                break
15            if nums[j] != nums[i]:
16                nums[i+1] = nums[j]
17                i = i + 1
18            j = j + 1
19        return i + 1
20# @lc code=end

Accepted

161/161 cases passed (40 ms)
Your runtime beats 95.72 % of python3 submissions
Your memory usage beats 8.16 % of python3 submissions (14.7 MB)

Leetcode 合并两个有序链表

Leetcode 合并两个有序链表

合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

解题思路

初始化一个新的链表want节点, 并用head变量保存头部
当l1和l2都不为空时, 比较两个链表的头部元素, 较小的赋值给新链接want, 并将链接指针后移
当l1或l2有一个为空时, 将不为空的链接剩余节点追加到want
最后返回head->next(即真正的链接第一个元素)

Answer

 1#
 2# @lc app=leetcode.cn id=21 lang=python3
 3#
 4# [21] 合并两个有序链表
 5#
 6
 7# @lc code=start
 8# Definition for singly-linked list.
 9# class ListNode:
10#     def __init__(self, val=0, next=None):
11#         self.val = val
12#         self.next = next
13class Solution:
14    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
15        want = ListNode(0)
16        head = want
17        while l1 and l2:
18            if l1.val <= l2.val:
19                tmp = ListNode(l1.val)
20                l1 = l1.next
21            else:
22                tmp = ListNode(l2.val)
23                l2 = l2.next
24            want.next = tmp
25            want = want.next
26        if l1:
27            want.next = l1
28        if l2:
29            want.next = l2
30        return head.next
31# @lc code=end

Accepted

208/208 cases passed (44 ms)
Your runtime beats 78.91 % of python3 submissions
Your memory usage beats 7.14 % of python3 submissions (13.8 MB)

Leetcode 有效的括号

Leetcode 有效的括号

有效的括号

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。

示例 1:

输入: "()"
输出: true

示例 2:

输入: "()[]{}"
输出: true

示例 3:

输入: "(]"
输出: false

示例 4:

输入: "([)]"
输出: false

示例 5:

输入: "{[]}"
输出: true

解题思路

将给定字符串打散成数组
初始化字典, 右侧括号为键, 左侧括号为值
循环数组中的每个字符

如果当前字符不是字典的键(即不是右侧括号), 将当前字符追加到一个空数组stack
否则(即当前字符是右侧括号),

判断stack不为空的情况下, 最后一个元素是否等于字典中当前字符键的值
相等则继续判断下一个字符
不相等即返回False,
最后判断stack, 非空返回False

Answer

 1#
 2# @lc app=leetcode.cn id=20 lang=python3
 3#
 4# [20] 有效的括号
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def isValid(self, s: str) -> bool:
10        s = list(s)
11        dic = {")":"(","]":"[","}":"{"}
12        stack = []
13        for i in s:
14            if not i in dic:
15                stack.append(i)
16            else:
17                if stack and stack.pop() == dic[i]:
18                    pass
19                else:
20                    return False
21        return True if not stack else False
22# @lc code=end

Accepted

76/76 cases passed (36 ms)
Your runtime beats 90.49 % of python3 submissions
Your memory usage beats 5.22 % of python3 submissions (13.8 MB)

Leetcode 最长公共前缀

Leetcode 最长公共前缀

最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 “"。

示例 1:

输入: ["flower","flow","flight"]
输出: "fl"

示例 2:

输入: ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。

说明:

所有输入只包含小写字母 a-z 。

解题思路

原始数组转为set,再转为list, 去重
如果只有一个元素, 最长公共前缀就是该元素
设置初始最长公共前缀为”"
对数组各元素同步截取前n个字符. 放入set去重, 如果set长度为1, 则公共前缀为集合的元素
继续对各元素同步截取, 直到set长度不为1, 返回保存的公共前缀

Answer

 1#
 2# @lc app=leetcode.cn id=14 lang=python3
 3#
 4# [14] 最长公共前缀
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def longestCommonPrefix(self, strs: List[str]) -> str:
10        strs = list(set(strs))
11        if len(strs) == 1:
12            return strs[0]
13        idx = 1
14        prefix = ""
15        while True:
16            ary = [i[0:idx] for i in strs]
17            if len(set(ary))==1:
18                prefix = ary[0]
19                idx = idx + 1
20            else:
21                break
22        return prefix
23                
24# @lc code=end

Accepted

118/118 cases passed (40 ms)
Your runtime beats 80.45 % of python3 submissions
Your memory usage beats 6.15 % of python3 submissions (13.7 MB)

Leetcode 罗马数字转整数

Leetcode 罗马数字转整数

罗马数字转整数

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边, 所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。

示例 1:

输入: "III"
输出: 3

示例 2:

输入: "IV"
输出: 4

示例 3:

输入: "IX"
输出: 9

示例 4:

输入: "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.

示例 5:

输入: "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.

解题思路

初始化一个字典, 包含所有字符到数字的情况,
注意顺序先特殊情况处理, 防止后面单字符转换后特殊情况消失
将给定的字符串用字典的key-value替换, 再分割成数组, 剔除空值, 每个元素转为数字
用sum求和数组返回

Answer

 1#
 2# @lc app=leetcode.cn id=13 lang=python3
 3#
 4# [13] 罗马数字转整数
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def romanToInt(self, s: str) -> int:
10        dic = {
11        "IV": "+4+",
12        "IX": "+9+",
13        "XL": "+40+",
14        "XC": "+90+",
15        "CD": "+400+",
16        "CM": "+900+",
17        "I": "+1+",
18        "V": "+5+",
19        "X": "+10+",
20        "L": "+50+",
21        "C": "+100+",
22        "D": "+500+",
23        "M": "+1000+",
24        }
25        for k,v in dic.items():
26            s = s.replace(k,v)
27        return sum([int(i) for i in s.split("+") if i])
28
29# @lc code=end

Accepted

3999/3999 cases passed (68 ms)
Your runtime beats 40.85 % of python3 submissions
Your memory usage beats 6.45 % of python3 submissions (13.7 MB)

Leetcode 回文数

Leetcode 回文数

回文数

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

示例 1:

输入: 121
输出: true

示例 2:

输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

示例 3:

输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。

进阶: 你能不将整数转为字符串来解决这个问题吗?

解题思路

判断是否负数, 是负数直接返回False
正数的时候, 转化字符串再转为数组,
取数组长度的一半取整, 然后对数组前后各一半对比, 有一个不同则返回False, 否则返回True

Answer

 1#
 2# @lc app=leetcode.cn id=9 lang=python3
 3#
 4# [9] 回文数
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def isPalindrome(self, x: int) -> bool:
10        if x < 0:
11            return False
12        else:
13            ary = list(str(x))
14            lens = len(ary)
15            half = lens // 2
16            for i in range(0,half):
17                if ary[i] != ary[ -1 * (i + 1)]:
18                    return False
19            return True
20
21# @lc code=end

Accepted

11509/11509 cases passed (84 ms)
Your runtime beats 71.7 % of python3 submissions
Your memory usage beats 5.88 % of python3 submissions (13.8 MB)

进阶思考

首先判断负数, 直接返回False
正数的话, 原始x除10取余数赋值给y, x除10商赋值给s
如果s不为0, 则将商s赋值给x, 继续除10, 余数赋值给 y = y*10 + 本次余数, 商继续赋值给s
知道商s为0, 此时判断 y==s 返回判断结果

进阶 Answer

 1#
 2# @lc app=leetcode.cn id=9 lang=python3
 3#
 4# [9] 回文数
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def isPalindrome(self, x: int) -> bool:
10        if x < 0:
11            return False
12        k = x
13        y = 0
14        while True:
15            y = x % 10 if y == 0 else y * 10 + x % 10
16            s = x // 10
17            if not s:
18                break
19            x = s
20        return y == k
21# @lc code=end
11509/11509 cases passed (88 ms)
Your runtime beats 60.61 % of python3 submissions
Your memory usage beats 5.88 % of python3 submissions (13.7 MB)

Leetcode 整数反转

Leetcode 整数反转

整数反转

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

示例 1:

输入: 123
输出: 321

示例 2:

输入: -123
输出: -321

示例 3:

输入: 120
输出: 21

注意:

假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−2^31, 2^31 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。

解题思路

判断是否负数, 转为正整数
将正整数转为字符串, 再转换为列表, 使用 reverse 函数翻转, 最后用 join 组合起来
还原给出的正负符号
最后输出前判断是否超出32 位的有符号整数

Answer

 1#
 2# @lc app=leetcode.cn id=7 lang=python3
 3#
 4# [7] 整数反转
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def reverse(self, x: int) -> int:
10        if x < 0:
11            x = list(str(-1 * x))
12            x.reverse()
13            y = -1 * int(''.join(x))
14        else:
15            x = list(str(x))
16            x.reverse()
17            y = int(''.join(x))
18        if y < -1 * 2 ** 31 or y > 2 ** 31 -1:
19            return 0
20        else:
21            return y
22# @lc code=end

Accepted

1032/1032 cases passed (48 ms)
Your runtime beats 44.33 % of python3 submissions
Your memory usage beats 6.67 % of python3 submissions (13.8 MB)

Leetcode 两数之和

Leetcode 两数之和

两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

示例:

    给定 nums = [2, 7, 11, 15], target = 9

    因为 nums[0] + nums[1] = 2 + 7 = 9
    所以返回 [0, 1]

解题思路

从列表头部开始每次取出一个数字: A, 并记录取数的索引: k,
在剩余的数组: ary[k+1:] 中查找: target - A 的索引 j,
如果找到返回: [k,j], 没有找到就从头部继续往后取出数字.

Answer

 1#
 2# @lc app=leetcode.cn id=1 lang=python3
 3#
 4# [1] 两数之和
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def twoSum(self, nums: List[int], target: int) -> List[int]:
10        cnt = 0
11        while len(nums):
12            a = nums.pop(0)
13            want = target - a
14            if want in nums:
15                idx = nums.index(want)
16                return [cnt, idx+cnt+1]
17            cnt = cnt + 1
18
19# @lc code=end
 1#
 2# @lc app=leetcode.cn id=1 lang=python3
 3#
 4# [1] 两数之和
 5#
 6
 7# @lc code=start
 8class Solution:
 9    def twoSum(self, nums: List[int], target: int) -> List[int]:
10        cnt = 0
11        lens = len(nums)
12        while cnt < lens - 1:
13            a = nums[cnt]
14            if target - a in nums[cnt + 1:]:
15                return [cnt,nums.index(target - a, cnt + 1)]
16            cnt = cnt + 1
17
18# @lc code=end

Accepted

 29/29 cases passed (768 ms)
 Your runtime beats 43.42 % of python3 submissions
 Your memory usage beats 13.41 % of python3 submissions (14.6 MB)

Linux

Linux 下升级 openssl

Linux 下升级 openssl

在Linux下升级最新版openssl

下载最新源码包

在官网https://www.openssl.org/source/ 页面可以下载最新源码包 当前最新版地址: https://www.openssl.org/source/openssl-3.1.2.tar.gz 使用命令 wget https://www.openssl.org/source/openssl-3.1.2.tar.gz

解压/编译/安装

1
2tar -zxvf openssl-3.1.2.tar.gz
3cd openssl-3.1.2
4./config --prefix=/usr/local/openssl
5make && make install

配置

1
2echo "/usr/local/openssl/lib64/" >> /etc/ld.so.conf
3ldconfig
4
5mv /usr/bin/openssl /usr/bin/openssl.old
6ln -sv /usr/local/openssl/bin/openssl /usr/bin/openssl
7
8openssl version

升级openssl完成后, 编译安装Python ./configure -C --with-openssl=/usr/local/openssl --with-openssl-rpath=auto --prefix=/usr/local/Python3.11

Raspberry Pi 初次安装运行必要配置

Raspberry Pi 初次安装运行时的一些必要配置

Raspberry Pi 基金会开发的一款微型电脑

树莓派,(英语:Raspberry Pi,简写为RPi,别名为RasPi/RPI)是为学习计算机编程教育而设计,只有信用卡大小的微型电脑,其系统基于Linux。

随着Windows 10 IoT的发布,用户可以用上运行Windows的树莓派。

Raspberry Pi 初次安装运行后, 一些必要的配置, 可以更好的运行使用.

启用ssh

  • 在boot磁盘新建文件 ssh 用来启用ssh登录.

配置WIFI

  • 在boot磁盘新建/修改文件 wpa_supplicant.conf
1ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
2update_config=1
3country=CN
4
5network={
6    ssid="yourssid"
7    psk="yourwifipwd"
8    key_mgmt=WPA-PSK
9}

修改用户密码

1# 登录raspberry后修改pi用户密码
2passwd
3# 修改root用户密码
4sudo passwd root
5# 解锁root用户
6sudo passwd --unlock root

配置时区

sudo dpkg-reconfigure tzdata

修改源

1#更改apt软件源
2sudo sed -i 's|raspbian.raspberrypi.org|mirrors.ustc.edu.cn/raspbian|g' /etc/apt/sources.list
3#更改raspberrypi软件源
4sudo sed -i 's|//archive.raspberrypi.org|//mirrors.ustc.edu.cn/archive.raspberrypi.org|g' /etc/apt/sources.list.d/raspi.list
5#更新源
6sudo apt-get update

扩展磁盘空间

sudo raspi-config 选择Advancd Options -> Expand Filesystem 然后重启

Centos Upgrade Python

Centos Upgrade Python

Centos 升级指定版本Python

最近升级Python3.10, 发现centos自带ssl包版本过低, 所以在升级脚本中添加了ssl的升级过程

执行脚本完成后, 自动建立 python3 pip3 软连接

  1
  2#!/bin/bash
  3
  4
  5function log(){
  6    echo -e "\033[31m" ">>>>>> " $(date +"%Y-%m-%d %H:%M:%S") $@ " <<<<<<" "\033[0m"
  7    sleep 2
  8}
  9
 10
 11parent_dir=$(pwd)/
 12
 13
 14# 基础变量
 15install_python_version=3.10.0
 16install_openssl_version=1.1.1l
 17
 18
 19shortver=${install_python_version%.*}
 20doubleshort=${shortver/./}
 21python_packagename=Python-${install_python_version}
 22local_python_dir=/usr/local/${python_packagename}/
 23pyM=/usr/bin/python${install_python_version%%.*}
 24piM=/usr/bin/pip${install_python_version%%.*}
 25pyN=/usr/bin/python${doubleshort}
 26piN=/usr/bin/pip${doubleshort}
 27
 28
 29# https://www.openssl.org/source/openssl-3.0.0.tar.gz
 30# https://www.openssl.org/source/openssl-1.1.1l.tar.gz
 31openssl_packagename=openssl-${install_openssl_version}
 32
 33
 34# centos环境升级
 35# log "yum libary"
 36# yum update
 37# yum install -y gcc libffi-devel zlib* openssl-devel libffi-devel \
 38#     zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make
 39
 40
 41# debian环境升级
 42#apt-get install zlib1g-dev libbz2-dev libssl-dev libncurses5-dev libsqlite3-dev libreadline-dev
 43#    tk-dev libgdbm-dev libdb-dev libpcap-dev xz-utils libexpat1-dev liblzma-dev libffi-dev libc6-dev
 44
 45
 46# 建立软件包目录
 47log "mkdir sofrware dir and into"
 48soft_dir=${parent_dir}soft/
 49[[ ! -d "${soft_dir}" ]] && mkdir -p "${soft_dir}"
 50pushd ${soft_dir}
 51
 52
 53# 移除备份旧文件
 54log "remove old files"
 55rm -fr ${python_packagename}
 56rm -fr ${local_python_dir}
 57[[ -f ${pyM} ]] && mv -f ${pyM}{,.bak}
 58[[ -f ${piM} ]] && mv -f ${piM}{,.bak}
 59[[ -f ${pyN} ]] && mv -f ${pyN}{,.bak}
 60[[ -f ${piN} ]] && mv -f ${piN}{,.bak}
 61
 62
 63# 下载新版源码
 64log "curl openssl and python source, then untar"
 65pyurl=https://www.python.org/ftp/python/${install_python_version}/${python_packagename}.tgz
 66log ${pyurl}
 67if [[ ! -f "${soft_dir}${python_packagename}.tgz" ]]; then
 68    curl -O ${pyurl}
 69fi
 70if [[ ! -f "${soft_dir}${python_packagename}.tgz" ]]; then
 71    log ${python_packagename}.tgz Download Failed
 72fi
 73tar -zxvf ${soft_dir}${python_packagename}.tgz
 74
 75
 76opurl=https://www.openssl.org/source/${openssl_packagename}.tar.gz
 77log opurl
 78if [[ ! -f "${soft_dir}${openssl_packagename}.tar.gz" ]]; then
 79    curl -O ${opurl}
 80    exit 1
 81fi
 82if [[ ! -f "${soft_dir}${openssl_packagename}.tar.gz" ]]; then
 83    log ${openssl_packagename}.tar.gz Download Failed
 84    exit 1
 85fi
 86tar -zxvf ${soft_dir}${openssl_packagename}.tar.gz
 87
 88
 89# 安装新openssl
 90log "install new openssl"
 91sslcnf=$(find /etc/ -name openssl.cnf -printf "%h\n")
 92pushd ${openssl_packagename}
 93./config --prefix=/usr/local/custom-openssl --libdir=lib --openssldir=${sslcnf}
 94make -j1 depend
 95make -j8
 96make install_sw
 97popd
 98
 99
100# 解压源码, 编译安装
101log "into source dir and compile python"
102pushd ${python_packagename}
103./configure -C --with-openssl=/usr/local/custom-openssl --with-openssl-rpath=auto --prefix=${local_python_dir}
104make -j8
105make altinstall
106popd
107
108
109# 建立链接文件
110log "link executable files"
111ln -s ${local_python_dir}bin/python${shortver} ${pyM}
112ln -s ${local_python_dir}bin/python${shortver} ${pyN}
113ln -s ${local_python_dir}bin/pip${shortver} ${piM}
114ln -s ${local_python_dir}bin/pip${shortver} ${piN}
115
116
117# 升级环境包
118log "upgrade pip"
119${piN} install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade pip
120
121
122# 设置腾讯源
123${piN} config set global.index-url https://mirrors.cloud.tencent.com/pypi/simple

Centos Upgrade Sqlite

Centos Upgrade Sqlite

centos 升级 sqlite version=3.7

1# 下载最新版
2wget https://www.sqlite.org/2021/sqlite-autoconf-3370000.tar.gz --no-check-certificate
3tar -zxvf sqlite-autoconf-3370000.tar.gz
4cd sqlite-autoconf-3370000/
5./configure --prefix=/usr/local/ && make && make install

修改profile文件

1export LD_LIBRARY_PATH="/usr/local/lib/"

Linux Curl

Linux Curl

Linux curl

curl 是常用的命令行工具,用来请求 Web 服务器。它的名字就是客户端(client)的 URL 工具的意思。

参数

调试类

-v, –verbose 输出信息 -q, –disable 在第一个参数位置设置后 .curlrc 的设置直接失效,这个参数会影响到 -K, –config -A, –user-agent -e, –referer -K, –config FILE 指定配置文件 -L, –location 跟踪重定向 (H)

CLI显示设置

-s, –silent Silent模式。不输出任务内容 -S, –show-error 显示错误. 在选项 -s 中,当 curl 出现错误时将显示 -f, –fail 不显示 连接失败时HTTP错误信息 -i, –include 显示 response的header (H/F) -I, –head 仅显示 响应文档头 -l, –list-only 只列出FTP目录的名称 (F) -#, –progress-bar 以进度条 显示传输进度

数据传输类

-X, –request [GET|POST|PUT|DELETE|…] 使用指定的 http method 例如 -X POST -H, –header

设定 request里的header 例如 -H “Content-Type: application/json” -e, –referer 设定 referer (H) -d, –data 设定 http body 默认使用 content-type application/x-www-form-urlencoded (H) –data-raw ASCII 编码 HTTP POST 数据 (H) –data-binary binary 编码 HTTP POST 数据 (H) –data-urlencode url 编码 HTTP POST 数据 (H) -G, –get 使用 HTTP GET 方法发送 -d 数据 (H) -F, –form <name=string> 模拟 HTTP 表单数据提交 multipart POST (H) –form-string <name=string> 模拟 HTTP 表单数据提交 (H) -u, –user user:password 使用帐户,密码 例如 admin:password -b, –cookie cookie 文件 (H) -j, –junk-session-cookies 读取文件中但忽略会话cookie (H) -A, –user-agent user-agent设置 (H)

传输设置

-C, –continue-at OFFSET 断点续转 -x, –proxy [PROTOCOL://]HOST[:PORT] 在指定的端口上使用代理 -U, –proxy-user USER[:PASSWORD] 代理用户名及密码

文件操作

-T, –upload-file 上传文件 -a, –append 添加要上传的文件 (F/SFTP)

输出设置

-o, –output 将输出写入文件,而非 stdout -O, –remote-name 将输出写入远程文件 -D, –dump-header 将头信息写入指定的文件 -c, –cookie-jar 操作结束后,要写入 Cookies 的文件位置

用例

  • -A参数指定客户端的用户代理标头,即User-Agent。curl 的默认用户代理字符串是curl/[version]。 curl -A 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' https://google.com

  • 通过-H参数直接指定标头,更改User-Agent。 curl -H 'User-Agent: php/1.0' https://google.com

  • -b参数用来向服务器发送 Cookie。 curl -b 'foo=bar' https://google.com curl -b 'foo1=bar;foo2=bar2' https://google.com curl -b cookies.txt https://www.google.com

  • -c参数将服务器设置的 Cookie 写入一个文件。 curl -c cookies.txt https://www.google.com

  • -d参数用于发送 POST 请求的数据体。 curl -d'login=emma&password=123'-X POST https://google.com/login curl -d 'login=emma' -d 'password=123' -X POST https://google.com/login 使用-d参数以后,HTTP 请求会自动加上标头 Content-Type : application/x-www-form-urlencoded 。 并且会自动将请求转为 POST 方法,因此可以省略-X POST。

  • –data-urlencode 参数等同于-d,发送 POST 请求的数据体,区别在于会自动将发送的数据进行 URL 编码。 curl --data-urlencode 'comment=hello world' https://google.com/login

  • -e参数用来设置 HTTP 的标头Referer,表示请求的来源。 curl -e 'https://google.com?q=example' https://www.example.com

  • -H参数可以通过直接添加标头Referer,达到同样效果。 curl -H 'Referer: https://google.com?q=example' https://www.example.com

  • -F参数用来向服务器上传二进制文件。 curl -F 'file=@photo.png' https://google.com/profile 命令会给 HTTP 请求加上标头Content-Type: multipart/form-data,然后将文件photo.png作为file字段上传。 -F参数可以指定 MIME 类型。 curl -F 'file=@photo.png;type=image/png' https://google.com/profile 上面命令指定 MIME 类型为image/png,否则 curl 会把 MIME 类型设为application/octet-streamcurl -F 'file=@photo.png;filename=me.png' https://google.com/profile 上面命令中,原始文件名为photo.png,但是服务器接收到的文件名为me.png。

  • -G参数用来构造 URL 的查询字符串 curl -G -d 'q=kitties' -d 'count=20' https://google.com/search 上面命令会发出一个 GET 请求,实际请求的URL为https://google.com/search?q=kitties&count=20。如果省略–G,会发出一个 POST 请求。 curl -G --data-urlencode 'comment=hello world' https://www.example.com 如果数据需要 URL 编码,可以结合--data--urlencode参数。

  • -H参数添加 HTTP 请求的标头。 curl -H 'Accept-Language: en-US' https://google.com curl -H 'Accept-Language: en-US' -H 'Secret-Message: xyzzy' https://google.com curl -d '{"login": "emma", "pass": "123"}' -H 'Content-Type: application/json' https://google.com/login

  • -i参数打印出服务器回应的 HTTP 标头。 curl -i https://www.example.com 上面命令收到服务器回应后,先输出服务器回应的标头,然后空一行,再输出网页的源码。

  • -I参数向服务器发出 HEAD 请求,然会将服务器返回的 HTTP 标头打印出来。 curl -I https://www.example.com 上面命令输出服务器对 HEAD 请求的回应。 –head参数等同于-I。 curl --head https://www.example.com

  • -k参数指定跳过 SSL 检测。 curl -k https://www.example.com

  • –limit-rate用来限制 HTTP 请求和回应的带宽,模拟慢网速的环境。 curl --limit-rate 200k https://google.com

  • -o参数将服务器的回应保存成文件,等同于wget命令。 curl -o example.html https://www.example.com

  • -O参数将服务器回应保存成文件,并将 URL 的最后部分当作文件名。 curl -O https://www.example.com/foo/bar.html

  • -s参数将不输出错误和进度信息。 curl -s https://www.example.com

  • -u参数用来设置服务器认证的用户名和密码。 curl -u 'bob:12345' https://google.com/login 上面命令设置用户名为bob,密码为12345, 然后将其转为 HTTP 标头Authorization: Basic Ym9iOjEyMzQ1curl https://bob:12345@google.com/login 上面命令能够识别 URL 里面的用户名和密码,将其转为上个例子里面的 HTTP 标头。 curl -u 'bob' https://google.com/login 上面命令只设置了用户名,执行后,curl 会提示用户输入密码。

  • -x参数指定 HTTP 请求的代理。 curl -x socks5://james:cats@myproxy.com:8080 https://www.example.com 上面命令指定 HTTP 请求通过myproxy.com:8080的 socks5 代理发出。 curl -x james:cats@myproxy.com:8080 https://www.example.com 如果没有指定代理协议,默认为 HTTP

  • -X参数指定 HTTP 请求的方法。 curl -X POST https://www.example.com

  • -r 0-100 分段下载 curl -r 0-100 -o img.part1 http://mydomian.cn/thumb/xxx.jpg curl -r 100-200 -o img.part2 http://mydomian.cn/thumb/xxx.jpg 最后合并cat所有文件

用例收集

  • 下载保存
curl http://mydomain.net > index.html
curl -o index.html http://mydomain.net
curl -O http://mydomain.net/target.tar.gz
  • GET curl http://www.yahoo.com/login.cgi?user=nickname&password=12345

  • POST curl -d "user=nickname&password=12345" http://www.yahoo.com/login.cgi

  • POST文件 curl -F upload= $localfile -F $btn_name=$btn_value http://mydomain.net/~zzh/up_file.cgi

  • 通过代理 curl -x 123.45.67.89:1080 -o page.html http://mydomain.net

  • 保存Cookie curl -x 123.45.67.89:1080 -o page1.html -D cookie0001.txt http://mydomain.net

  • 使用Cookie curl -x 123.45.67.89:1080 -o page1.html -D cookie0002.txt -b cookie0001.txt http://mydomain.net

  • 模仿浏览器 curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -x123.45.67.89:1080 -o page.html -D cookie0001.txt http://mydomain.net

  • 伪造referer curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -x123.45.67.89:1080 -e"mail.yahoo.com" -o page.html -D cookie0001.txt http://mydomain.net

  • 循环下载 curl -O http://mydomain.net/~zzh/screen[1-10].JPG

  • 循环匹配下载 curl -O http://mydomain.net/~{zzh,nick}/[001-201].JPG # >like zzh/001.JPG

  • 循环引用下载 curl -o #2_#1.jpg http://mydomain.net/~{zzh,nick}/[001-201].JPG # like >001_zzh.jpg

  • 断点续传 curl -c -O http://mydomain.net/~zzh/screen1.JPG

  • 分块下载

curl -r  0 -10240  -o "zhao.part1"  http://mydomain.net/~zzh/zhao1.mp3 &\
curl -r 10241 -20480  -o "zhao.part1"  http://mydomain.net/~zzh/zhao1.mp3 &\
curl -r 20481 -40960  -o "zhao.part1"  http://mydomain.net/~zzh/zhao1.mp3 &\
curl -r 40961 - -o  "zhao.part1"  http://mydomain.net/~zzh/zhao1.mp3
..
cat zhao.part* > zhao.mp3

参数列表

在以下选项中,(H) 表示仅适用 HTTP/HTTPS ,(F) 表示仅适用于 FTP

    --anyauth      选择 "any" 认证方法 (H)
-a, --append        添加要上传的文件 (F/SFTP)
    --basic        使用HTTP基础认证(Basic Authentication)(H)
    --cacert FILE  CA 证书,用于每次请求认证 (SSL)
    --capath DIR    CA 证书目录 (SSL)
-E, --cert CERT[:PASSWD] 客户端证书文件及密码 (SSL)
    --cert-type TYPE 证书文件类型 (DER/PEM/ENG) (SSL)
    --ciphers LIST  SSL 秘钥 (SSL)
    --compressed    请求压缩 (使用 deflate 或 gzip)
-K, --config FILE  指定配置文件
    --connect-timeout SECONDS  连接超时设置
-C, --continue-at OFFSET  断点续转
-b, --cookie STRING/FILE  Cookies字符串或读取Cookies的文件位置 (H)
-c, --cookie-jar FILE  操作结束后,要写入 Cookies 的文件位置 (H)
    --create-dirs  创建必要的本地目录层次结构
    --crlf          在上传时将 LF 转写为 CRLF
    --crlfile FILE  从指定的文件获得PEM格式CRL列表
-d, --data DATA    HTTP POST 数据 (H)
    --data-ascii DATA  ASCII 编码 HTTP POST 数据 (H)
    --data-binary DATA  binary 编码 HTTP POST 数据 (H)
    --data-urlencode DATA  url 编码 HTTP POST 数据 (H)
    --delegation STRING GSS-API 委托权限
    --digest        使用数字身份验证 (H)
    --disable-eprt  禁止使用 EPRT 或 LPRT (F)
    --disable-epsv  禁止使用 EPSV (F)
-D, --dump-header FILE  将头信息写入指定的文件
    --egd-file FILE  为随机数据设置EGD socket路径(SSL)
    --engine ENGINGE  加密引擎 (SSL). "--engine list" 指定列表
-f, --fail          连接失败时不显示HTTP错误信息 (H)
-F, --form CONTENT  模拟 HTTP 表单数据提交(multipart POST) (H)
    --form-string STRING  模拟 HTTP 表单数据提交 (H)
    --ftp-account DATA  帐户数据提交 (F)
    --ftp-alternative-to-user COMMAND  指定替换 "USER [name]" 的字符串 (F)
    --ftp-create-dirs  如果不存在则创建远程目录 (F)
    --ftp-method [MULTICWD/NOCWD/SINGLECWD] 控制 CWD (F)
    --ftp-pasv      使用 PASV/EPSV 替换 PORT (F)
-P, --ftp-port ADR  使用指定 PORT 及地址替换 PASV (F)
    --ftp-skip-pasv-ip 跳过 PASV 的IP地址 (F)
    --ftp-pret      在 PASV 之前发送 PRET (drftpd) (F)
    --ftp-ssl-ccc  在认证之后发送 CCC (F)
    --ftp-ssl-ccc-mode ACTIVE/PASSIVE  设置 CCC 模式 (F)
    --ftp-ssl-control ftp 登录时需要 SSL/TLS (F)
-G, --get          使用 HTTP GET 方法发送 -d 数据  (H)
-g, --globoff      禁用的 URL 队列 及范围使用 {} 和 []
-H, --header LINE  要发送到服务端的自定义请求头 (H)
-I, --head          仅显示响应文档头
-h, --help          显示帮助
-0, --http1.0      使用 HTTP 1.0 (H)
    --ignore-content-length  忽略 HTTP Content-Length 头
-i, --include      在输出中包含协议头 (H/F)
-k, --insecure      允许连接到 SSL 站点,而不使用证书 (H)
    --interface INTERFACE  指定网络接口/地址
-4, --ipv4          将域名解析为 IPv4 地址
-6, --ipv6          将域名解析为 IPv6 地址
-j, --junk-session-cookies 读取文件中但忽略会话cookie (H)
    --keepalive-time SECONDS  keepalive 包间隔
    --key KEY      私钥文件名 (SSL/SSH)
    --key-type TYPE 私钥文件类型 (DER/PEM/ENG) (SSL)
    --krb LEVEL    启用指定安全级别的 Kerberos (F)
    --libcurl FILE  命令的libcurl等价代码
    --limit-rate RATE  限制传输速度
-l, --list-only    只列出FTP目录的名称 (F)
    --local-port RANGE  强制使用的本地端口号
-L, --location      跟踪重定向 (H)
    --location-trusted 类似 --location 并发送验证信息到其它主机 (H)
-M, --manual        显示全手动
    --mail-from FROM  从这个地址发送邮件
    --mail-rcpt TO  发送邮件到这个接收人(s)
    --mail-auth AUTH  原始电子邮件的起始地址
    --max-filesize BYTES  下载的最大文件大小 (H/F)
    --max-redirs NUM  最大重定向数 (H)
-m, --max-time SECONDS  允许的最多传输时间
    --metalink      处理指定的URL上的XML文件
    --negotiate    使用 HTTP Negotiate 认证 (H)
-n, --netrc        必须从 .netrc 文件读取用户名和密码
    --netrc-optional 使用 .netrc 或 URL; 将重写 -n 参数
    --netrc-file FILE  设置要使用的 netrc 文件名
-N, --no-buffer    禁用输出流的缓存
    --no-keepalive  禁用 connection 的 keepalive
    --no-sessionid  禁止重复使用 SSL session-ID (SSL)
    --noproxy      不使用代理的主机列表
    --ntlm          使用 HTTP NTLM 认证 (H)
-o, --output FILE  将输出写入文件,而非 stdout
    --pass PASS    传递给私钥的短语 (SSL/SSH)
    --post301      在 301 重定向后不要切换为 GET 请求 (H)
    --post302      在 302 重定向后不要切换为 GET 请求 (H)
    --post303      在 303 重定向后不要切换为 GET 请求 (H)
-#, --progress-bar  以进度条显示传输进度
    --proto PROTOCOLS  启用/禁用 指定的协议
    --proto-redir PROTOCOLS  在重定向上 启用/禁用 指定的协议
-x, --proxy [PROTOCOL://]HOST[:PORT] 在指定的端口上使用代理
    --proxy-anyauth 在代理上使用 "any" 认证方法 (H)
    --proxy-basic  在代理上使用 Basic 认证  (H)
    --proxy-digest  在代理上使用 Digest 认证 (H)
    --proxy-negotiate 在代理上使用 Negotiate 认证 (H)
    --proxy-ntlm    在代理上使用 NTLM 认证 (H)
-U, --proxy-user USER[:PASSWORD]  代理用户名及密码
    --proxy1.0 HOST[:PORT]  在指定的端口上使用 HTTP/1.0 代理
-p, --proxytunnel  使用HTTP代理 (用于 CONNECT)
    --pubkey KEY    公钥文件名 (SSH)
-Q, --quote CMD    在传输开始前向服务器发送命令 (F/SFTP)
    --random-file FILE  读取随机数据的文件 (SSL)
-r, --range RANGE  仅检索范围内的字节
    --raw          使用原始HTTP传输,而不使用编码 (H)
-e, --referer      Referer URL (H)
-J, --remote-header-name 从远程文件读取头信息 (H)
-O, --remote-name  将输出写入远程文件
    --remote-name-all 使用所有URL的远程文件名
-R, --remote-time  将远程文件的时间设置在本地输出上
-X, --request COMMAND  使用指定的请求命令
    --resolve HOST:PORT:ADDRESS  将 HOST:PORT 强制解析到 ADDRESS
    --retry NUM  出现问题时的重试次数
    --retry-delay SECONDS 重试时的延时时长
    --retry-max-time SECONDS  仅在指定时间段内重试
-S, --show-error    显示错误. 在选项 -s 中,当 curl 出现错误时将显示
-s, --silent        Silent模式。不输出任务内容
    --socks4 HOST[:PORT]  在指定的 host + port 上使用 SOCKS4 代理
    --socks4a HOST[:PORT]  在指定的 host + port 上使用 SOCKSa 代理
    --socks5 HOST[:PORT]  在指定的 host + port 上使用 SOCKS5 代理
    --socks5-hostname HOST[:PORT] SOCKS5 代理,指定用户名、密码
    --socks5-gssapi-service NAME  为gssapi使用SOCKS5代理服务名称
    --socks5-gssapi-nec  与NEC Socks5服务器兼容
-Y, --speed-limit RATE  在指定限速时间之后停止传输
-y, --speed-time SECONDS  指定时间之后触发限速. 默认 30
    --ssl          尝试 SSL/TLS (FTP, IMAP, POP3, SMTP)
    --ssl-reqd      需要 SSL/TLS (FTP, IMAP, POP3, SMTP)
-2, --sslv2        使用 SSLv2 (SSL)
-3, --sslv3        使用 SSLv3 (SSL)
    --ssl-allow-beast 允许的安全漏洞,提高互操作性(SSL)
    --stderr FILE  重定向 stderr 的文件位置. - means stdout
    --tcp-nodelay  使用 TCP_NODELAY 选项
-t, --telnet-option OPT=VAL  设置 telnet 选项
    --tftp-blksize VALUE  设备 TFTP BLKSIZE 选项 (必须 >512)
-z, --time-cond TIME  基于时间条件的传输
-1, --tlsv1        使用 => TLSv1 (SSL)
    --tlsv1.0      使用 TLSv1.0 (SSL)
    --tlsv1.1      使用 TLSv1.1 (SSL)
    --tlsv1.2      使用 TLSv1.2 (SSL)
    --trace FILE    将 debug 信息写入指定的文件
    --trace-ascii FILE  类似 --trace 但使用16进度输出
    --trace-time    向 trace/verbose 输出添加时间戳
    --tr-encoding  请求压缩传输编码 (H)
-T, --upload-file FILE  将文件传输(上传)到指定位置
    --url URL      指定所使用的 URL
-B, --use-ascii    使用 ASCII/text 传输
-u, --user USER[:PASSWORD]  指定服务器认证用户名、密码
    --tlsuser USER  TLS 用户名
    --tlspassword STRING TLS 密码
    --tlsauthtype STRING  TLS 认证类型 (默认 SRP)
    --unix-socket FILE    通过这个 UNIX socket 域连接
-A, --user-agent STRING  要发送到服务器的 User-Agent (H)
-v, --verbose      显示详细操作信息
-V, --version      显示版本号并退出
-w, --write-out FORMAT  完成后输出什么
    --xattr        将元数据存储在扩展文件属性中
-q                .curlrc 如果作为第一个参数无效

Curl Api

Curl Api

Linux curl

curl 是常用的命令行工具,用来请求 Web 服务器。它的名字就是客户端(client)的 URL 工具的意思。

参数

调试类

-v, --verbose                          输出信息 
-q, --disable                          在第一个参数位置设置后 .curlrc 的设置直接失效,
                                       这个参数会影响到 -K, --config -A, --user-agent -e, --referer 
-K, --config FILE                      指定配置文件 
-L, --location                         跟踪重定向 (H) 

CLI显示设置

-s, --silent                           Silent模式。不输出任务内容 
-S, --show-error                       显示错误. 在选项 -s 中,当 curl 出现错误时将显示 
-f, --fail                             不显示 连接失败时HTTP错误信息 
-i, --include                          显示 response的header (H/F) 
-I, --head                             仅显示 响应文档头 
-l, --list-only                        只列出FTP目录的名称 (F) 
-#, --progress-bar                     以进度条 显示传输进度 

数据传输类

-X, --request [GET|POST|PUT|DELETE|…]  使用指定的 http method 例如 -X POST 
-H, --header <header>                  设定 request里的header 例如 -H "Content-Type: application/json" 
-e, --referer                          设定 referer (H) 
-d, --data <data>                      设定 http body 默认使用 content-type application/x-www-form-urlencoded (H) 
--data-raw <data>                      ASCII 编码 HTTP POST 数据 (H) 
--data-binary <data>                   binary 编码 HTTP POST 数据 (H) 
--data-urlencode <data>                url 编码 HTTP POST 数据 (H) 
-G, --get                              使用 HTTP GET 方法发送 -d 数据 (H) 
-F, --form <name=string>               模拟 HTTP 表单数据提交 multipart POST (H) 
--form-string <name=string>            模拟 HTTP 表单数据提交 (H) 
-u, --user <user:password>             使用帐户,密码 例如 admin:password 
-b, --cookie <data>                    cookie 文件 (H) 
-j, --junk-session-cookies             读取文件中但忽略会话cookie (H) 
-A, --user-agent                       user-agent设置 (H) 

传输设置

-C, --continue-at OFFSET               断点续转 
-x, --proxy [PROTOCOL://]HOST[:PORT]   在指定的端口上使用代理 
-U, --proxy-user USER[:PASSWORD]       代理用户名及密码 

文件操作

-T, --upload-file <file>               上传文件 
-a, --append                           添加要上传的文件 (F/SFTP) 

输出设置

-o, --output <file>                    将输出写入文件,而非 stdout 
-O, --remote-name                      将输出写入远程文件 
-D, --dump-header <file>               将头信息写入指定的文件 
-c, --cookie-jar <file>                操作结束后,要写入 Cookies 的文件位置 

用例

  • -A参数指定客户端的用户代理标头,即User-Agent。curl 的默认用户代理字符串是curl/[version]。 curl -A 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' https://google.com

  • 通过-H参数直接指定标头,更改User-Agent。 curl -H 'User-Agent: php/1.0' https://google.com

  • -b参数用来向服务器发送 Cookie。 curl -b 'foo=bar' https://google.com curl -b 'foo1=bar;foo2=bar2' https://google.com curl -b cookies.txt https://www.google.com

  • -c参数将服务器设置的 Cookie 写入一个文件。 curl -c cookies.txt https://www.google.com

  • -d参数用于发送 POST 请求的数据体。 curl -d'login=emma&password=123'-X POST https://google.com/login curl -d 'login=emma' -d 'password=123' -X POST https://google.com/login 使用-d参数以后,HTTP 请求会自动加上标头 Content-Type : application/x-www-form-urlencoded 。 并且会自动将请求转为 POST 方法,因此可以省略-X POST。

  • –data-urlencode 参数等同于-d,发送 POST 请求的数据体,区别在于会自动将发送的数据进行 URL 编码。 curl --data-urlencode 'comment=hello world' https://google.com/login

  • -e参数用来设置 HTTP 的标头Referer,表示请求的来源。 curl -e 'https://google.com?q=example' https://www.example.com

  • -H参数可以通过直接添加标头Referer,达到同样效果。 curl -H 'Referer: https://google.com?q=example' https://www.example.com

  • -F参数用来向服务器上传二进制文件。 curl -F 'file=@photo.png' https://google.com/profile 命令会给 HTTP 请求加上标头Content-Type: multipart/form-data,然后将文件photo.png作为file字段上传。 -F参数可以指定 MIME 类型。 curl -F 'file=@photo.png;type=image/png' https://google.com/profile 上面命令指定 MIME 类型为image/png,否则 curl 会把 MIME 类型设为application/octet-streamcurl -F 'file=@photo.png;filename=me.png' https://google.com/profile 上面命令中,原始文件名为photo.png,但是服务器接收到的文件名为me.png。

  • -G参数用来构造 URL 的查询字符串 curl -G -d 'q=kitties' -d 'count=20' https://google.com/search 上面命令会发出一个 GET 请求,实际请求的URL为https://google.com/search?q=kitties&count=20。如果省略–G,会发出一个 POST 请求。 curl -G --data-urlencode 'comment=hello world' https://www.example.com 如果数据需要 URL 编码,可以结合--data--urlencode参数。

  • -H参数添加 HTTP 请求的标头。 curl -H 'Accept-Language: en-US' https://google.com curl -H 'Accept-Language: en-US' -H 'Secret-Message: xyzzy' https://google.com curl -d '{"login": "emma", "pass": "123"}' -H 'Content-Type: application/json' https://google.com/login

  • -i参数打印出服务器回应的 HTTP 标头。 curl -i https://www.example.com 上面命令收到服务器回应后,先输出服务器回应的标头,然后空一行,再输出网页的源码。

  • -I参数向服务器发出 HEAD 请求,然会将服务器返回的 HTTP 标头打印出来。 curl -I https://www.example.com 上面命令输出服务器对 HEAD 请求的回应。 –head参数等同于-I。 curl --head https://www.example.com

  • -k参数指定跳过 SSL 检测。 curl -k https://www.example.com

  • –limit-rate用来限制 HTTP 请求和回应的带宽,模拟慢网速的环境。 curl --limit-rate 200k https://google.com

  • -o参数将服务器的回应保存成文件,等同于wget命令。 curl -o example.html https://www.example.com

  • -O参数将服务器回应保存成文件,并将 URL 的最后部分当作文件名。 curl -O https://www.example.com/foo/bar.html

  • -s参数将不输出错误和进度信息。 curl -s https://www.example.com

  • -u参数用来设置服务器认证的用户名和密码。 curl -u 'bob:12345' https://google.com/login 上面命令设置用户名为bob,密码为12345, 然后将其转为 HTTP 标头Authorization: Basic Ym9iOjEyMzQ1curl https://bob:12345@google.com/login 上面命令能够识别 URL 里面的用户名和密码,将其转为上个例子里面的 HTTP 标头。 curl -u 'bob' https://google.com/login 上面命令只设置了用户名,执行后,curl 会提示用户输入密码。

  • -x参数指定 HTTP 请求的代理。 curl -x socks5://james:cats@myproxy.com:8080 https://www.example.com 上面命令指定 HTTP 请求通过myproxy.com:8080的 socks5 代理发出。 curl -x james:cats@myproxy.com:8080 https://www.example.com
    如果没有指定代理协议,默认为 HTTP

  • -X参数指定 HTTP 请求的方法。 curl -X POST https://www.example.com

  • -r 0-100 分段下载 curl -r 0-100 -o img.part1 http://mydomian.cn/thumb/xxx.jpg curl -r 100-200 -o img.part2 http://mydomian.cn/thumb/xxx.jpg 最后合并cat所有文件

用例收集

  • 下载保存
curl http://mydomain.net > index.html 
curl -o index.html http://mydomain.net 
curl -O http://mydomain.net/target.tar.gz 
  • GET curl http://www.yahoo.com/login.cgi?user=nickname&password=12345

  • POST curl -d "user=nickname&password=12345" http://www.yahoo.com/login.cgi

  • POST文件 curl -F upload= $localfile -F $btn_name=$btn_value http://mydomain.net/~zzh/up_file.cgi

  • 通过代理 curl -x 123.45.67.89:1080 -o page.html http://mydomain.net

  • 保存Cookie curl -x 123.45.67.89:1080 -o page1.html -D cookie0001.txt http://mydomain.net

  • 使用Cookie curl -x 123.45.67.89:1080 -o page1.html -D cookie0002.txt -b cookie0001.txt http://mydomain.net

  • 模仿浏览器 curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -x123.45.67.89:1080 -o page.html -D cookie0001.txt http://mydomain.net

  • 伪造referer curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -x123.45.67.89:1080 -e"mail.yahoo.com" -o page.html -D cookie0001.txt http://mydomain.net

  • 循环下载 curl -O http://mydomain.net/~zzh/screen[1-10].JPG

  • 循环匹配下载 curl -O http://mydomain.net/~{zzh,nick}/[001-201].JPG # >like zzh/001.JPG

  • 循环引用下载 curl -o #2_#1.jpg http://mydomain.net/~{zzh,nick}/[001-201].JPG # like >001_zzh.jpg

  • 断点续传 curl -c -O http://mydomain.net/~zzh/screen1.JPG

  • 分块下载

curl -r  0 -10240  -o "zhao.part1"  http://mydomain.net/~zzh/zhao1.mp3 &\ 
curl -r 10241 -20480  -o "zhao.part1"  http://mydomain.net/~zzh/zhao1.mp3 &\ 
curl -r 20481 -40960  -o "zhao.part1"  http://mydomain.net/~zzh/zhao1.mp3 &\ 
curl -r 40961 - -o  "zhao.part1"  http://mydomain.net/~zzh/zhao1.mp3 
.. 
cat zhao.part* > zhao.mp3 

参数列表

在以下选项中,(H) 表示仅适用 HTTP/HTTPS ,(F) 表示仅适用于 FTP

    --anyauth      选择 "any" 认证方法 (H)   
-a, --append        添加要上传的文件 (F/SFTP)   
    --basic        使用HTTP基础认证(Basic Authentication)(H)   
    --cacert FILE  CA 证书,用于每次请求认证 (SSL)   
    --capath DIR    CA 证书目录 (SSL)   
-E, --cert CERT[:PASSWD] 客户端证书文件及密码 (SSL)   
    --cert-type TYPE 证书文件类型 (DER/PEM/ENG) (SSL)   
    --ciphers LIST  SSL 秘钥 (SSL)   
    --compressed    请求压缩 (使用 deflate 或 gzip)   
-K, --config FILE  指定配置文件   
    --connect-timeout SECONDS  连接超时设置   
-C, --continue-at OFFSET  断点续转   
-b, --cookie STRING/FILE  Cookies字符串或读取Cookies的文件位置 (H)   
-c, --cookie-jar FILE  操作结束后,要写入 Cookies 的文件位置 (H)   
    --create-dirs  创建必要的本地目录层次结构   
    --crlf          在上传时将 LF 转写为 CRLF   
    --crlfile FILE  从指定的文件获得PEM格式CRL列表   
-d, --data DATA    HTTP POST 数据 (H)   
    --data-ascii DATA  ASCII 编码 HTTP POST 数据 (H)   
    --data-binary DATA  binary 编码 HTTP POST 数据 (H)   
    --data-urlencode DATA  url 编码 HTTP POST 数据 (H)   
    --delegation STRING GSS-API 委托权限   
    --digest        使用数字身份验证 (H)   
    --disable-eprt  禁止使用 EPRT 或 LPRT (F)   
    --disable-epsv  禁止使用 EPSV (F)   
-D, --dump-header FILE  将头信息写入指定的文件   
    --egd-file FILE  为随机数据设置EGD socket路径(SSL)   
    --engine ENGINGE  加密引擎 (SSL). "--engine list" 指定列表   
-f, --fail          连接失败时不显示HTTP错误信息 (H)   
-F, --form CONTENT  模拟 HTTP 表单数据提交(multipart POST) (H)   
    --form-string STRING  模拟 HTTP 表单数据提交 (H)   
    --ftp-account DATA  帐户数据提交 (F)   
    --ftp-alternative-to-user COMMAND  指定替换 "USER [name]" 的字符串 (F)   
    --ftp-create-dirs  如果不存在则创建远程目录 (F)   
    --ftp-method [MULTICWD/NOCWD/SINGLECWD] 控制 CWD (F)   
    --ftp-pasv      使用 PASV/EPSV 替换 PORT (F)   
-P, --ftp-port ADR  使用指定 PORT 及地址替换 PASV (F)   
    --ftp-skip-pasv-ip 跳过 PASV 的IP地址 (F)   
    --ftp-pret      在 PASV 之前发送 PRET (drftpd) (F)   
    --ftp-ssl-ccc  在认证之后发送 CCC (F)   
    --ftp-ssl-ccc-mode ACTIVE/PASSIVE  设置 CCC 模式 (F)   
    --ftp-ssl-control ftp 登录时需要 SSL/TLS (F)   
-G, --get          使用 HTTP GET 方法发送 -d 数据  (H)   
-g, --globoff      禁用的 URL 队列 及范围使用 {} 和 []   
-H, --header LINE  要发送到服务端的自定义请求头 (H)   
-I, --head          仅显示响应文档头   
-h, --help          显示帮助   
-0, --http1.0      使用 HTTP 1.0 (H)   
    --ignore-content-length  忽略 HTTP Content-Length 头   
-i, --include      在输出中包含协议头 (H/F)   
-k, --insecure      允许连接到 SSL 站点,而不使用证书 (H)   
    --interface INTERFACE  指定网络接口/地址   
-4, --ipv4          将域名解析为 IPv4 地址   
-6, --ipv6          将域名解析为 IPv6 地址   
-j, --junk-session-cookies 读取文件中但忽略会话cookie (H)   
    --keepalive-time SECONDS  keepalive 包间隔   
    --key KEY      私钥文件名 (SSL/SSH)   
    --key-type TYPE 私钥文件类型 (DER/PEM/ENG) (SSL)   
    --krb LEVEL    启用指定安全级别的 Kerberos (F)   
    --libcurl FILE  命令的libcurl等价代码   
    --limit-rate RATE  限制传输速度   
-l, --list-only    只列出FTP目录的名称 (F)   
    --local-port RANGE  强制使用的本地端口号   
-L, --location      跟踪重定向 (H)   
    --location-trusted 类似 --location 并发送验证信息到其它主机 (H)   
-M, --manual        显示全手动   
    --mail-from FROM  从这个地址发送邮件   
    --mail-rcpt TO  发送邮件到这个接收人(s)   
    --mail-auth AUTH  原始电子邮件的起始地址   
    --max-filesize BYTES  下载的最大文件大小 (H/F)   
    --max-redirs NUM  最大重定向数 (H)   
-m, --max-time SECONDS  允许的最多传输时间   
    --metalink      处理指定的URL上的XML文件   
    --negotiate    使用 HTTP Negotiate 认证 (H)   
-n, --netrc        必须从 .netrc 文件读取用户名和密码   
    --netrc-optional 使用 .netrc 或 URL; 将重写 -n 参数   
    --netrc-file FILE  设置要使用的 netrc 文件名   
-N, --no-buffer    禁用输出流的缓存   
    --no-keepalive  禁用 connection 的 keepalive   
    --no-sessionid  禁止重复使用 SSL session-ID (SSL)   
    --noproxy      不使用代理的主机列表   
    --ntlm          使用 HTTP NTLM 认证 (H)   
-o, --output FILE  将输出写入文件,而非 stdout   
    --pass PASS    传递给私钥的短语 (SSL/SSH)   
    --post301      在 301 重定向后不要切换为 GET 请求 (H)   
    --post302      在 302 重定向后不要切换为 GET 请求 (H)   
    --post303      在 303 重定向后不要切换为 GET 请求 (H)   
-#, --progress-bar  以进度条显示传输进度   
    --proto PROTOCOLS  启用/禁用 指定的协议   
    --proto-redir PROTOCOLS  在重定向上 启用/禁用 指定的协议   
-x, --proxy [PROTOCOL://]HOST[:PORT] 在指定的端口上使用代理   
    --proxy-anyauth 在代理上使用 "any" 认证方法 (H)   
    --proxy-basic  在代理上使用 Basic 认证  (H)   
    --proxy-digest  在代理上使用 Digest 认证 (H)   
    --proxy-negotiate 在代理上使用 Negotiate 认证 (H)   
    --proxy-ntlm    在代理上使用 NTLM 认证 (H)   
-U, --proxy-user USER[:PASSWORD]  代理用户名及密码   
    --proxy1.0 HOST[:PORT]  在指定的端口上使用 HTTP/1.0 代理   
-p, --proxytunnel  使用HTTP代理 (用于 CONNECT)   
    --pubkey KEY    公钥文件名 (SSH)   
-Q, --quote CMD    在传输开始前向服务器发送命令 (F/SFTP)   
    --random-file FILE  读取随机数据的文件 (SSL)   
-r, --range RANGE  仅检索范围内的字节   
    --raw          使用原始HTTP传输,而不使用编码 (H)   
-e, --referer      Referer URL (H)   
-J, --remote-header-name 从远程文件读取头信息 (H)   
-O, --remote-name  将输出写入远程文件   
    --remote-name-all 使用所有URL的远程文件名   
-R, --remote-time  将远程文件的时间设置在本地输出上   
-X, --request COMMAND  使用指定的请求命令   
    --resolve HOST:PORT:ADDRESS  将 HOST:PORT 强制解析到 ADDRESS   
    --retry NUM  出现问题时的重试次数   
    --retry-delay SECONDS 重试时的延时时长   
    --retry-max-time SECONDS  仅在指定时间段内重试   
-S, --show-error    显示错误. 在选项 -s 中,当 curl 出现错误时将显示   
-s, --silent        Silent模式。不输出任务内容   
    --socks4 HOST[:PORT]  在指定的 host + port 上使用 SOCKS4 代理   
    --socks4a HOST[:PORT]  在指定的 host + port 上使用 SOCKSa 代理   
    --socks5 HOST[:PORT]  在指定的 host + port 上使用 SOCKS5 代理   
    --socks5-hostname HOST[:PORT] SOCKS5 代理,指定用户名、密码   
    --socks5-gssapi-service NAME  为gssapi使用SOCKS5代理服务名称   
    --socks5-gssapi-nec  与NEC Socks5服务器兼容   
-Y, --speed-limit RATE  在指定限速时间之后停止传输   
-y, --speed-time SECONDS  指定时间之后触发限速. 默认 30   
    --ssl          尝试 SSL/TLS (FTP, IMAP, POP3, SMTP)   
    --ssl-reqd      需要 SSL/TLS (FTP, IMAP, POP3, SMTP)   
-2, --sslv2        使用 SSLv2 (SSL)   
-3, --sslv3        使用 SSLv3 (SSL)   
    --ssl-allow-beast 允许的安全漏洞,提高互操作性(SSL)   
    --stderr FILE  重定向 stderr 的文件位置. - means stdout   
    --tcp-nodelay  使用 TCP_NODELAY 选项   
-t, --telnet-option OPT=VAL  设置 telnet 选项   
    --tftp-blksize VALUE  设备 TFTP BLKSIZE 选项 (必须 >512)   
-z, --time-cond TIME  基于时间条件的传输   
-1, --tlsv1        使用 => TLSv1 (SSL)   
    --tlsv1.0      使用 TLSv1.0 (SSL)   
    --tlsv1.1      使用 TLSv1.1 (SSL)   
    --tlsv1.2      使用 TLSv1.2 (SSL)   
    --trace FILE    将 debug 信息写入指定的文件   
    --trace-ascii FILE  类似 --trace 但使用16进度输出   
    --trace-time    向 trace/verbose 输出添加时间戳   
    --tr-encoding  请求压缩传输编码 (H)   
-T, --upload-file FILE  将文件传输(上传)到指定位置   
    --url URL      指定所使用的 URL   
-B, --use-ascii    使用 ASCII/text 传输   
-u, --user USER[:PASSWORD]  指定服务器认证用户名、密码   
    --tlsuser USER  TLS 用户名   
    --tlspassword STRING TLS 密码   
    --tlsauthtype STRING  TLS 认证类型 (默认 SRP)   
    --unix-socket FILE    通过这个 UNIX socket 域连接   
-A, --user-agent STRING  要发送到服务器的 User-Agent (H)   
-v, --verbose      显示详细操作信息   
-V, --version      显示版本号并退出   
-w, --write-out FORMAT  完成后输出什么   
    --xattr        将元数据存储在扩展文件属性中   
-q                .curlrc 如果作为第一个参数无效   

Python

Openpyxl 操作续

Openpyxl 操作

Openpyxl 操作

第一步 创建工作簿改名并保存

1import openpyxl
2
3wb = openpyxl.Workbook()
4ws = wb.active
5ws.title = 'SheetName'
6wb.save("./filename.xlsx")
7
8wb.close()

第二步 新建工作簿一个最前一个最后

 1import openpyxl
 2
 3wb = openpyxl.Workbook()
 4ws = wb.active
 5ws.title = 'SheetName'
 6
 7ws = wb.creat_sheet("sheet1", 0)
 8ws = wb.create_sheet("sheet2")
 9
10wb.save("./filename.xlsx")
11
12wb.close()

第三步 写入单元格

 1import openpyxl
 2# step 1
 3wb = openpyxl.Workbook()
 4ws = wb.active
 5ws.title = 'SheetName'
 6
 7# step 2
 8ws = wb.creat_sheet("sheet1", 0)
 9ws = wb.create_sheet("sheet2")
10
11# step 3
12ws['A1'] = 'Interfaces'
13ws['B1'] = 'Description'
14ws.cell(row=2, column=1, value='Gi1/0/1')
15ws.cell(row=3, column=1, value='Gi1/0/2')
16ws.cell(row=2, column=2, value='PC1')
17ws.cell(row=3, column=2, value='PC2')
18
19wb.save("./filename.xlsx")
20
21wb.close()

第四步 查看指定单元格/行/列的内容

 1import openpyxl
 2# step 1
 3wb = openpyxl.Workbook()
 4ws = wb.active
 5ws.title = 'SheetName'
 6
 7# step 2
 8ws = wb.creat_sheet("sheet1", 0)
 9ws = wb.create_sheet("sheet2")
10
11# step 3
12ws['A1'] = 'Interfaces'
13ws['B1'] = 'Description'
14ws.cell(row=2, column=1, value='Gi1/0/1')
15ws.cell(row=3, column=1, value='Gi1/0/2')
16ws.cell(row=2, column=2, value='PC1')
17ws.cell(row=3, column=2, value='PC2')
18
19# step 4
20a3 = ws1['A3']
21print (a3.value)
22
23column_A = ws1['A']
24for i in column_A:
25    print (i.value)
26
27row_3 = ws1[3]
28for i in row_3:
29    print (i.value)
30
31for row in ws1.iter_rows(min_row=1, max_col=2, max_row=3):
32    for cell in row:
33        print (cell.value)
34
35for row in ws1.values:
36    for value in row:
37        print (value)
38
39b3 = ws1['B3']
40b3.value = 'PC3'
41print (b3.value)
42
43wb.save("./filename.xlsx")
44
45wb.close()

第五步 设置工作簿单元格属性

 1import openpyxl
 2from openpyxl.styles import PatternFill, Border, Side
 3
 4# step 1
 5wb = openpyxl.Workbook()
 6ws = wb.active
 7ws.title = 'SheetName'
 8
 9# step 2
10ws = wb.creat_sheet("sheet1", 0)
11ws = wb.create_sheet("sheet2")
12
13# step 3
14ws['A1'] = 'Interfaces'
15ws['B1'] = 'Description'
16ws.cell(row=2, column=1, value='Gi1/0/1')
17ws.cell(row=3, column=1, value='Gi1/0/2')
18ws.cell(row=2, column=2, value='PC1')
19ws.cell(row=3, column=2, value='PC2')
20
21# step 4
22a3 = ws1['A3']
23print (a3.value)
24
25column_A = ws1['A']
26for i in column_A:
27    print (i.value)
28
29row_3 = ws1[3]
30for i in row_3:
31    print (i.value)
32
33for row in ws1.iter_rows(min_row=1, max_col=2, max_row=3):
34    for cell in row:
35        print (cell.value)
36
37for row in ws1.values:
38    for value in row:
39        print (value)
40
41b3 = ws1['B3']
42b3.value = 'PC3'
43print (b3.value)
44
45# step 5
46yellowFill = PatternFill(start_color='FFFF00', end_color='FFFF00', fill_type='solid')
47thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin'))
48
49ws1['A1'].fill=yellowFill
50ws1['B1'].fill=yellowFill
51
52dims = {}
53for row in ws1.rows:
54    for cell in row:
55        cell.border=thin_border
56        if cell.value:
57            dims[cell.column_letter] = max((dims.get(cell.column, 0), len(str(cell.value))))
58
59for col, value in dims.items():
60    ws1.column_dimensions[col].width = value + 1
61
62
63wb.save("./filename.xlsx")
64
65wb.close()

解决PIP安装时开启代理的错误

解决PIP安装类库, 同时开启代理产生的错误

解决PIP安装时开启代理的错误

开启本地代理安装PIP时, 有可能会有如下错误

1$ pip install wmi
2Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
3WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) 
4    after connection broken by 'ProxyError('Cannot connect to proxy.', FileNotFoundError(2, 'No such file or directory'))': /simple/wmi/

解决方法

  • 在系统目录C:\Users\用户\AppData\Roaming新建pip文件夹
  • 在pip文件夹下新建pip.ini文件,并写入如下配置
1[global]
2index-url = http://mirrors.aliyun.com/pypi/simple/
3[install]
4trusted-host = mirrors.aliyun.com

Sqlalchemy Docs

Sqlalchemy Docs

SQLAlchemy 是python中,通过ORM操作数据库的框架。简单点来说,就是帮助我们从烦冗的sql语句中解脱出来,从而不需要再去写原生的sql语句,只需要用python的语法来操作对象,就能被自动映射为sql语句。

Sqlalchemy 简单使用

安装配置

pip install sqlalchemy    

初步使用

 1# 导入:    
 2from sqlalchemy import Column, String, create_engine    
 3from sqlalchemy.orm import sessionmaker    
 4from sqlalchemy.ext.declarative import declarative_base    
 5    
 6# 创建对象的基类:    
 7Base = declarative_base()    
 8    
 9# 定义User对象:    
10class User(Base):    
11    # 表的名字:    
12    __tablename__ = 'user'    
13    
14    # 表的结构:    
15    id = Column(Integer, primary_key=True, autoincrement=True)    
16    name = Column(String(20))    
17    
18# 初始化数据库连接:    
19engine = create_engine('mysql+pymysql://root:root@localhost/tmpdb?charset=utf8')    
20# 创建DBSession类型:    
21DBSession = sessionmaker(bind=engine)    
22# 创建session对象:    
23session = DBSession()    
24# 创建新User对象:    
25new_user = User(id='5', name='Bob')    
26# 添加到session:    
27session.add(new_user)    
28# 提交即保存到数据库:    
29session.commit()    
30# 关闭session:    
31session.close()    

初始化数据库连接

1engine = create_engine('dialect+driver://username:password@host:port/database')    
2# dialect:数据库类型    
3# driver:数据库驱动选择    
4# username:数据库用户名    
5# password: 用户密码    
6# host:服务器地址    
7# port:端口    
8# database:数据库    
 1# PostgreSQL    
 2engine = create_engine('postgresql://username:password@localhost/database')    
 3engine = create_engine('postgresql+psycopg2://username:password@localhost/database')    
 4engine = create_engine('postgresql+pg8000://username:password@localhost/database')    
 5    
 6# Mysql    
 7engine = create_engine('mysql://username:password@localhost/database')    
 8engine = create_engine('mysql+mysqldb://username:password@localhost/database')    
 9engine = create_engine('mysql+mysqlconnector://username:password@localhost/database')    
10engine = create_engine('mysql+oursql://username:password@localhost/database')    
11engine = create_engine('mysql+pymysql://username:password@localhost/database')    
12    
13# Oracle    
14engine = create_engine('oracle://username:password@127.0.0.1:1521/database')    
15engine = create_engine('oracle+cx_oracle://username:password@tnsname')    
16    
17# Microsoft SQL Server    
18engine = create_engine('mssql+pyodbc://username:password@mydsn')    
19engine = create_engine('mssql+pymssql://username:password@hostname:port/database')    
20    
21# SQLite    
22engine = create_engine('sqlite:///database.db')    
23engine = create_engine('sqlite:absolute/path/to/database.db')    
# create_engine 其它可选参数    
# echo :为 True 时候会把sql语句打印出来    
# pool_size: 是连接池的大小,默认为5个,0表示连接数无限制    
# pool_recycle: MySQL 默认情况下如果一个连接8小时内容没有任何动作(查询请求)就会自动断开链接,出现 MySQL has gone away的错误。设置了 pool_recycle 后 SQLAlchemy 就会在指定时间内回收连接。如果设置为3600 就表示 1小时后该连接会被自动回收。    
# pool_pre_ping : 这是1.2新增的参数,如果值为True,那么每次从连接池中拿连接的时候,都会向数据库发送一个类似 select 1 的测试查询语句来判断服务器是否正常运行。当该连接出现 disconnect 的情况时,该连接连同pool中的其它连接都会被回收。    

MetaData Table

 1# 获取元数据    
 2metadata = MetaData()    
 3# 定义表    
 4user = Table('user', metadata,    
 5    Column('id', Integer, primary_key=True),    
 6    Column('name', String(20)),    
 7    )    
 8     
 9color = Table('color', metadata,    
10    Column('id', Integer, primary_key=True),    
11    Column('name', String(20)),    
12    )    
13    
14# 执行sql语句    
15engine.execute(    
16    "INSERT INTO db_name.color(id, name) VALUES ('1', 'liuyao');"    
17)    
18result = engine.execute('select * from color')    
19print(result.fetchall())        

数据模型

 1from sqlalchemy.ext.declarative import declarative_base       
 2from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index       
 3       
 4Base = declarative_base()       
 5       
 6       
 7class User(Base):       
 8    __tablename__ = 'user'       
 9    id = Column(Integer, primary_key=True, autoincrement=True)       
10    name = Column(String(80))       
11       
12    def __repr__(self):       
13        return '<User: {}>'.format(self.name)       
14       
15       
16class Address(Base):       
17    __tablename__ = 'address'       
18    id = Column(Integer, primary_key=True, autoincrement=True)       
19    email = Column(String(80))       
20    user_id = Column(Integer, ForeignKey('user.id'))       
21       
22    def __repr__(self):       
23        return "<Address %s %d>" % (self.email, self.user_id)       
24       
25       
26# 清除已有表       
27Base.metadata.drop_all(engine)               
28# 建立表       
29Base.metadata.create_all(engine)       
30       
31       

数据查询

 1# 前置数据模型代码       
 2class User(Base):       
 3    __tablename__ = 'user'       
 4    id = Column(Integer, primary_key=True, autoincrement=True)       
 5    name = Column(String(40), unique=True, nullable=False)       
 6    email = Column(String(80), nullable=True)       
 7       
 8    def __repr__(self):       
 9        return "<User: %s, %s, %s>" % (self.id, self.name, self.email)       
10       
11    def to_dict(self):       
12        return {c.name: getattr(self, c.name, None) for c in self.__table__.columns}       
13       
14       
15class Course(Base):       
16    __tablename__ = 'course'       
17    id = Column(Integer, primary_key=True, autoincrement=True)       
18    name = Column(String(80))       
19    # ForeignKey 设置外键关联,第一个参数为字符串,user 为数据表名,id 为字段名       
20    # 第二个参数 ondelete 设置删除 User 实例后对关联的 Course 实例的处理规则       
21    # 'CASCADE' 表示级联删除,删除用户实例后,对应的课程实例也会被连带删除       
22    user_id = Column(Integer, ForeignKey('user.id', ondelete='CASCADE'))       
23    # relationship 设置查询接口,以便后期进行数据库查询操作       
24    # 第一个参数为位置参数,参数值为外键关联的映射类名,数据类型为字符串       
25    # 第二个参数 backref 设置反向查询接口       
26    # backref 的第一个参数 'course' 为查询属性,User 实例使用该属性可以获得相关课程实例的列表       
27    # backref 的第二个参数 cascade 如此设置即可实现 Python 语句删除用户数据时级联删除课程数据       
28    user = relationship('User',       
29                        backref=backref('course', cascade='all, delete-orphan'))       
30       
31    def __repr__(self):       
32        return '<Course: %s, %s, %s>' % (self.id, self.name, self.user_id)       
33       
34    def to_dict(self):       
35        return {c.name: getattr(self, c.name, None) for c in self.__table__.columns}       
36       
37       
38class Address(Base):       
39    __tablename__ = "address"       
40    id = Column(Integer, primary_key=True, autoincrement=True, comment='主键')       
41    user_id = Column(Integer, nullable=False, comment='用户ID')       
42    addr = Column(String(200), nullable=True)       
43       
44    def __repr__(self):       
45        return '<Address %s, %s>' % (self.user_id, self.addr)       
46       
47    def to_dict(self):       
48        return {c.name: getattr(self, c.name, None) for c in self.__table__.columns}       
 1userquery = session.query(User)       
 2lst = [       
 3    # 条件查询       
 4    userquery.filter(User.id > 3).all(),       
 5    userquery.filter(User.id > 4).all()[:3],       
 6    session.query(User.name).filter(User.id > 4).all(),       
 7    userquery.filter(User.id == 3).first(),       
 8    userquery.filter(User.id == 5).one(),       
 9    userquery.filter(User.id.between(3,6)).all(),       
10    # 限制返回条数       
11    userquery.filter(User.id > 0).all(),       
12    userquery.filter(User.id > 0).limit(2).all(),       
13    userquery.filter(User.id > 0).offset(2).all(),       
14    userquery.filter(User.id > 0).slice(2, 3).all(),       
15    # 条件排序       
16    userquery.filter(User.id > 0).order_by(User.id).all(),       
17    userquery.filter(User.id > 0).order_by(desc(User.id)).all(),       
18    userquery.filter(User.id > 0).order_by(User.id.asc()).all(),       
19    userquery.filter(User.id > 0).order_by(User.id.desc()).all(),       
20    # 不等于       
21    userquery.filter(User.id != 3).all(),       
22    # 模糊匹配 like, not like       
23    userquery.filter(User.email.like('%ao%')).all(),       
24    userquery.filter(User.email.notlike('%ao%')).all(),       
25    # 匹配       
26    userquery.filter(User.email.startswith("a")).all(),       
27    userquery.filter(User.email.endswith("g")).all(),       
28    userquery.filter(User.email.contains("ao")).all(),       
29    # 属于in_ 不属于 notin_       
30    userquery.filter(User.id.in_([1, 3, 5])).all(),       
31    userquery.filter(User.id.notin_((1, 3, 5))).all(),       
32    # 空判断       
33    userquery.filter(User.name == None).all(),       
34    userquery.filter(User.name.is_(None)).all(),       
35    userquery.filter(User.name.isnot(None)).all(),       
36    # 多条件       
37    userquery.filter(User.id > 3, User.id < 5).all(),       
38    userquery.filter(User.id > 3).filter(User.id < 5).all(),       
39    # 选择条件       
40    userquery.filter(or_(User.id < 2, User.id > 9)).all(),       
41    userquery.filter(and_(User.id > 3, User.id < 6)).all(),       
42    # 去重       
43    userquery.filter(User.id > 3).distinct().all(),       
44    # 聚合函数       
45    session.query(Course.user_id, func.count(Course.user_id).label('number')).group_by(Course.user_id).all(),       
46    session.query(Course.user_id, func.count(Course.user_id).label('number')).group_by(Course.user_id).having(func.count(Course.user_id) > 1).all(),       
47    session.query(Course.user_id, func.sum(Course.user_id).label('number')).group_by(Course.user_id).all(),       
48    session.query(Course.user_id, func.max(Course.user_id).label('number')).group_by(Course.user_id).all(),       
49    session.query(Course.user_id, func.min(Course.user_id).label('number')).group_by(Course.user_id).all(),       
50    # 使用extract提取时间中的分钟或者天来分组       
51    session.query(extract('minute', User.creatime).label('minute'), func.count('*').label('count')).group_by('minute').all(),       
52    session.query(extract('day', User.creatime).label('day'), func.count('*').label('count')).group_by('day').all(),       
53    # Join       
54    有外键       
55    session.query(User.id, User.name.label('uname'), Course.name.label("cname")).join(Course).filter(User.id > 4).all(),       
56    无外键, 指定关联关系       
57    session.query(User.id, User.name, Address.addr).join(Address, User.id == Address.user_id).filter(User.id > 5).all(),       
58    # text 直接写sql       
59    userquery.filter(text("id>:id")).params(id=4).all(),       
60       
61]       
62       
63# 外连接       
64smtp = session.query(User).filter(User.id > 5).subquery()       
65lst.append(session.query(smtp.c.name, Address.addr).outerjoin(smtp, Address.user_id == smtp.c.id).all())       
66       
67       
68for res in lst:       
69    print(res)       
70    # 单对象       
71    # data = [r.to_dict() for r in res]       
72    # print(data)       
73    # 多表查询时       
74    # data = [dict(zip(result.keys(), result)) for result in res]       
75    # print(data)       
76    print("*" * 30)       

模型关系

使用代码维护表间外键关联

 1class Blog(Base):
 2    __tablename__ = 'blog'
 3
 4    id = Column(BIGINT, primary_key=True, autoincrement=True)
 5    title = Column(String(64), server_default='', nullable=False)
 6    text = Column(Text, nullable=False)
 7    user = Column(BIGINT, nullable=False)  # Column(BIGINT, ForeignKey('user.id'), index=True, nullable=False)
 8    create = Column(BIGINT, index=True, server_default='0', nullable=False)
 9
10    def __repr__(self):
11        return '<Course: %s, %s, %s>' % (self.id, self.title, self.user)
12
13class User(Base):
14    __tablename__ = 'user'
15
16    id = Column(BIGINT, primary_key=True, autoincrement=True)
17    name = Column(String(32), server_default='', nullable=False)
18    username = Column(String(32), index=True, server_default='', nullable=True)
19    password = Column(String(64), server_default='', nullable=False)
20
21    def __repr__(self):
22        return '<Course: %s, %s, %s>' % (self.id, self.name, self.username)
23
24
25# 查询
26print( session.query(User).all() )
27pirnt( session.query(Blog).all() )
28print( session.query(Blog).join(User, user.id==Blog.user).all() )

使用数据库维护表间外键关联

 1class Blog(Base):
 2    __tablename__ = 'blog'
 3
 4    id = Column(BIGINT, primary_key=True, autoincrement=True)
 5    title = Column(String(64), server_default='', nullable=False)
 6    text = Column(Text, nullable=False)
 7    user = Column(BIGINT, ForeignKey('user.id'), index=True, nullable=False)
 8    create = Column(BIGINT, index=True, server_default='0', nullable=False)
 9
10    def __repr__(self):
11        return '<Course: %s, %s, %s>' % (self.id, self.title, self.user)
12
13class User(Base):
14    __tablename__ = 'user'
15
16    id = Column(BIGINT, primary_key=True, autoincrement=True)
17    name = Column(String(32), server_default='', nullable=False)
18    username = Column(String(32), index=True, server_default='', nullable=True)
19    password = Column(String(64), server_default='', nullable=False)
20
21    def __repr__(self):
22        return '<Course: %s, %s, %s>' % (self.id, self.name, self.username)
23
24
25# 查询
26print( session.query(User).all() )
27pirnt( session.query(Blog).all() )
28print( session.query(Blog).join(User).filter(User.id==3).all() )

backref & back_populates

 1# backref 只要一边写上就可以
 2class User(Base):
 3    __tablename__ = 'user'
 4    id = Column(Integer, primary_key=True, autoincrement=True)
 5    name = Column(String(80))
 6
 7    addresses = relationship("Address", backref="user")
 8
 9    def __repr__(self):
10        return '<User: {}>'.format(self.name)
11
12
13class Address(Base):
14    __tablename__ = 'address'
15    id = Column(Integer, primary_key=True, autoincrement=True)
16    email = Column(String(80))
17    user_id = Column(Integer, ForeignKey('user.id'))
18
19    def __repr__(self):
20        return "<Address %s %d>" % (self.email, self.user_id)
21
22# back_populates 要两边都写上
23class User(Base):
24    __tablename__ = 'user'
25    id = Column(Integer, primary_key=True, autoincrement=True)
26    name = Column(String(80))
27
28    addresses = relationship("Address", back_populates="user")
29
30    def __repr__(self):
31        return '<User: {}>'.format(self.name)
32
33
34class Address(Base):
35    __tablename__ = 'address'
36    id = Column(Integer, primary_key=True, autoincrement=True)
37    email = Column(String(80))
38    user_id = Column(Integer, ForeignKey('user.id'))
39
40    user = relationship("User", back_populates="addresses")
41
42    def __repr__(self):
43        return "<Address %s %d>" % (self.email, self.user_id)
44
45# 查询
46
47user = session.query(User).get(3)
48print(user, user.address)
49addr = session.qeury(Address).get(3)
50print(addr, addr.user)

一对多关联

 1class Parent(Base):  # 一
 2    __tablename__ = 'parent'
 3    id = Column(Integer, primary_key=True)
 4    name = Column(String(64), nullable=False)
 5    children = relationship("Child", backref=backref('parents'))
 6
 7
 8class Child(Base):  # 多
 9    __tablename__ = 'child'
10    id = Column(Integer, primary_key=True)
11    name = Column(String(64), nullable=False)
12    parent_id = Column(Integer, ForeignKey('parent.id'))
13
14# 一对多 一方
15# children = relationship("Child", backref=backref('parents'), cascade="all, delete-orphan")
16# 一对多 多方
17# parents = relationship("Parent", backref=backref('children', cascade="all, delete-orphan"))
18# 以上可以级联删除

一对一关联

1    

多对多关联

1    

Python Faker基础

Python Faker基础

Faker库基础应用

安装使用

pip install Faker    
    
from faker import Faker   # 1    
fake = Faker()            # 2    
fake.name()               # 3    
# Donna Kelly    
fake.address()            # 4    
# 519 Donna River    
    

使用中文数据

from faker import Faker               
fake = Faker(locale='zh_CN')           
fake.name()                            
# 庞超    
fake.address()                         
# 河北省辛集县合川张街p座 489476    

其他API

地址相关

fake.address()            # 地址    
# '香港特别行政区大冶县上街钟街k座 664713'    
     
fake.building_number()    # 楼名        
# 'v座'    
     
fake.city()               # 完整城市名    
# '长春县'    
     
fake.city_name()          # 城市名字(不带市县)    
# '梧州'    
     
fake.city_suffix()        # 城市后缀名    
# '市'    
     
fake.country()            # 国家名称    
# '厄立特里亚'    
     
fake.country_code(representation="alpha-2")    
# 'BZ'                    # 国家编号    
     
fake.district()           # 地区    
# '沙湾'    
     
fake.postcode()           # 邮编    
# '332991'    
     
fake.province()           # 省    
# '河北省'    
     
fake.street_address()     # 街道地址    
# '武汉街D座'    
     
fake.street_name()        # 街道名称    
# '广州路'    
     
fake.street_suffix()      # 街道后缀名    
# '路'    
汽车相关    
    
fake.license_plate()      # 牌照    
# 'ZCO 000'    

银行相关

fake.bank_country()          # 银行所属国家    
# 'GB'    
     
fake.bban()                  # 基本银行账号    
# 'TPET9323218579379'              
     
fake.iban()                  # 国际银行代码    
# 'GB82IRVM1531009974701'    

条形码相关

fake.ean(length=13)    # EAN条形码    
# '5456457843465'    
     
fake.ean13()           # EAN13条形码    
# '2689789887590'    
     
fake.ean8()            # EAN8条形码    
# '52227936'    

颜色相关

fake.color_name()        # 颜色名称    
# 'Orange'    
     
fake.hex_color()         # 颜色十六进制值    
# '#a5cb7c'    
     
fake.rgb_color()         # 颜色RGB值    
# '15,245,42'    
     
fake.rgb_css_color()     # CSS颜色值    
# 'rgb(15,70,13)'    
     
fake.safe_color_name()   # 安全色    
# 'aqua'    
     
fake.safe_hex_color()    # 安全色十六进制值    
# '#881100'    

公司相关

fake.bs()                 # 商业用词    
# 'synthesize strategic vortals'    
     
fake.catch_phrase()       # 妙句(口号)    
# 'Robust even-keeled service-desk'    
     
fake.company()            # 公司名称    
# '富罳科技有限公司'    
     
fake.company_prefix()     # 公司名称前缀    
# '商软冠联'    
     
fake.company_suffix()     # 公司名称后缀    
# '网络有限公司'    

信用卡相关

fake.credit_card_expire(start="now", end="+10y", date_format="%m/%y")    # 过期年月    
# '11/20'                                                    
     
fake.credit_card_full(card_type=None)            # 完整信用卡信息    
# 'VISA 16 digit\n秀珍 卢\n4653084445257690 11/19\nCVC: 935\n'    
     
fake.credit_card_number(card_type=None)          # 信用卡卡号    
# '4339481813664365360'    
     
fake.credit_card_provider(card_type=None)        # 信用卡提供商    
# 'VISA 19 digit'    
     
fake.credit_card_security_code(card_type=None)   # 信用卡安全码    
# '597'    

货币相关

fake.cryptocurrency()           # 加密货币代码+名称    
# ('TRX', 'TRON')    
     
fake.cryptocurrency_code()      # 加密货币代码    
# 'MZC'    
     
fake.cryptocurrency_name()      # 加密货币名称    
# 'Ripple'    
     
fake.currency()                 # 货币代码+名称    
# ('GNF', 'Guinean franc')    
     
fake.currency_code()            # 货币代码    
# 'SOS'    
     
fake.currency_name()            # 货币名称    
# 'Lebanese pound'    

时间相关

fake.am_pm()        # AM或PM    
# 'PM'    
     
fake.century()      # 世纪    
# 'XII'    
     
fake.date(pattern="%Y-%m-%d", end_datetime=None)            # 日期字符串(可设置格式和最大日期)    
# '1998-05-13'    
     
fake.date_between(start_date="-30y", end_date="today")      # 日期(可设置限定范围)    
# datetime.date(2014, 8, 17)    
     
fake.date_between_dates(date_start=None, date_end=None)     # 同上    
# datetime.date(2019, 10, 14)    
     
fake.date_object(end_datetime=None)                         # 日期(可设置最大日期)    
# datetime.date(1981, 12, 20)    
     
fake.date_of_birth(tzinfo=None, minimum_age=0, maximum_age=115)    # 出生日期    
# datetime.date(1931, 12, 8)    
     
fake.date_this_century(before_today=True, after_today=False)       # 本世纪日期    
# datetime.date(2003, 5, 4)    
     
fake.date_this_decade(before_today=True, after_today=False)        # 本年代中的日期    
# datetime.date(2014, 1, 29)    
     
fake.date_this_month(before_today=True, after_today=False)         # 本月中的日期    
# datetime.date(2019, 10, 10)    
     
fake.date_this_year(before_today=True, after_today=False)          # 本年中的日期    
# datetime.date(2019, 3, 6)    
     
fake.date_time(tzinfo=None, end_datetime=None)                     # 日期和时间    
# datetime.datetime(1990, 8, 11, 22, 25)    
     
fake.date_time_ad(tzinfo=None, end_datetime=None, start_datetime=None)    # 日期和时间(从001年1月1日到现在)    
# datetime.datetime(244, 12, 17, 9, 59, 56)    
     
fake.date_time_between(start_date="-30y", end_date="now", tzinfo=None)    # 日期时间(可设置限定范围)    
# datetime.datetime(1995, 4, 19, 17, 23, 51)    
     
fake.date_time_between_dates(datetime_start=None, datetime_end=None, tzinfo=None)    # 同上    
# datetime.datetime(2019, 10, 14, 14, 15, 36)                                      
     
fake.date_time_this_century(before_now=True, after_now=False, tzinfo=None)     # 本世纪中的日期和时间    
# datetime.datetime(2009, 8, 26, 18, 27, 9)    
     
fake.date_time_this_decade(before_now=True, after_now=False, tzinfo=None)      # 本年代中的日期和时间    
# datetime.datetime(2019, 2, 24, 22, 18, 44)    
     
fake.date_time_this_month(before_now=True, after_now=False, tzinfo=None)       # 本月中的日期和时间    
# datetime.datetime(2019, 10, 3, 9, 20, 44)    
     
fake.date_time_this_year(before_now=True, after_now=False, tzinfo=None)        # 本年中的日期和时间    
# datetime.datetime(2019, 2, 10, 7, 3, 18)    
     
fake.day_of_month()   # 几号    
# '23'    
     
fake.day_of_week()    # 星期几    
# 'Tuesday'    
     
fake.future_date(end_date="+30d", tzinfo=None)        # 未来日期    
# datetime.date(2019, 10, 28)    
     
fake.future_datetime(end_date="+30d", tzinfo=None)    # 未来日期和时间    
# datetime.datetime(2019, 10, 28, 21, 4, 35)    
     
fake.iso8601(tzinfo=None, end_datetime=None)          # iso8601格式日期和时间    
# '1995-04-10T00:45:01'    
     
fake.month()                                          # 第几月    
# '07'    
     
fake.month_name()                                     # 月份名称    
# 'December'    
     
fake.past_date(start_date="-30d", tzinfo=None)        # 过去日期    
# datetime.date(2019, 10, 3)    
     
fake.past_datetime(start_date="-30d", tzinfo=None)    # 过去日期和时间    
# datetime.datetime(2019, 9, 30, 20, 25, 43)    
     
fake.time(pattern="%H:%M:%S", end_datetime=None)      # 时间(可设置格式和最大日期时间)    
# '14:26:44'    
     
fake.time_delta(end_datetime=None)                    # 时间间隔    
# datetime.timedelta(0)    
     
fake.time_object(end_datetime=None)                   # 时间(可设置最大日期时间)    
# datetime.time(4, 41, 39)    
     
fake.time_series(start_date="-30d", end_date="now", precision=None, distrib=None, tzinfo=None)    
# <generator object Provider.time_series at 0x7fadf51e0930>    
     
fake.timezone()    # 时区    
# 'Asia/Baku'    
     
fake.unix_time(end_datetime=None, start_datetime=None)    # UNIX时间戳    
# 393980728    
     
fake.year()        # 某年    
# '2016'    

文件相关

fake.file_extension(category=None)                # 文件扩展名    
# 'avi'    
     
fake.file_name(category=None, extension=None)     # 文件名    
# '专业.pptx'    
     
fake.file_path(depth=1, category=None, extension=None)    # 文件路径    
# '/的话/以上.ods'    
     
fake.mime_type(category=None)                     # MIME类型    
# 'application/xop+xml'    
     
fake.unix_device(prefix=None)                     # UNIX设备    
# '/dev/xvdq'    
     
fake.unix_partition(prefix=None)                  # UNIX分区    
# '/dev/xvdc6'    

坐标相关

fake.coordinate(center=None, radius=0.001)        # 坐标    
# Decimal('147.543284')    
     
fake.latitude()                                   # 纬度    
# Decimal('66.519139')    
     
fake.latlng()                                     # 经纬度    
# (Decimal('55.3370965'), Decimal('-15.427896'))    
     
fake.local_latlng(country_code="US", coords_only=False)    # 返回某个国家某地的经纬度    
# ('25.67927', '-80.31727', 'Kendall', 'US', 'America/New_York')    
     
fake.location_on_land(coords_only=False)                   # 返回地球上某个位置的经纬度    
# ('42.50729', '1.53414', 'les Escaldes', 'AD', 'Europe/Andorra')    
     
fake.longitude()                                   # 经度    
# Decimal('70.815233')    

网络相关

fake.ascii_company_email(*args, **kwargs)        # 企业邮箱(ascii编码)    
# 'qiuyan@xiulan.cn'    
     
fake.ascii_email(*args, **kwargs)                # 企业邮箱+免费邮箱(ascii编码)    
# 'lei59@78.net'    
     
fake.ascii_free_email(*args, **kwargs)           # 免费邮箱(ascii编码)    
# 'pcheng@gmail.com'    
     
fake.ascii_safe_email(*args, **kwargs)           # 安全邮箱(ascii编码)    
# 'fangyan@example.org'    
     
fake.company_email(*args, **kwargs)              # 企业邮箱    
# 'scao@pingjing.net'    
     
fake.domain_name(levels=1)                       # 域名    
# 'dy.cn'    
     
fake.domain_word(*args, **kwargs)                # 二级域名    
# 'gangxiuying'    
     
fake.email(*args, **kwargs)                      # 企业邮箱+免费邮箱    
# 'na13@ding.cn'    
     
fake.free_email(*args, **kwargs)                 # 免费邮箱    
# 'fang48@hotmail.com'    
     
fake.free_email_domain(*args, **kwargs)          # 免费邮箱域名    
# 'yahoo.com'    
     
fake.hostname(*args, **kwargs)                   # 主机名    
# 'lt-70.53.cn'    
     
fake.image_url(width=None, height=None)          # 图片URL    
# 'https://placekitten.com/752/243'    
     
fake.ipv4(network=False, address_class=None, private=None)    # ipv4    
# '160.152.149.78'    
     
fake.ipv4_network_class()                                     # ipv4网络等级    
# 'b'    
     
fake.ipv4_private(network=False, address_class=None)          # 私有ipv4    
# '10.99.124.57'    
     
fake.ipv4_public(network=False, address_class=None)           # 公共ipv4    
# '169.120.29.235'    
     
fake.ipv6(network=False)                                      # ipv6    
# 'f392:573f:d60f:9aed:2a4c:36d7:fe5b:7034'    
     
fake.mac_address()                            # MAC地址    
# '62:67:79:8c:c2:40'    
     
fake.safe_email(*args, **kwargs)              # 安全邮箱    
# 'jing58@example.org'    
     
fake.slug(*args, **kwargs)                    # URL中的slug    
# ''    
     
fake.tld()                                    # 顶级域名    
# 'cn'    
     
fake.uri()                                    # URI    
# 'http://yi.com/list/main/explore/register.php'    
     
fake.uri_extension()                          # URI扩展    
# '.php'    
     
fake.uri_page()                               # URI页    
# 'terms'    
     
fake.uri_path(deep=None)                      # URI路径    
# 'blog/tags/blog'    
     
fake.url(schemes=None)                        # URL    
# 'http://liutao.cn/'    
     
fake.user_name(*args, **kwargs)               # 用户名    
# 'xiulan80'    

图书相关

fake.isbn10(separator="-")        # ISBN-10图书编号    
# '0-588-73943-X'    
     
fake.isbn13(separator="-")        # ISBN-13图书编号    
# '978-1-116-51399-8'    

职位相关

fake.job()        # 职位    
# '法务助理'    

文本相关

fake.paragraph(nb_sentences=3, variable_nb_sentences=True, ext_word_list=None)    # 单个段落    
# '最新事情生产.方面解决名称责任而且.类型其实内容发生电脑.音乐具有今年是一.'    
     
fake.paragraphs(nb=3, ext_word_list=None)                                         # 多个段落                                                
# ['使用评论管理.没有广告工作评论是否.', '帖子而且专业.这些比较完全发现准备设计工具.', '完成详细发生空间汽车.新闻电影您的游戏这种操作网站知道.']    
     
fake.sentence(nb_words=6, variable_nb_words=True, ext_word_list=None)    # 单个句子    
# '直接这样点击单位对于时候.'    
     
fake.sentences(nb=3, ext_word_list=None)                                 # 多个句子    
# ['电话国际项目管理.', '软件之后提高一样次数电影规定.', '东西会员发展什么不断经济.']    
     
fake.text(max_nb_chars=200, ext_word_list=None)                          # 单个文本    
# ('资源信息得到因此开发资源资料.\n'    
#  '国家这样等级需要用户如此.电话非常一切游戏所以学校类型.不要正在如果来源认为投资在线.\n'    
#  '这些更新密码其中起来实现有些.以上事情重要通过.\n'    
#  '但是就是介绍最大深圳简介设计.历史这种可以出现中心社区.\n'    
#  '政府当然包括简介全国内容生活.有些地址以上.回复这些来自搜索现在不断经营不断.\n'    
#  '操作为什孩子报告东西拥有如此.相关特别业务日本这种.合作问题准备比较谢谢.')    
     
fake.texts(nb_texts=3, max_nb_chars=200, ext_word_list=None)             # 多个文本    
# [   '地址控制无法正在必须中心积分一些.支持制作安全.\n'    
#     '比较最新最大她的功能能够是一.主题选择当前显示.\n'    
#     '的话社会现在地区阅读继续所有.美国数据正在深圳不能.\n'    
#     '能够查看其中生活商品.谢谢认为之后以及以下之后这里.\n'    
#     '活动支持人民这么今年.要求包括生活运行技术社会.\n'    
#     '当前更多游戏.下载一点开发论坛法律为了美国.\n'    
#     '如何更新个人谢谢作为还有论坛.销售销售法律学生这么责任一些.',    
#     '日本最大方法活动主题到了结果.教育还有孩子觉得简介出现国际.东西国家图片威望品牌.\n'    
#     '那些会员现在准备可能.威望部分文件主题东西业务一切之间.所以必须当前方法.\n'    
#     '等级大小重要可能下载孩子.来源感觉业务文件以后深圳学校.网络什么新闻都是安全.\n'    
#     '资料重要成功谢谢时候音乐安全相关.电脑系列日期.工具使用搜索来源首页.\n'    
#     '直接企业影响大小什么.相关品牌选择她的规定来源推荐.',    
#     '中文文化数据内容系统.他们这些之间深圳.\n'    
#     '联系城市出现部分都是政府生活.社会同时人民市场现在决定需要.其他政府简介深圳教育加入对于.\n'    
#     '运行是一语言安全通过大小学生.商品然后信息由于虽然.\n'    
#     '因为关于选择希望行业具有深圳.出现价格那么下载提高知道人员.设备直接显示事情帖子正在两个关于.\n'    
#     '系列公司大家.论坛所以完全文章标准.活动中国工具电脑.\n'    
#     '主题作者不能.进行国家系统地区增加.经验质量价格我的.']    
     
fake.word(ext_word_list=None)                                            # 单个词语    
# '新闻'    
     
fake.words(nb=3, ext_word_list=None, unique=False)                       # 多个词语    
# ['选择', '历史', '规定']    

编码相关

fake.binary(length=1048576)                # 二进制    
# (b'\xbf\xce\x01Y:\xf7\xf4\xe0G]\x94*Rb\x9f\x85\xb6\xcd\x83\x15\t\xbc\x16\x8d'    
#  b'\xcb\n\x90\x10S\x1e85\x91\xae\x06\xbdq.\xf6c\x1f\xfd\x94=\\\xf9_\xc2'    
#  b't\xe0{\x15\xd9\x8fW7\xe5[\x0b\x84\xd2\x94\xf4\xd91\xd2\x91\x01\xb5\xeej\x84'    
#  b'*\x81\x96\xa7\xa9\xda\x1f\xee\x9a\xb0\x1d\xef\xad\x92\x1c\x0f\xa0U6\xaf'    
#  b'x5\x9f\x93\\b \xf7kq\xfe\x97(\xe0Q\x89*\xbb\x8b\x9a\x14\xd2\xfe\x07'    
#  b'\xfe\xcfYy\x16\x12\xef\xe3\xd9%\x95\\\x80O\xec\x9f\xf7\x88\xfal'    
#  b'\x11\x93\x94\xb1\xd9\xf6b\xf0\x7f\xa2\x95\x93[\x98\xf3\xe0$\xdd\xe0D'    
#  b'\xde\x8c\xe3\xe0\xc0f\xab\x1c\xf6\xdf]\xbe8U\x11\xc7\xce\xf6f\xc9'    
#  b'1\xa6\xda\x85\xe6.\xda\xd1_\x8a\xbe\x05\xbf\xf4*x [\xb9\xc3\xbb\x99\xa1\xbe'    
#  b'GT\xb75\x96\x8a\x9a:`o\x1bm\xe9KzT\x0c\xdc\xb1\xe7ssiN\xcb2\x8eY'    
#  b'\xd1\xb4\x8c+\xe9\xc1Ph\x0fD\x0f\xd5}\n/K$\x85J\xaf\x1d\xb2\xd0R\xa7n0l'    
#  b'\xafQ\x91\x95\xac]a\xe1\x8f\x1f\x9e`e\xd2\x1f\xaa\xeb\xf3[}(\xd60\x01'    
#  b'Y\r\xe2XCW\xba\xa3\xad\xe4OP\x891=\xff\xae\xb9\x9d\xa2!\xfa2\r\x81\xfat\xfb'    
#  b'3t%\xd5\x11B\x94Os\x8d\xc5\xae%\xa6\x93}[p\x02\xd7\xba\xa4\xf0?R\xbb\xf6\xb1'    
#  b'h\x12J\x05\xce\xf9\xcd\xc6\xa7\xed\x80\x9e\x9e\xf8q]\xab\x9a\xd7\xd6'    
#  b'\xad\xecK\x1d=\xb0?\xb2\x83\t<\xb2ZGl\x9f\x8dmI\x1d\xf1jh\xd3s\x9d\xd6\xf9'    
#  b'\x8e\xbfs\xa9_\xe0\xaf\x86O\xde|\x17\xb5\x8b\xe4:Z\xa1\x01f\xc9l[Z'    
#  b'\xb4\x7fS\x0f7\x9c\x9d\xdd\xd3PY\x86\xf4\xec\xcb\x87\x05\xafU-\xaebY~'    
#  b"\x9f\xec\xf6\x9c\x84\x99'S\xd4\t.\xd0x\xbb\x01<&\xdd\xfc6M\xa9|R"    
#  b'\xec\xf9b\xcdz\x9a\x97p\xb5\xb6\x13\xd9\xab\x91C\xe4\x95\xc9\x18\xaeAi\\N'    
#  b"#\x99\t+Z\xd2\xf1\x89\xa0L\x04\xef\xaf<\xc4\xfbO\xcd\x83\xd4\x17'C\x10"    
#  b'\x0b\xd6\xb5Cv\x98}E\xc9;\xbf\x05\xab\xc7 W\xa8\xbcmX\x06\x865\xbe\\f\xedc'    
#  b'\xacb\xc8\x84\xc0KI\xd5\xea\x888\x93^\xfcE\xee,^(\x97g\xd17\xcd8\xabU\x95'    
#  b'\x17~]\x08\x11\xa4\xbf\xed\xf3\xabm\x15l\xde\xf5\x06c\xe1\xad+'    
#  b'\xed\xd1\xa5\xda\x15\xbax\xac}\x8e\xd7\x8831\x04\xb3\xae\xc7\xb4\x04'    
#  b'y\xda!\xeb\x1e\xcd\n+\x94#4\xe51\xc8\xe9t\n.:\xfd\xcfc\x1a\xcf\x99VY\x11'    
#  b'Y\x1bF\xe9\x9e\xebK\x86WD\x80\x12\xf1\x11z\xf6\xe3vV4\xbcB\n^k(\x1aw'    
#  b'<\xfd\x95z\t\xf7\xaa_F%n\xc4\xeb\x94\xcd\x80\xffh\xbe{^\x04\xe3\xe7'    
#  b'\xab\xa3\xd9\x037\x86\xde~J\x15th\x98_\xda\xe25\xeaO\xc8\x15\xae\xd7\xa9'    
#  b'\x80\x9as\xef<FU\xb2\x10\x7fN\x05\x8dd_\xef\x0bQO-\x9diW\xdc\xcdV\xbe*'    
#  b'\x13\xa7$\x08\xe4\xb8\x96bd\xcf\xe7\xd6h\xe9.{Z:S\xef\xc4\x14R\x91'    
#  b"\xce\xd3\xcd\xe3\xbc\x9f!Y\x05A\xa00\x11\xca\xaa\xeb\xc4')\xb3\xdcF\x8e\xfa"    
#  b'\xbd\x9b:\xae\x1f\xbe<7]\x93E\xc2\x1b\x17\xc95x\x8f\x88|\xb8^\xea\x06'    
#  b'(\x9d\xc5\xeb\x8a|\x9f\x05\x83\xfe\xf5KsUy\xdc\xd1S\x96\xda\xc5q\xc4\xfd'    
#  b'\xeb\xc4"\x14Y\x1cU\x99\xe8\x11r\x04\x941\xa1\xac^c\xbbG\xc4\xd8\xb70'    
#  b'\xadX\x98\xad\xf8\xc1\x11\x10\xbc\x00\x80\x84\x05\x07b\x8c0\x93\xe6\xd8'    
#  b'\xe2I\xea\xecm+-\x8aY\xb8F\x0e\x19#zH{/\xcb\x88\xac\xa9\xfe\x84cH[_'    
#  b'0d\xc6\xc4\x0b\r\x9ef\n\xb3\x97d\xb4;\xf1\x014kv\xd9h\xad\x18/\xe6\xf1r\xa1'    
#  b'3\x9cz\xf7\x90\r\xaf\xed\x85\x07\x80\xbb\xc2\x82\xe4\xcc\x91\xc8\xdf\x9a'    
#  b'`St\xd8\x98\xbb\xac\xe9\x93\xe0*\xd7\x9b/)\x93\x08\xc1\x0cxhD\xd2\xf1'    
#  b'\xbe5\xe1\x1f:\x04\x07\xf1\xb4\xaeJ\xe2\xe0[\x9e\xa4\x9b\xed)\xbf\xc2}+\x88'    
#  b'\x08I^f\x82-\xa2o\xb2\xc3\x85\xc5;Z\x13B\xf76~\x9af\xf7\xa9\x1a\xa4\xd4\xb8b')    
     
fake.boolean(chance_of_getting_true=50)    # 布尔值    
# True    
     
fake.md5(raw_output=False)                 # Md5    
# '0712ca7a3be00aa01c823de37dc61230'    
     
fake.null_boolean()                        # NULL+布尔值    
# True    
     
fake.password(length=10, special_chars=True, digits=True, upper_case=True, lower_case=True)                           # 密码    
# '^7cSoHR1^r'    
     
fake.sha1(raw_output=False)                # SHA1    
# 'f89f039d9fc00860651d9a567ac27990ae609445'    
     
fake.sha256(raw_output=False)              # SHA256    
# '675a85aa0d29583200f75351e35b4af0335af835fc617382cbd9fece258b6520'    
     
fake.uuid4(cast_to=<class 'str'>)          # UUID4    
# '0d7be36a-febd-4f9f-bf1e-791c0ee1227b'    

人物相关

fake.first_name()            # 名字    
# '强'    
     
fake.first_name_female()     # 名字(女)    
# '桂荣'    
     
fake.first_name_male()       # 名字(男)    
# '志强'    
     
fake.first_romanized_name()  # 名字(罗马文)    
# 'Chao'    
     
fake.last_name()             # 姓    
# '宋'    
     
fake.last_name_female()      # 姓(女)    
# '陆'    
     
fake.last_name_male()        # 姓(男)    
# '曾'    
     
fake.last_romanized_name()   # 姓(罗马文)    
# 'Xie'    
     
fake.name()                  # 姓名    
# '王凯'    
     
fake.name_female()           # 姓名(女)    
# '戴丽丽'    
     
fake.name_male()             # 姓名(男)    
# '刘荣'    
     
fake.prefix()                # 称谓    
# ''    
     
fake.prefix_female()         # 称谓(女)    
# ''    
     
fake.prefix_male()           # 称谓(男)    
# ''    
     
fake.romanized_name()        # 称谓(罗马文)    
# 'Guiying Chang'    
     
fake.suffix()                # 姓名后缀(中文不适用)    
# ''    
     
fake.suffix_female()    
# ''    
     
fake.suffix_male()    
# ''    

电话相关

fake.msisdn()                # 完整手机号码(加了国家和国内区号)    
# '9067936325890'    
     
fake.phone_number()          # 手机号    
# '18520149907'    
     
fake.phonenumber_prefix()    # 区号    
# 145    

档案相关

fake.profile(fields=None, sex=None)        # 档案(完整)    
# {   'address': '河南省昆明市清河哈尔滨路H座 496152',    
#     'birthdate': datetime.date(2014, 11, 20),    
#     'blood_group': 'AB+',    
#     'company': '易动力信息有限公司',    
#     'current_location': (Decimal('77.504143'), Decimal('-167.365806')),    
#     'job': '培训策划',    
#     'mail': 'liangyang@yahoo.com',    
#     'name': '杨磊',    
#     'residence': '澳门特别行政区台北县西夏兴城街L座 803680',    
#     'sex': 'F',    
#     'ssn': '140722200004166520',    
#     'username': 'lei65',    
#     'website': [   'http://www.29.cn/',    
#                    'http://www.lei.cn/',    
#                    'http://lishao.net/',    
#                    'https://www.feng.net/']}    
     
fake.simple_profile(sex=None)               # 档案(简单)    
# {   'address': '广西壮族自治区南宁市花溪孙街c座 653694',    
#     'birthdate': datetime.date(1993, 12, 16),    
#     'mail': 'haomin@yahoo.com',    
#     'name': '任秀英',    
#     'sex': 'F',    
#     'username': 'iding'}    

Python相关

fake.pybool()    # Python布尔值    
# False    
     
fake.pydecimal(left_digits=None, right_digits=None, positive=False, min_value=None, max_value=None)  # Python十进制数    
# Decimal('-837022273798.0')    
     
fake.pydict(nb_elements=10, variable_nb_elements=True, *value_types)    # Python字典    
# {   '一种': 6381,    
#     '可以': -9242847.69292,    
#     '地址': 9668,    
#     '拥有': 'jVBverSGAJvHsrcZPFDg',    
#     '控制': Decimal('-98521.0'),    
#     '本站': datetime.datetime(1983, 5, 30, 22, 51, 22),    
#     '来源': 'MRTmgbdlwNlqHiIDUVTN',    
#     '标题': 929,    
#     '注册': 'QvYtlygVIopYPasYHCQr',    
#     '解决': -7138575.3,    
#     '问题': 1115.0}    
     
fake.pyfloat(left_digits=None, right_digits=None, positive=False, min_value=None, max_value=None)        # Python浮点数    
# 6.7442382094132    
     
fake.pyint(min_value=0, max_value=9999, step=1)    # Python整型值    
# 8326    
     
fake.pyiterable(nb_elements=10, variable_nb_elements=True, *value_types)    # Python可迭代对象    
# {'gang42@gmail.com', Decimal('-638462592926556.0'), 5383, 1608, 185608.962728, datetime.datetime(2013, 8, 7, 10, 44, 51), 'xvqHfWdLyTkaFoguvnqd', datetime.datetime(1999, 9, 10, 4, 41, 29), Decimal('4627589014.65023'), 'http://57.cn/category/', 'UZJwIrsLowvwVGAChwzB', Decimal('68.623476938'), 'mtUbDpTHnQAPVjXzknIM'}    
     
fake.pylist(nb_elements=10, variable_nb_elements=True, *value_types)    # Python列表    
# [   589,    
#     'https://www.yangbai.cn/main/',    
#     'http://fang.cn/faq/',    
#     'HvtSTwWqDtughQLYibOd',    
#     Decimal('-3541501.934427'),    
#     2758,    
#     datetime.datetime(2018, 2, 22, 9, 51, 8),    
#     5375,    
#     'UVXMfCqJyZwBkfgGhQiH',    
#     'HfxybvRTPwaFmuhwvKLT',    
#     Decimal('-21565647052012.8'),    
#     'wEqWsXKTputijSMWhCIb']    
     
fake.pyset(nb_elements=10, variable_nb_elements=True, *value_types)    # Python集合    
# {7105, 'sidMFYVhXjkNZnHHimJJ', 'yexiuying@kw.cn', 'GPxoyEYixUGAoRCiEmDe', datetime.datetime(2001, 6, 17, 12, 49, 57), 'vOsPAdmmCmkJxeBUpBJP', -75011.0}    
     
fake.pystr(min_chars=None, max_chars=20)    # Python字符串    
# 'NOlWELuogcxSfRjYauSV'    
     
fake.pystruct(count=10, *value_types)       # Python结构    
# (   [   'SQeHWPNdooccsfbZslee',    
#         'nDXibfaPXSpmIpxtDUWP',    
#         'DrZHepzMfNPRrxgcXwvR',    
#         988.956374402,    
#         7239,    
#         4885,    
#         datetime.datetime(1972, 6, 13, 14, 18, 11),    
#         -582284.9732,    
#         datetime.datetime(1997, 8, 23, 9, 19, 6),    
#         'http://www.hu.cn/homepage.php'],    
#     {   '一般': 'oqUQKBhqNylyofEditXs',    
#         '不要': 'qTlztJembuRZHFEzZnGO',    
#         '价格': -2100690667.387,    
#         '国内': datetime.datetime(1989, 9, 3, 11, 27, 11),    
#         '密码': 'aWaufuJAzfgeuhyXAwDL',    
#         '开发': 'aJvNisEMynJcAPhbNAHa',    
#         '方法': 'WVEqHUnnkpUbAnllUqKL',    
#         '汽车': 'bfQlaULiNfjgkrqQUCnL',    
#         '用户': 'WDYNlInLyCcIXMFgyLDS',    
#         '那个': 'qWivpUnOcTwGDhOXihOb'},    
#     {   '个人': {   1: 'http://www.ik.cn/categories/tags/search/homepage/',    
#                   2: [   'gBSKOBAYYlPwILaWgory',    
#                          'xoeueUWWgbvNHDxKYASD',    
#                          'nkcelmDSpqiQasuKvNZg'],    
#                   3: {   1: 2000,    
#                          2: 'SeDZKUpCxrCLlrDIlPxV',    
#                          3: [Decimal('7833105.737'), Decimal('-7.994')]}},    
#         '帖子': {   0: 'HXTKojcilYqgYmFUMjuk',    
#                   1: [6887, 3635, 'http://hezhu.com/list/main/terms.html'],    
#                   2: {   0: 'hkong@fujiang.cn',    
#                          1: 4676,    
#                          2: ['JYEFavcRqcsdpnSMwENU', 'vxu@gmail.com']}},    
#         '应该': {   7: 'EmzzdZrmUpIetxPktXAU',    
#                   8: [   Decimal('4786692875733.0'),    
#                          datetime.datetime(2016, 10, 11, 10, 38, 20),    
#                          'ghtelDQAsBeYDaokgbYg'],    
#                   9: {   7: 'yanding@yahoo.com',    
#                          8: 'dtjdazSyZCStWkVYwIvK',    
#                          9: ['TPTzKNGReDCJmrfTkKmd', 'TKQmVfrNRioICuqCrrDQ']}},    
#         '我的': {   3: 'http://17.cn/home/',    
#                   4: [   'https://www.guiyingsu.cn/category/',    
#                          'gweRIERFoojbKxRiiliG',    
#                          'dMjUNjDRCSpdrNAlHXRp'],    
#                   5: {   3: 'YeIsIoVHcIgAQWYZkQiR',    
#                          4: 'hGDzyNMVafuDMXSbbhzY',    
#                          5: [977, 'xCFBFdaPHNyFscSCqEWd']}},    
#         '或者': {   9: 'owgjdYQvTWZIZRewhkev',    
#                   10: ['nHusiXLRunAMvynwjJgu', 6500, 'cQRHfcdFJGUyPDlIocqG'],    
#                   11: {   9: 'sETogfbiwRIqFlrGXeiT',    
#                           10: 'tliang@kong.cn',    
#                           11: [   'https://chaohao.cn/register.html',    
#                                   'fang21@yahoo.com']}},    
#         '技术': {   4: 8843,    
#                   5: [-5660697068472.0, 7952, -52210308185.53],    
#                   6: {   4: 6477,    
#                          5: 8669,    
#                          6: ['sGueDRKWFAtTExnruySP', 'YZcIHHkbDRLUgeHhblCu']}},    
#         '深圳': {   5: 2532,    
#                   6: [   Decimal('66661967013036.0'),    
#                          'lei14@yahoo.com',    
#                          'https://www.fangyao.cn/categories/search.html'],    
#                   7: {   5: datetime.datetime(1988, 9, 11, 2, 30, 1),    
#                          6: 50.1,    
#                          7: [   'https://www.gang.cn/',    
#                                 'http://www.liao.cn/posts/app/main.html']}},    
#         '生产': {   2: 2187,    
#                   3: [   8629589.339,    
#                          'QvftOABFsahZurjYIPTr',    
#                          'GumqSZMuOSIfrUzjTzKO'],    
#                   4: {   2: 1982,    
#                          3: 'WatxfisQAelRTuwopoOA',    
#                          4: ['xiacheng@00.cn', 'flrVEiuWlEnJjbxCazQG']}},    
#         '起来': {   6: 'luming@yahoo.com',    
#                   7: [   'http://www.yu.cn/home.php',    
#                          'vvmhckwxQGnMCafhjXIA',    
#                          Decimal('-511928454.48')],    
#                   8: {   6: 'https://www.naguiying.cn/',    
#                          7: 279.928,    
#                          8: [5034, 'shaochao@17.cn']}},    
#         '那么': {   8: 'PNrBODNdjLnhalWpVMXk',    
#                   9: [   datetime.datetime(1973, 7, 4, 11, 42, 8),    
#                          'iye@gmail.com',    
#                          'iEPyTnfNhNhWWXbkStQC'],    
#                   10: {   8: Decimal('-227034846260.0'),    
#                           9: Decimal('616424892362.0'),    
#                           10: [   'AjpDMNozhUbedUuOZWdL',    
#                                   datetime.datetime(1972, 10, 27, 8, 36, 39)]}}})    
     
fake.pytuple(nb_elements=10, variable_nb_elements=True, *value_types)    # Python元组    
# (   Decimal('989085669.60574'),    
#     'yang44@hotmail.com',    
#     794,    
#     datetime.datetime(1989, 12, 11, 4, 10, 40),    
#     234,    
#     'TyEwXywfUShjlUVwtMAk',    
#     'NLUdMSRYoBHmGGPhbwor',    
#     -69.356824324)    

身份证相关

fake.ssn(min_age=18, max_age=90)    # 身份证    
# '410622198603154708'    

用户代理相关

fake.android_platform_token()        # 安卓    
# 'Android 5.0.1'    
     
fake.chrome(version_from=13, version_to=63, build_from=800, build_to=899)    # Chrome    
# ('Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_10_9) AppleWebKit/534.0 (KHTML, '    
#  'like Gecko) Chrome/62.0.826.0 Safari/534.0')    
     
fake.firefox()                       # FireFox    
# ('Mozilla/5.0 (Windows NT 5.1; cs-CZ; rv:1.9.0.20) Gecko/2010-12-02 06:14:30 '    
#  'Firefox/3.6.5')    
     
fake.internet_explorer()             # Ie    
# 'Mozilla/5.0 (compatible; MSIE 7.0; Windows 95; Trident/3.0)'        
     
fake.ios_platform_token()            # ios    
# 'iPhone; CPU iPhone OS 5_1_1 like Mac OS X'    
     
fake.linux_platform_token()          # Linux    
# 'X11; Linux i686'    
     
fake.linux_processor()               # Linux处理器    
# 'x86_64'    
     
fake.mac_platform_token()            # Mac    
# 'Macintosh; U; PPC Mac OS X 10_11_2'    
     
fake.mac_processor()                 # Mac处理器    
# 'Intel'    
     
fake.opera()                         # Opera    
# 'Opera/8.32.(Windows 98; Win 9x 4.90; mr-IN) Presto/2.9.188 Version/10.00'    
     
fake.safari()                        # Safari    
# ('Mozilla/5.0 (Windows; U; Windows NT 6.0) AppleWebKit/533.43.6 (KHTML, like '    
#  'Gecko) Version/4.0.5 Safari/533.43.6')    
     
fake.user_agent()                    # 随机用户代理    
# 'Mozilla/5.0 (compatible; MSIE 9.0; Windows 95; Trident/3.0)'    
     
fake.windows_platform_token()        # Windows    
# 'Windows NT 6.2'    

Python 技巧

Python 技巧

Python 小技巧

统计代码运行时间

1import time
2
3btime = time.time()
4a = [x**3 for x in range(10000000)]
5etime = time.time()
6print("used {:.5}s" % (etime-btime))

使用set替代list查找

1data = (i**2 for i in range(100000))
2dlst = list(data)
3dset = set(data)
4
51234 in dlst
61234 in dset

其他加速技巧

  • 避免使用全局变量
  • 交换变量不使用中间值
  • 字符串拼接使用join
  • 使用for循环替代while

Atexit

Atexit

Python 退出程序时执行代码 atexit

python atexit 模块定义了一个 register 函数,用于在 python 解释器中注册一个退出函数, 这个函数在解释器正常终止时自动执行,一般用来做一些资源清理的操作。 atexit 按注册的相反顺序执行这些函数; 例如注册A、B、C,在解释器终止时按顺序C,B,A运行。

 1import atexit
 2
 3print("some code ............")
 4
 5
 6def exit0(*args, **kwarg):
 7    print('exit0')
 8    for arg in args:
 9        print(' ' * 4, arg)
10
11    for item in kwarg.items():
12        print(' ' * 4, item)
13
14
15def exit1():
16    print('exit1')
17    raise Exception('exit1')
18
19
20def exit2():
21    print('exit2')
22    print(1 / 0)
23
24
25atexit.register(exit0, *[1, 2, 3], **{"a": 1, "b": 2, })
26atexit.register(exit1)
27atexit.register(exit2)
28
29
30@atexit.register
31def exit3():
32    print('exit3')
33
34
35print('other code ..............')
36
37
38if __name__ == '__main__':
39    pass

Openpyxl 操作

Openpyxl 操作

Openpyxl 操作

xls xlsx 文件格式转换

openpyxl是用于读取/写入Excel 2010 xlsx/xlsm文件的Python库, 也就是说openpyxl这个Python库不支持xls文件的读取和操作

可以手工打开另存转换格式 或者

 1import os
 2import win32com.client as win32
 3filename = '.\1.xls'
 4Excelapp = win32.gencache.EnsureDispatch('Excel.Application')
 5workbook = Excelapp.Workbooks.Open(filename)
 6# 转xlsx时: FileFormat=51,
 7# 转xls时:  FileFormat=56,
 8workbook.SaveAs(filename.replace('xls', 'xlsx'), FileFormat=51)
 9workbook.Close()
10Excelapp.Application.Quit()
11# 删除源文件
12# os.remove(filename)
13
14# 如果想将xlsx的文件转换为xls的话,则可以使用以下的代码:
15# workbook.SaveAs(filename.replace('xlsx', 'xls'), FileFormat=56)

创建、打开工作簿

 1import openpyxl
 2
 3# 创建新工作簿
 4wb = openpyxl.WorkBook()
 5# 在指定位置新建工作表
 6ws = wb.create_sheet('sheetname', 0)
 7
 8# 打开已有工作簿
 9wb = openpyxl.load_workbook('xlsx_filename')
10# 打开已有工作表
11ws = wb['sheetname']
12ws1 = wb.get_sheet_by_name('sheetname')
13
14# 设置工作表标签颜色
15ws.sheet_properties.tabColor = 'ff0000'
16
17# 读取已有所有工作表名称
18for sht in ws.sheetnames:
19    print("sht : ", sht)
20# 保存并退出
21wb.save('xlsx_filename')
22wb.close()

单元格操作

 1# 访问指定单元格
 2cell_1 = ws['A1']
 3cell_2 = ws.cell(row=1, column=1)
 4
 5# 返回指定单元格的值
 6value_1 = ws['A1'].value
 7value_2 = ws.cell(row=1, column=1).value
 8
 9# 设置指定单元格内容
10ws['A1'].value = 'xlsx 内容'
11ws.cell(row=1, column=1).value ='xlsx 内容'
12
13# 多个单元格
14# 访问A1至C3范围单元格
15cell_range = ws['A1':'C3']
16# 访问A列所有存在数据的单元格
17colA = ws['A']
18# 访问A列到C列所有存在数据的单元格
19col_range = ws['A:C']
20# 访问第1行所有存在数据的单元格
21row1 = ws[1]
22# 访问第1行至第5行所有存在数据的单元格
23row_range = ws[1:5]
24
25# 多行列
26for row in ws.iter_rows(min_row=1, max_col=2, max_row=2):
27    for cell in row:
28        print(cell)
29#输出:
30<Cell 'sht'.A1>
31<Cell 'sht'.B1>
32<Cell 'sht'.A2>
33<Cell 'sht'.B2>
34
35for col in ws.iter_cols(min_row=1, max_col=2, max_row=2):
36         for cell in col:
37             print(cell)
38#输出:
39<Cell 'sht'.A1>
40<Cell 'sht'.A2>
41<Cell 'sht'.B1>
42<Cell 'sht'.B2>
43
44# 单元格的常见属性
45print(ws.cell(column=2, row=9).column_letter)
46print(ws.cell(column=2, row=9).coordinate)
47print(ws.cell(column=2, row=9).col_idx)
48print(ws.cell(column=2, row=9).encoding)
49print(ws.cell(column=2, row=9).offset)
50print(ws.cell(column=2, row=9).is_date)
51print(ws.cell(column=2, row=9).data_type)
52print(ws.cell(column=2, row=9).has_style)
53print(ws.cell(column=2, row=9).style)
54print(ws.cell(column=2, row=9).style_id)
55print(ws.cell(column=2, row=9).font)
56print(ws.cell(column=2, row=9).alignment)
57print(ws.cell(column=2, row=9).border)
58print(ws.cell(column=2, row=9).fill)
59print(ws.cell(column=2, row=9).number_format)
60print(ws.cell(column=2, row=9).hyperlink)
61
62# 调整列宽和行高
63# 调整列宽
64ws.column_dimensions['A'].width = 20.0
65# 调整行高
66ws.row_dimensions[1].height = 40
67
68# 合并单元格
69ws.merge_cells("A1:B1")
70ws.merge_cells(start_column=3,end_column=5,start_row=3,end_row=5)

单元格样式设置

 1from openpyxl import *
 2from openpyxl.styles import PatternFill, Font, Alignment, Border, Side
 3
 4# 设置字体
 5font = Font(name='微软雅黑',
 6            size=11,
 7            color='FF000000',
 8            bold=True,
 9            italic=True,
10            vertAlign='baseline',
11            underline='double',
12            strike=False)
13wsheet['A2'].font = font
14
15# 边线设置
16side_type = Side(border_style='mediumDashDot',color='FF000000')
17border = Border(left=side_type,
18                right=side_type,
19                top=side_type,
20                bottom=side_type,
21                diagonal=side_type,
22                diagonal_direction=30,
23                outline=side_type,
24                vertical=side_type,
25                horizontal=side_type
26                )
27
28wsheet['A3'].border = border
29# border_style的样式有:
30# ‘dashDot’,‘dashDotDot’,‘dashed’,‘dotted’,‘double’,
31# ‘hair’,‘medium’,‘mediumDashDot’,‘mediumDashDotDot’,
32# ‘mediumDashed’,‘slantDashDot’,‘thick’,‘thin’
33
34# 填充设置
35fill = PatternFill(fill_type = 'darkDown',start_color='A6DA70D6',end_color='000000')
36wsheet['A4'].fill = fill
37# fill_type类型有:'none'、'solid'、'darkDown'、'darkGray'、'darkGrid'、'darkHorizontal'、'darkTrellis'、'darkUp'、'darkVertical'、'gray0625'、
38# 'gray125'、'lightDown'、'lightGray'、'lightGrid'、'lightHorizontal'、
39# 'lightTrellis'、'lightUp'、'lightVertical'、'mediumGray'
40
41# 对齐设置
42align = Alignment(horizontal='center',vertical='center',text_rotation=0,wrap_text=True,shrink_to_fit=True,indent=0)
43wsheet['A6'].alignment = align
44# Horizontal:水平方向,左对齐left,居中center对齐和右对齐right可选。
45# Vertical:垂直方向,有居中center,靠上top,靠下bottom,两端对齐justify等可选。
46# text_rotation:文本旋转度。
47# wrap_text:自动换行
48# Indent:缩进。
49
50# 数字格式设置
51wsheet['A9'].number_format = 'd-mmm-yy'
52
53col = ws.column_dimensions['A']
54col.number_format = u'#,##0.00€'
55# 一些格式
56# 0: 'General',
57# 1: '0',
58# 2: '0.00',
59# 3: '#,##0',
60# 4: '#,##0.00',
61# 5: '"$"#,##0_);("$"#,##0)',
62# 6: '"$"#,##0_);[Red]("$"#,##0)',
63# 7: '"$"#,##0.00_);("$"#,##0.00)',
64# 8: '"$"#,##0.00_);[Red]("$"#,##0.00)',
65# 9: '0%',
66# 10: '0.00%',
67# 11: '0.00E+00',
68# 12: '# ?/?',
69# 13: '# ??/??',
70# 14: 'mm-dd-yy',
71# 15: 'd-mmm-yy',
72# 16: 'd-mmm',
73# 17: 'mmm-yy',
74# 18: 'h:mm AM/PM',
75# 19: 'h:mm:ss AM/PM',
76# 20: 'h:mm',
77# 21: 'h:mm:ss',
78# 22: 'm/d/yy h:mm',
79#
80# 37: '#,##0_);(#,##0)',
81# 38: '#,##0_);[Red](#,##0)',
82# 39: '#,##0.00_);(#,##0.00)',
83# 40: '#,##0.00_);[Red](#,##0.00)',
84#
85# 41: r'_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)',
86# 42: r'_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)',
87# 43: r'_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)',
88#
89# 44: r'_("$"* #,##0.00_)_("$"* \(#,##0.00\)_("$"* "-"??_)_(@_)',
90# 45: 'mm:ss',
91# 46: '[h]:mm:ss',
92# 47: 'mmss.0',
93# 48: '##0.0E+0',
94# 49: '@',

使用公式

1# 所有可用公式都在这里
2from openpyxl.utils import FORMULAE
3print(len(FORMULAE))
4print(FORMULAE)
5
6
7sheet["C2"] = "=SUM(A2,B2)"

合并拆分单元格

1ws.merge_cells('A2:D2')
2ws.unmerge_cells('A2:D2')
3# or equivalently
4ws.merge_cells(start_row=2, start_column=1, end_row=4, end_column=4)
5ws.unmerge_cells(start_row=2, start_column=1, end_row=4, end_column=4)

隐藏行列

1ws.column_dimensions.group('A','D', hidden=True)
2ws.row_dimensions.group(1,10, hidden=True)
3wb.save('group.xlsx')

插入删除行列

1ws.insert_rows(7)
2ws.insert_cols(3)
3ws.delete_rows(7)
4ws.delete_cols(3)

Xlwings 操作

Xlwings 操作

Xlwings 操作

创建工作簿,工作表

 1import xlwings as xw
 2
 3# 创建一个新的App,并在新App中新建一个Book
 4wb = xw.Book()
 5wb.save('1.xlsx')
 6wb.close()
 7
 8# 当前App下新建一个Book
 9# visible参数控制创建文件时可见的属性
10app=xw.App(visible=False,add_book=False)
11wb=app.books.add()
12
13ws = wb.sheets.avtive
14ws1 = wb.sheets.add('新建工作表', after=ws)
15
16wb.save('1.xlsx')
17wb.close()
18#结束进程
19app.quit()

打开已有工作簿

 1import xlwings as xw
 2app=xw.App(visible=True,add_book=False)
 3#不显示Excel消息框
 4app.display_alerts=False
 5#关闭屏幕更新,可加快宏的执行速度
 6app.screen_updating=False
 7
 8wb=app.books.open('1.xlsx')
 9# 输出打开的excle的绝对路径
10# print(wb.fullname)
11wb.save()
12wb.close()
13# 退出excel程序,
14app.quit()
15# 通过杀掉进程强制Excel app退出
16# app.kill()
17# 
18# 以第一种方式创建Book时,打开文件的操作可如下
19wb = xw.Book('1.xlsx')
20
21app = xw.App(visible=False, add_book=False)
22app.display_alerts = False    # 关闭一些提示信息,可以加快运行速度。 默认为 True。
23app.screen_updating = False    # 更新显示工作表的内容。默认为 True。关闭它也可以提升运行速度。
24
25wb = app.books.open("./111.xlsx")
26ws = wb.sheets['ExportOrderList11954161104']

单元格写入

 1# 在A1单元格写入值
 2# 实例化一个工作表对象
 3sheet1 = wb.sheets["sheet1"]
 4# 或者
 5# sheet1 =xw.books['1.xlsx'].sheets['sheet1']
 6输出工作簿名称
 7# print(sheet1.name)
 8# 写入值
 9sheet1.range('A1').value = 'python知识学堂'
10# 读值并打印
11print('value of A1:',sheet1.range('A1').value)
12# 清空单元格内容,如果A1中是图片,此方法没有效果
13sheet1.range('A1').clear()
14# 传入列表写入多行值
15sheet1.range('A1').value = [['a','b','c'],[1,2,3]]
16
17# 当然也可以将pandas的DataFrame数据写入
18import pandas as pd
19df = pd.DataFrame([[1,2], [3,4]], columns=['A', 'B'])
20sheet1.range('A1').value = df
21# 读取数据,输出类型为DataFrame
22sheet1.range('A1').options(pd.DataFrame, expand='table').value

单元格读取

 1# 读取全部行列
 2max_row, max_col = sht.used_range.last_cell.row, sht.used_range.last_cell.column
 3lst = sht.range((1,1), (max_row, max_col)).value
 4
 5rng = sht.range('A1:D3')
 6for cell in rng:
 7    print(cell.value)
 8
 9# 读取行, 列(0起始)
10rng = sht[2:5, :3]
11for cell in rng:
12    print(cell.value)

单元格设置

1"""设置单元格大小"""
2ws.autofit()                #在整个工作表上自动调整宽度,可传参数
3ws.autofit(axis='c')        # 在整个工作表上自动调整列的宽度
4ws.autofit(axis='r')        # 在整个工作表上自动调整行的宽度
5ws.autofit('c')        # 在整个工作表上自动调整列的宽度
6ws.autofit('r')        # 在整个工作表上自动调整行的宽度
7ws.range(1,4).column_width = 5    # 设置第4列 列宽。(1,4)为第1行第4列的单元格
8ws.range(1,4).row_height = 20     # 设置第1行 行高

边框线

 1b3 = ws.range('b3')
 2
 3# Borders(9) 底部边框,LineStyle = 1 直线。
 4b3.api.Borders(9).LineStyle = 1
 5b3.api.Borders(9).Weight = 3                # 设置边框粗细。
 6
 7# Borders(7) 左边框,LineStyle = 2 虚线。
 8b3.api.Borders(7).LineStyle = 2
 9b3.api.Borders(7).Weight = 3
10
11# Borders(8) 顶部框,LineStyle = 5 双点划线。
12b3.api.Borders(8).LineStyle = 5
13b3.api.Borders(8).Weight = 3
14
15# Borders(10) 右边框,LineStyle = 4 点划线。
16b3.api.Borders(10).LineStyle = 4
17b3.api.Borders(10).Weight = 3
18
19# Borders(5) 单元格内从左上角 到 右下角。
20b3.api.Borders(5).LineStyle = 1
21b3.api.Borders(5).Weight = 3
22
23# Borders(6) 单元格内从左下角 到 右上角。
24b3.api.Borders(6).LineStyle = 1
25b3.api.Borders(6).Weight = 3
26
27"""如果是一个区域的单元格,内部边框设置如下"""
28# Borders(11) 内部垂直边线。
29b3.api.Borders(11).LineStyle = 1
30b3.api.Borders(11).Weight = 3
31
32# Borders(12) 内部水平边线。
33b3.api.Borders(12).LineStyle = 1
34b3.api.Borders(12).Weight = 3

使用公式

1# 使用公式
2ws.range('AB2').formula='=SUM(A1,A2)'

基础代码

 1# coding=utf-8
 2import xlwings as xw
 3# 设置程序不可见运行
 4app = xw.App(visible=False, add_book=False)
 5
 6# ===============  第一部分,创建并写入数据 =====================
 7# 创建一个test2.xlsx表,并写入数据
 8# wb = app.books.add()
 9# ws = wb.sheets.active
10# arr = []
11# for col in range(1,4):
12#     arr_temp = []
13#     for row in range(1,4):
14#         arr_temp.append(col*10+row)
15#     arr.append(arr_temp)
16# ws.range('A1:B3').value=arr
17# wb.save('data/test2.xlsx')
18# wb.close()
19# app.quit()
20# exit()
21
22# ============== 第二部分,插入、删除行和列 ========================
23
24# 导入已存的demo表格
25load_wb = app.books.open('data/test2.xlsx')
26# # 打开活动的工作薄的活动工作簿,或者指定的工作簿
27load_ws = load_wb.sheets.active
28# load_ws = load_wb.sheets['Sheet']
29
30# 获取总行数(存在数据)
31rows = load_ws.api.UsedRange.Rows.count
32cols = load_ws.api.UsedRange.Columns.count
33# print('该表格总共有:'+str(rows)+' 行')
34# print('该表格总共有:'+str(cols)+' 列')
35# exit()
36
37
38# 1-①在第二行前插入2行(可理解为: 在第2-4行插入空白行)
39# load_ws.api.rows('2:4').insert
40# 1-②删除第2-4行
41# load_ws.api.rows('2:4').delete
42# 2-①在第二列前插入2列(这里处理的不是很好,其实是增加了对应区域的单元格,并未直接增加列)
43# load_ws.range('B1:C'+str(cols)).api.insert
44# 2-②删除第2-4列
45# load_ws.range('B1:C'+str(cols)).api.delete
46
47# ============== 第三部分,修改指定单元格的值 ========================
48# load_ws.range('A1').value = 'x11'
49
50# ============== 第四部分,合并单元格 ========================
51# load_ws.range('A1:A2').api.merge
52
53# ============== 第五部分,获取单元格横纵坐标index ========================
54rng=xw.Range('B2')
55# 返回当前格子的行值
56# print(rng.row)
57# 返回当前格子的列值
58# print(rng.column)
59# 返回和设置当前格子的高度和宽度
60print(rng.width)
61print(rng.height)
62rng.row_height=40
63rng.column_width=50
64# 指定单元格的高度和宽度自适应
65# rng.columns.autofit()
66rng.rows.autofit()
67print(rng.width)
68print(rng.height)
69# load_ws.range('A1:A2').api.height = 20
70
71
72# ============== 第六部分,其它 ========================
73# lst=load_ws.range('A1:A'+str(load_ws['A1048576'].end('up').row)).value #把excel单列值读取到列表中
74# lst1=load_ws.range('A1:C'+str(load_ws['A1048576'].end('up').row)).value # 把excel连续两个列的值读取到列表中
75# lst=load_ws.range('A1:A'+str(load_ws['A1048576'].end('up').row)).value #A列的值
76# lst2=load_ws.range('C1:C'+str(load_ws['A1048576'].end('up').row)).value#C列的值
77# lst3=list(zip(lst,lst2))#合并起来然后转为列表
78# dicta=dict(lst3)#列表转为字典
79
80# ============== 第七部分,Office操作文档 ========================
81# https://docs.microsoft.com/en-us/office/vba/api/excel.range(object)
82
83
84
85load_wb.save()
86load_wb.close()
87app.quit()

待续……

Python Decorator

Python Decorator

普通函数装饰器

函数接收一个 函数名 作为参数 内部定义一个函数, 接收参数, 然后 内部函数内部 执行接收的函数名 最后外部函数返回内部函数

def loger(fun):
    def show(*args, **kwargs):
        print("记录日志->执行前")
        fun(*args, **kwargs)
        print("记录日志->执行后")
    return show


@loger
def xiaoming():
    print("function is running......")


@loger
def jack():
    print("function is running......")


xiaoming()
jack()
print("---" * 30)

可接收参数的普通函数装饰器

在不接受参数的装饰器基础上, 外面增加一层函数, 接收参数

def say_hello(contry):
    def loger(fun):
        def show(*args, **kwargs):
            if contry == 'china':
                print('中国')
            elif contry == 'english':
                print('English')
            print("记录日志->执行前")
            fun(*args, **kwargs)
            print("记录日志->执行后")
        return show
    return loger


@say_hello('china')
def xiaoming():
    print("function is running......")


@say_hello('english')
def jack():
    print("function is running......")


xiaoming()
jack()
print("---" * 30)

普通类装饰器

init 接收被装饰的函数名 call 接收参数

class Loger(object):

    def __init__(self, fun):
        self.fun = fun

    def __call__(self, *args, **kwargs):
        print("before fun run")
        self.fun(*args, **kwargs)
        print("after fun run")


@Loger
def xiaoming():
    print("function is running......")


@Loger
def jack():
    print("function is running......")


xiaoming()
jack()
print("---" * 30)

可接收参数的类装饰器

init 接收参数 call 接收被装饰的函数名, 内部定义一个函数接收参数, 并执行外部接收的函数名

class SLoger(object):

    def __init__(self, contry):
        self.contry = contry

    def __call__(self, fun):
        def show(*args, **kwargs):
            if self.contry == 'china':
                print("中国")
            elif self.contry == 'english':
                print("English")

            print("before fun run")
            fun(*args, **kwargs)
            print("after fun run")
        return show


@SLoger('china')
def xiaoming():
    print("function is running......")


@SLoger('english')
def jack():
    print("function is running......")


xiaoming()
jack()
print("---" * 30)

Jupyter Notebook

Jupyter Notebook / jupyterlab

Linux服务器上搭建jupyter notebook / jupyterlab

安装基础软件

1pip install ipython jupyter
2pip install jupyterlab

生成配置文件

jupyter notebook --generate-config Writing default config to: /root/.jupyter/jupyter_notebook_config.py

jupyter lab --generate-config

生成秘钥

1# ipython
2In [1]: from notebook.auth import passwd
3In [2]: passwd()
4Enter password:
5Out[2]: 'argon2:$argon2id$v=19$m=10240,t=10,p=8$Sunk/A1dg/SA'

编辑配置文件

c.NotebookApp.ip = '*'  # 对外提供访问的ip
c.NotebookApp.port = 8888 # 对外提供访问的端口
c.NotebookApp.open_browser = False # 启动不打开浏览器
c.NotebookApp.password = 'sha1:f8b5f5dbeca8:d1f5b93d5e787e4bf1bf4ad2c48c177ba79f55dd'  # 上面生成的秘钥
c.NotebookApp.notebook_dir = '/root/jupyter_dir' # 设置jupyter启动后默认文件夹
c.NotebookApp.allow_root = True  # 允许root用户执行

插件安装

pip install jupyter_contrib_nbextensions
jupyter contrib nbextension install --user
pip install jupyter_nbextensions_configurator
jupyter nbextensions_configurator enable --user

pip install jupyterthemes
jt -l  # 列出可选的主题

# -f(字体)  -fs(字体大小) -cellw(占屏比或宽度)  -ofs(输出段的字号)  -T(显示工具栏)  -N(显示自己主机名)
jt -t monokai -f fira -fs 9 -ofs 9 -dfs 9 -T -N

后台运行

nohup jupyter notebook &>./jupyter.log & nohup jupyter lab --allow-root &>./jupyter.log &

重启脚本

rejn(){ 
        pid=$(ps aux | grep jupyter-notebook | grep -v 'grep' | awk '{print $2}')
        kill -9 ${pid}                             
        nohup jupyter notebook &>./jupyter.log &   
}       
        
        
rejl(){ 
        pid=$(ps aux | grep jupyter-lab | grep -v 'grep' | awk '{print $2}')
        kill -9 ${pid}                             
        nohup jupyter lab --allow-root &>./jupyterlab.log &
} 

Arrow_api

Arrow_api

安装

pip install arrow

引入

import arrow

获取时间, 及各个字段值

now = arrow.now()
print(now)
print(now.year, now.month, now.day, now.hour, now.minute, now.second, now.microsecond)
print(now.tzinfo, now.fold, now.timestamp)
print('-'*12)
print(now.format())
print(now.format('YYYY-MM-DD HH:mm:ss'))
print('-'*12)

utc时间

utcnow = arrow.utcnow()
print(utcnow)
print('-'*12)

字符串转时间

t = arrow.get("2020-10-11 12:34:45", "YYYY-MM-DD HH:mm:ss")
print(t)
print('-'*12)

时间戳转时间

t = arrow.get(1604555923)
print(t)
print('-'*12)

指定时间

t = arrow.get(2020, 12, 23, 9, 10, 11)
print(t)
print('-'*12)

时间推移

years, months, days, hours, minutes, seconds, microseconds, weeks, quarters, weekday

t = arrow.now()
print(t)
print(t.replace(year=2011, hour=11))
t = arrow.now()
print(t)
print(t.shift(days=1))
print(t.shift(days=-1))
print('-'*12)

范围和跨度

print(arrow.now().span('hours'))
print(arrow.now().span('days'))

只获取两端

print(arrow.now().floor("days"))
print(arrow.now().ceil("days"))
print('-'*12)

指定时间段内指定间隔的所有时间点

b = arrow.now().shift(days=-2).datetime
e = arrow.now().shift(days=+2).datetime
for item in arrow.now().range('days', b, e):
    print(item, item.format('YYYY-MM-DD HH:mm:ss'))

笔记

Hugo 使用 docsy 主题模板搭建站点

使用Hugo的主题模板 docsy 搭建自己的文档站点, 支持API文档,博客等展示模式

关于docsy主题模板

docsy主题非常适合用于开源项目,支持文档和博客。

Docsy是一个文件式的网站,提供了使用者一些样板以及文件指南,能良好的支持技术文件发布。

Docsy是由Hugo等开源工具打造而成,结合Google的开源文件创建经验,提供方便的工具,帮助使用者快速建立开源项目文件网站。

配置基础环境

 1# 配置hugo extend 环境
 2wget https://github.com/gohugoio/hugo/releases/download/v0.117.0/hugo_extended_0.117.0_linux-amd64.tar.gz
 3tar -zxvf hugo_extended_0.117.0_linux-amd64.tar.gz
 4cd hugo_extended_0.117.0_linux-amd64
 5cp hugo /usr/bin/hugo
 6
 7
 8wget https://nodejs.org/dist/v20.5.1/node-v20.5.1-linux-x64.tar.xz
 9tar xvf node-v20.5.1-linux-x64.tar.xz
10cd node-v20.5.1-linux-x64
11# 配置node环境
12echo "PATH='path-to-node-v20.5.1-linux-x64/bin:$PATH'" >> ~/.bash_profile

使用docsy模板

1git clone --depth 1 https://github.com/google/docsy-example.git  website
2cd website
3npm install postcss postcss-cli autoprefixer

Chrome 禁止 Http 转换 Https

使用Chrome访问网站时, 禁止网址自动从Http转换Https访问

Chrome浏览器中会自动转换网址从http到https,启用安全访问
但是, 有时候我们不需要它强制转换, 如: 证书失效…..

此时在chrome地址栏输入 chrome://net-internals/#hsts
打开的页面中 左侧选择 Domain Security Policy 然后右侧找到 Query HSTS/PKP domain
在下面的输入框中输入要访问的域名, 可以查询是否该域名是否会自动转换http->https

想要取消自动转换, 则同页面最底部找到Delete domain security policies
在其下的文本框中输入 不想转换http->https的域名提交

这样再次访问该域名时, 就不会自动添加https了

Redis键空间事件通知

Redis键空间事件通知

Redis键空间事件通知

从Redis 2.8.0 开始 键空间通知允许客户端订阅发布/订阅信道来接收以某种方式影响Redis数据集的事件
由于Redis的发布/订阅当前是发后即忘模式的,因此如果你的应用需要可靠的事件通知,则无法满足,也就是说,
如果你的发布/订阅客户端断开连接并在稍后重连,客户端断开的这段时间内的所有事件通知都会丢失。

空间事件通知

键空间通知被实现成对每个影响Redis数据集的操作发送两个不同类型的事件。例如,一个在0号数据库中对名称为mykey的键执行DEL操作将触发推送两条消息,
相当于执行了下面两条PUBLISH命令:

PUBLISH keyspace@0:mykey del
PUBLISH keyevent@0:del mykey

很容易看出一个信道可以监听所有针对键mykey的事件,另一个信道允许获取对所有键执行删除操作的信息。
第一类事件,以keyspace为前缀的信道被称为键-空间通知,
第二类事件,以keyevent为前缀的信道被称为键-事件通知。

Redis配置

默认情况下,键空间事件通知是被禁用的,因为这个功能会消耗一些CPU,默认打开是不明智的。可以在redis.conf文件中使用notify-keyspace-events或CONFIG SET命令启用它。

参数:

K 键空间事件,以__keyspace@__为前缀发布消息
E 键事件事件,以__keyevent@__为前缀发布消息
g 通用命令(非特定类型),例如 DEL、 EXPIRE、 RENAME等
$ 字符串命令
l 列表命令
s 集合命令
h 哈希命令
z 有序集合命令
x 键过期事件(每次当一个键过期时生成的事件)
e 键淘汰事件(当一个键由于内存超量导致被淘汰时生成的事件)
A 参数g$lshzxe的别名,因此"AKE"字符串表示所有的事件

K或E至少有一个应该出现在参数字符串中,否则,无论字符串的其他部分是什么,都不会推送事件。 例如,为了只针对列表开启键-空间事件,配置参数必须设置为Kl,以此类推。 字符串KEA可以用来开启任何可能的事件。

事件列表

DEL 命令会对每一个被删除的键生成一个del event。
RENAME 命令会生成两个事件,对源键生成一个rename_from事件,对目标键生成一个rename_to事件。
EXPIRE 命令在对一个键设置过期时间时生成一个expire event,或在每次使用正数时间对一个键设置过期时间后导致键因过期被删除时生成一个expired event(查看EXPIRE的文档来获取更多信息)。
SORT 命令在使用STORE设置一个新建时会生成一个sortstore event。如果结果列表为空,并使用了STORE选项,且相同的键名已经存在,结果就是这个键被删除,因此这种情况下会生成一个del event。
SET和它的左右变种(SETEX、SETNX、GETSET)会生成set events。然而SETEX同时还会生成一个expire events。
MSET 会对每个键生成一个独立的set event。
SETRANGE 命令生成一个setrange event。
INCR、DECR、INCRBY、DECRBY 命令都会生成incrby events。
INCRBYFLOAT 命令会生成一个incrbyfloat events。
APPEND 命令会生成一个append event。
LPUSH和LPUSHX 命令会生成一个单一的lpush event,即使是在复杂情况下。
RPUSH和RPUSHX 命令会生成一个单一的rpush event,即使是在复杂情况下。
RPOP 命令会生成一个rpop event。如果列表中的最后一个元素被弹出,还会额外生成一个del event。
LPOP 命令会生成一个lpop event。如果列表中的第一个元素被弹出,还会额外生成一个del event。
LINSERT 命令会生成一个linsert event。
LSET 命令会生成一个lset event。
LREM 命令会生成一个lrem event,如果结果列表为空且键被删除将额外生成一个del event。
LTRIM 命令会生成一个ltrim event,如果结果列表为空且键被删除将额外生成一个del event。
RPOPLPUSH和BRPOPLPUSH 命令会生成一个rpop event和一个lpush event。在这两种情况下,顺序都是有保证的(lpush event将总是在rpop event之后被推送)。如果结果列表长度为0且键被删除将额外生成一个del event。
HSET、HSETNX和HMSET 都会生成一个单一的hset event。
HINCRBY 命令会生成一个hincrby event。
HINCRBYFLOAT 命令会生成一个hincrbyfloat event。
HDEL 命令会生成一个单一的hdel event,如果结果哈希为空且键被删除将额外生成一个del event。
SADD 命令会生成一个单一的sadd event,即使是在复杂情况下。
SREM 命令会生成一个单一的srem event,如果结果集合为空且键被删除将额外生成一个del event。
SMOVE 命令会对源键生成一个srem event,且对目标键生成一个sadd event。
SPOP 命令会生成一个spop event,如果结果集合为空且键被删除将额外生成一个del event。
SINTERSTORE、SUNIONSTORE、SDIFFSTORE 会分别生成sinterstore event、sunionostore event、sdiffstore event。在集合为空且被存储的键已经存在的特殊情况下,由于key会被删除会生成一个del event。
ZINCR 命令会生成一个zincr event。
ZADD 命令会生成一个单一的zadd event,即使有多个元素一次性被添加。
ZREM 命令会生成一个的那一的zrem event,即使有多个元素一次性被删除。当结果有序集合为空且键被删除,会生成一个额外的del event。
ZREMBYSCORE 命令会生成一个单一的zrembyscore event。当结果有序集合为空且键被删除,会生成一个额外的del event。
ZREMBYRANK 命令会生成一个单一的zrembyrank event。当结果有序集合为空且键被删除,会生成一个额外的del event。
ZINTERSTORE和ZUNIONSTORE 会分别生成zinterstore event和zunionstore event。在有序集合为空且被存储的键已经存在的特殊情况下,由于key会被删除会生成一个del event。
每次由于键的过期时间到导致键被从数据集中删除时,会生成一个expired event。
每次由于Redis超过最大内存限制 ,使用maxmemory policy释放内存导致一个键从数据集中被淘汰时,会生成一个evicted event。

** 只有在目标键真正被修改时,所有命令才会生成事件。例如一个SREM命令从一个集合中删除了一个不存在的元素,这实际上不会对键造成改变,因此不会生成任何事件。 **

测试用例:

redis-cli config set notify-keyspace-events KA
redis-cli psubscribe '__keyspace*'

过期事件

有生存时间的键在Redis中过期有两种方式:

当键被一个命令访问且发现键已过期。
通过在后台系统中运行定时任务增量地查找过期键,这样能够收集到那些从未被访问键。

当一个键被访问且被上述两种方法之一发现已过期时会生成expired events,这就会导致一个结果,Redis服务器将无法保证在键的生存时间变为0时立即生成expired events。
如果没有命令不断地访问键,且有很多的键被设置了生存时间,则在键的生存时间下降到0和生成expired events这之间会有一个显著的延迟。
基本上来说,Redis服务器是在删除过期键时,而不是在键的生存时间理论上变为0时生成expired events。