Python3正则使用\w却能匹配中文问题

# 正则中\w等同于[A-Za-z0-9_],但是由于Python3的re库默认使用的是Unicode字符集,导致也能匹配中文
# 通过指定匹配ASCII字符即可解决问题
import re
pattern = re.compile(r'\w+', re.ASCII) # 使用ASCII标志
# pattern = re.compile(r'\w+', re.A) # 使用ASCII标志
text = "hello_世界123"
matches = pattern.findall(text)
print(matches)

re模块的多种标志(flags)说明:

  1. re.ASCII / re.A

    • 使 \w, \W, \b, \B, \d, \D, \s, 和 \S 只匹配ASCII字符,而不是匹配Unicode字符。
  2. re.IGNORECASE / re.I

    • 使匹配对大小写不敏感。例如,[A-Z] 也会匹配小写字母,[a-z] 也会匹配大写字母。
  3. re.MULTILINE / re.M

    • 多行模式。影响 ^$ 的行为。^ 匹配字符串的开始以及每行的开始(紧跟在每个换行符之后),$ 匹配字符串的结束以及每行的结束(紧跟在每个换行符之前)。
  4. re.DOTALL / re.S

    • 使 .(点号)匹配任何字符,包括换行符。默认情况下,. 不匹配换行符。
  5. re.VERBOSE / re.X

    • 详细模式。这允许你组织正则表达式,使其更易于阅读。在该模式下,空白字符被忽略,除非在字符类中或被转义,且#可用于引入注释。
  6. re.DEBUG

    • 打印关于编译表达式的调试信息。
  7. re.UNICODE / re.U

    • 使 \w, \W, \b, \B, \d, \D, \s, 和 \S 执行Unicode匹配而不是ASCII匹配。这是Python 3中的默认行为,因此通常不需要显式设置。

也可以组合使用,例如:re.I | re.M

  1. SSH禁用密码登录,修改端口

    # 复制公钥到服务器
    vi ~/.ssh/authorized_keys
    # 修改sshd配置文件
    Port 1234
    PermitRootLogin prohibit-password
    PubkeyAuthentication yes
    PasswordAuthentication no
    ChallengeResponseAuthentication no
    # 重启ssh服务
    systemctl restart ssh
    service ssh restart
  2. 同步Git公钥

    # 生成SSH密钥对
    ssh-keygen -t rsa -b 4096 -C "****@gmail.com"
    # 将SSH公钥添加到Git服务
    cat ~/.ssh/id_rsa.pub
  3. 安装Docker

    Debian install docker

原理:通过解码V2ray原服务器配置,使用GcoreCDN的IP替换原域名

  1. CloudFlare先配置域名DNS Record,CNAME类型
  2. 使用配置域名的服务器生成V2ray服务器配置,vmess协议,格式如:vmess://字符串
  3. 通过对服务器配置的字符串进行解码,解密出JSON字符串
  4. 获取GcoreCDN的IP,同时对IP进行Ping处理,过滤无法访问的IP,也可以对IP的443端口进行访问,判断是否有响应
  5. 用能够联通的IP替换JSON字符串中的地址,在进行编码后加上协议生成新的V2ray服务器配置

Python代码示例:

# -*- coding:utf-8 -*-
import base64
import copy
import json
from concurrent.futures import ThreadPoolExecutor

import requests
from multiping import MultiPing

ORIGINAL_CONFIG = "vmess://字符串"

ALL_CONFIG = []
IP_URL = "https://api.gcore.com/cdn/public-ip-list"
ORIGINAL_CONFIG_DECODE = json.loads(base64.b64decode(ORIGINAL_CONFIG).decode('utf-8'))
CONFIG_FILE = open('config.txt', 'w+', encoding='utf-8')


def get_request():
    request = requests.Session()
    request.trust_env = False
    return request


def get_ip_list():
    response = get_request().get(IP_URL, verify=False)
    if response.status_code == 200:
        response_body = response.json()
        return [ip.replace('/32', '') for ip in response_body.get("addresses", [])]
    else:
        return []


def do(ip):
    config = copy.deepcopy(ORIGINAL_CONFIG_DECODE)
    config["add"] = ip
    CONFIG_FILE.write(f"vmess://{base64.b64encode(json.dumps(config).encode()).decode('utf-8')}\r")


with ThreadPoolExecutor(max_workers=10) as executor:
    mp = MultiPing(get_ip_list())
    mp.send()
    responses, no_responses = mp.receive(1)
    executor.map(do, responses.keys())
CONFIG_FILE.close()

  1. 启动后发现datenode节点无法启动,All specified directories have failed to load

    解决方法:
    修改datenode报错节点中路径的VERSION,改为日志中的clusterID

从特定时间开始按时间戳生成唯一字符串

  • 常规字符串a-z,A-Z,0-9一共62个字符串设置为字典
  • 将当前时间与特定时间的时间差,转为时间戳后生成一个62位字符串

    def timestampto62():
        timestamp_flag = 0 # 特定时间
        timestamp = int(datetime.now().timestamp() * 10 ** 6) -timestamp_flag
        characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        result = ""
        if timestamp == 0:
            return characters[0]
        while timestamp > 0:
            remainder = timestamp % 62
            result = characters[remainder] + result
            timestamp //= 62
        return result

  1. 查看Pod镜像tag

    kubectl describe pod -n <namespace> <podname>
  1. 通过Dockerfile编写相同tag的镜像

    FROM <docker_image_name>:<docker_image_tag>
    ADD ./test.txt /opt/test.txt
    docker build . --tag=<docker_image_name>:<docker_image_tag>
  1. 通过K8s更新pod

    kubectl get pod  -n <namespace> <podname> -o yaml | kubectl replace --force -f -

  • 工具 ADB
  • 命令

    # 连接手机
    adb shell
    # 获取应用列表包名
    pm list package
    # 卸载软件
    pm uninstall -k --user 0 包名
    adb shell service call package 131 s16 包名 i32 0 i32 0   # Android 13
    adb shell service call package 134 s16 包名 i32 0 i32 0   # Android 12
    # 安装软件
    pm install-existing --user 0 包名
    adb shell service call package 131 s16 包名 i32 1 i32 0
    # 冻结软件
    pm suspend 包名
    pm disable-user --user 0 包名
    # 解冻软件
    pm unsuspend 包名

    https://www.xda-developers.com/disable-system-app-bloatware-android/

  • 系统版本 ColorOS12.1 IN2020_11_C.35可卸载软件

    com.heytap.pictorial # 乐划锁屏
    com.heytap.yoli # 视频
    com.heytap.music # 音乐
    com.heytap.browser # 浏览器
    com.baidu.input_oppo # 自带输入法
    com.nearme.instant.platform # 快应用
    com.android.stk # SIM卡工具箱
    com.coloros.phonemanager # 手机管家
    com.opos.ads # 系统广告
    com.heytap.mcs # Oppo推送系统
    com.coloros.accessibilityassistant # 语音字幕
    com.iflytek.speechsuite # 科大讯飞语音引擎
    com.heytap.quicksearchbox # 桌面下拉搜索功能
    com.coloros.smartdrive # 车联
    com.oplus.sos # SOS急救
    com.android.traceur # 应用跟踪记录,时长统计
    com.android.printspooler # 打印处理服务
    com.coloros.karaoke # K歌返听
    com.coloros.translate.engine # 翻译引擎
    com.coloros.smartsidebar # 智能边栏
    com.coloros.focusmode # 专注模式
    com.oplus.securitykeyboard # 安全键盘
    com.oplus.safecenter # 安全中心,禁用后自启动关联启动不可用 儿童空间不可用
    com.coloros.childrenspace # 儿童空间
    com.coloros.securityguard # 安全事件 手机管家-安全工具
    com.oplus.statistics.rom # 用户体验计划
    com.oplus.dmp # 融合搜索
    com.coloros.securepay # 安全支付
    com.coloros.oshare # 互传
    com.heytap.htms # 移动服务 钱包中账号登录会用到
    com.oplus.pay # 支付
    com.heytap.vip  # oppo账号无法使用
    com.heytap.cloud # 云服务
    com.coloros.directui # 小布识屏
    com.heytap.speechassist # 小布语音助手
    com.coloros.ocrscanner # 小布扫一扫
    com.coloros.colordirectservice # 小布识屏相关
    com.google.android.gms  # 谷歌服务
    com.google.android.gsf # 谷歌服务框架
    com.google.android.cellbroadcastservice # 谷歌套件
    com.google.android.onetimeinitializer # 谷歌套件
    com.oplus.ota #本地升级
    com.oplus.sau # 系统更新
    com.oplus.romupdate # 系统更新

开发过程中经常遇到要调试https协议的接口,用Django快速模拟一个https服务端
主要模块:django-sslserver
安装方式:pip install django-sslserver
配置:
# settings.py
SECURE_SSL_REDIRECT = False # False只响应HTTPS协议请求,Ture将http重定向至https
INSTALLED_APPS = (
        "sslserver",
                )
# 第一次启动获取certificate和key
python manage.py runsslserver
# 后续启动命令
python manage.py runsslserver --certificate development.crt --key development.key

class AESTextField(models.CharField):

    def value_to_string(self, obj):
        """序列化"""
        value = self.value_from_object(obj)
        return self.get_prep_value(value)

    def to_python(self, value):
        if value is not None:
            try:
                value = AES.new('key').decrypt(value)
            except Exception as e:
                logger.exception(f'密码解密失败:{e}')
        return value

    def from_db_value(self, value, expression, connection):
        """从数据库取出来的值"""
        if value is not None:
            try:
                value = AES.new('key').decrypt(value)
            except Exception as e:
                logger.exception(f'密码解密失败:{e}')
        return value

    def get_prep_value(self, value):
        if value is not None:
            try:
                value = AES.new('key').encrypt(value)
            except Exception as e:
                logger.exception(f'密码加密失败:{e}')
        return value

    def value_from_object(self, obj):
        return super().value_from_object(obj)

    def get_db_prep_value(self, value, connection, prepared=False):
        return super().get_db_prep_value(value, connection, prepared)

    def get_db_prep_save(self, value, connection):
        return super().get_db_prep_save(value, connection)

  • 在Docker Desktop中启用并自动安装K8s;建议提前配置镜像加速器

l1ug0aiy.png

  • 安装 Dashboard

    kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.1/aio/deploy/recommended.yaml
    • 若无法连接raw.githubusercontent.com

      • 下载 Dashboard仓库文件 aio/deploy/recommended.yaml
      • 找到l1ugl9o5.png
      • 拉取依赖镜像 docker pull kubernetesui/dashboard:v2.5.1
      • 执行kubectl create -f ./aio/deploy/recommended.yaml
  • 开启代理访问kubectl proxy
  • 创建登录用户,新建文件dashboard-adminuser.yaml
    写入

    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: admin-user
    namespace: kubernetes-dashboard
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
    name: admin-user
    roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: cluster-admin
  • kind: ServiceAccount
    name: admin-user
    namespace: kubernetes-dashboard

  • 获取登录Token

    kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get sa/admin-user -o jsonpath="{.secrets[0].name}") -o go-template="{{.data.token | base64decode}}"
  • 访问 登录页面 并填入Token登录
  • 删除登录账户

    kubectl -n kubernetes-dashboard delete serviceaccount admin-user
    kubectl -n kubernetes-dashboard delete clusterrolebinding admin-user

https://www.lqse.top/usr/uploads/2022/04/546809765.png

在子系统中获取Win10宿主机的IP
cat /etc/resolv.conf|grep nameserver|awk '{print $2}'

代理添加

vim ~/.bashrc

export hostip=$(cat /etc/resolv.conf|grep nameserver|awk '{print $2}')

alias proxy='
    export https_proxy="http://${hostip}:port";
    export http_proxy="http://${hostip}:port";'

alias unproxy='
    unset https_proxy;
    unset http_proxy;'

开放WSL网卡防火墙使子系统能够访问宿主机

New-NetFirewallRule -DisplayName "WSL" -Direction Inbound  -InterfaceAlias "vEthernet (WSL)"  -Action Allow

Hyper-V虚拟机使用宿主机代理

vim ~/.bashrc

export hostip=$(cat /etc/network/interfaces|grep gateway| awk '{print $2}')

alias proxy='
    export https_proxy="http://${hostip}:port";
    export http_proxy="http://${hostip}:port";'

alias unproxy='
    unset https_proxy;
    unset http_proxy;'

服务端

使用 spyne 模块

import logging

from spyne import Application, rpc, ServiceBase, String, Integer, ComplexModel, Long
from spyne.protocol.soap import Soap11
from spyne.protocol.xml import XmlDocument

TNS = 'TNS'
_CUSTOMIZE = {"min_occurs": 1, "nullable": False}


class Int(Integer):
    __type_name__ = 'int'


PARAM = (
    String.customize(encoding='utf-8', **_CUSTOMIZE),
    Int.customize(**_CUSTOMIZE),
    Long.customize(**_CUSTOMIZE)
)

# class RequestParam(ComplexModel):
#     __namespace__ = TNS
#     name = String.customize(encoding='utf-8', **_CUSTOMIZE),
#     age = Int.customize(**_CUSTOMIZE)
#     id_crd = Long.customize(**_CUSTOMIZE)


RESPONSE = [
    Integer.customize(**_CUSTOMIZE),
    String.customize(encoding='utf-8', **_CUSTOMIZE)
]


class WebService(ServiceBase):
    @rpc(*PARAM,
         _returns=RESPONSE,
         _out_message_name='return',
         _out_variable_names=["code", 'msg'])
    def user_info(self, name, age, id_crd):
        print(f'name:{name},age:{age},id_crd:{id_crd}')
        return 0, 'OK'  # code, msg


def remove_response_namespace(ctx):
    # 取消返回xml里面的namespace
    namespace = f' xmlns:ns0="{TNS}"'
    ctx.out_string[0] = ctx.out_string[0].replace(b'ns0:', b'')
    ctx.out_string[0] = ctx.out_string[0].replace(namespace.encode('utf-8'), b'')


# 加入事件管理器
WebService.event_manager.add_listener('method_return_string', remove_response_namespace)

application = Application([WebService],
                          tns=TNS,
                          in_protocol=Soap11(validator='soft'),
                          out_protocol=XmlDocument())
if __name__ == '__main__':
    from spyne.server.wsgi import WsgiApplication
    from wsgiref.simple_server import make_server

    logging.basicConfig(level=logging.DEBUG)
    logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG)

    logging.info("listening to http://0.0.0.0:80")
    logging.info("wsdl is at: http://0.0.0.0:80?wsdl")

    wsgi_application = WsgiApplication(application)
    server = make_server('0.0.0.0', 80, wsgi_application)
    server.serve_forever()

可使用SoapUI软件发送请求

客户端

使用 zeep 模块;4.0.0版本后支持异步

from xml.dom import minidom

from zeep import Client, Settings
import urllib3
from requests import Session

urllib3.disable_warnings()
session = Session()
session.verify = False
soap_settings = Settings(raw_response=True)
client = Client('http://localhost:80/?wsdl', settings=soap_settings)
client.transport.session.verify = False


def parse_response(response_content):
    root = minidom.parseString(response_content)
    element = root.documentElement
    code_element = element.getElementsByTagName('code')
    msg_element = element.getElementsByTagName('msg')
    if code_element and msg_element:
        code = code_element[0].firstChild.data
        msg = msg_element[0].firstChild.data
        return int(code), msg
    return None, None


response = client.service.user_info(**{"name": 'wenxi',
                                       "age": 25,
                                       "id_crd": 123456789012345678
                                       })
print(response.status_code)
content = response.content.decode()
code, msg = parse_response(content)
print(code, msg)

import zipfile
from io import BytesIO


def zip_file(byte_file):
    buf = BytesIO()
    with zipfile.ZipFile(buf, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
        zf.writestr('result', byte_file)
    file = buf.getvalue()
    buf.close()
    return file


def unzip_file(byte_file):
    buf = BytesIO()
    buf.write(byte_file)
    zipfile_obj = zipfile.ZipFile(buf, compression=zipfile.ZIP_DEFLATED)
    file = zipfile_obj.read(zipfile_obj.namelist()[0])
    buf.close()
    zipfile_obj.close()
    return file

from Crypto.Cipher import AES

BLOCK_SIZE = AES.block_size


class AESCipher:

    def __init__(self, key, iv):
        try:
            key = bytes.fromhex(key)
        except:
            key = bytes(key, encoding='utf-8')
        iv = bytes(iv[0:16], encoding='utf-8')
        self.cipher = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)

    @staticmethod
    def pad(b):
        return b + (BLOCK_SIZE - len(b) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(b) % BLOCK_SIZE).encode()

    @staticmethod
    def unpad(b):
        return b[:-ord(b[len(b) - 1:])]

    def encrypt(self, text):
        text = self.pad(text)
        encrypted_text = self.cipher.encrypt(text)
        return encrypted_text

    def decrypt(self, encrypted_text):
        decrypted_text = self.cipher.decrypt(encrypted_text)
        return self.unpad(decrypted_text)

# 撤销本地commit
git reset HEAD~

# 撤销刚刚的push(会覆盖别人提交的代码)
git reset --soft HEAD~1
git push origin <分支名> --force
# ssh 错误:no matching cipher found. Their offer: aes128-cbc
# 在ssh config中添加行Ciphers +aes128-cbc
Ciphers +aes128-cbc,aes256-cbc,3des-cbc

Superspeed

bash <(curl -Lso- https://git.io/superspeed)

superbench

wget -qO- --no-check-certificate https://raw.githubusercontent.com/oooldking/script/master/superbench.sh | bash

bench.sh

wget -qO- bench.sh | bash

mPing

wget https://raw.githubusercontent.com/helloxz/mping/master/mping.sh
bash mping.sh

过滤Celery定时任务已完成和未完成的任务

from django_celery_beat.models import PeriodicTask
from django_filters import rest_framework as filters


class PeriodicTaskFilter(filters.FilterSet):
    completed = filters.BooleanFilter(method='filter_completed')

    class Meta:
        model = PeriodicTask
        fields = ['completed']

    @staticmethod
    def filter_completed(queryset, name, value):
        if value:
            return queryset.filter(last_run_at__isnull=False)
        else:
            return queryset.filter(last_run_at__isnull=True)

import json

import pytz
from django_celery_beat.models import PeriodicTask, PeriodicTasks, CrontabSchedule

from phone.models import PhoneInfo


def task_add(task_name, task_class, task_queue, interval=None, crontab=None, args=None, kwargs=None):
    """
    添加celery任务
    :param kwargs:  默认'{}'
    :param args:    默认'[]'
    :param task_name: 任务名
    :param task_class: 任务代码
    :param task_queue: 任务管道
    :param interval: 定时类型
    :param crontab: 定时类型
    :return: 任务id
    """
    if args is None:
        args = []
    if kwargs is None:
        kwargs = {}
    task = PeriodicTask.objects.create(name=task_name, task=task_class, interval=interval, crontab=crontab)
    task.queue = task_queue
    task.exchange = task_queue
    task.routing_key = 'default'
    task.enabled = True
    task.args = json.dumps(args)
    task.kwargs = json.dumps(kwargs)
    task.save()
    PeriodicTasks.changed(task)
    return task.id


def task_update(task_id, crontab):
    """
    修改任务
    :param task_id: 需要修改的任务的id
    :param crontab: 定时类型
    :return:
    """
    per_task = PeriodicTask.objects.get(id=task_id)
    per_task.crontab = crontab
    per_task.save()
    PeriodicTasks.changed(per_task)


def task_delete(task_id):
    """
    删除任务
    :param task_id:
    :return:
    """
    try:
        task_query = PeriodicTask.objects.get(id=task_id)
    except PeriodicTask.DoesNotExist:
        print(f'{task_id}ID 不存在')
    else:
        task_query.enabled = False
        task_query.save()
        # 删除任务
        task_query.delete()
    return


def task_list(task_name, task_queue):
    """
    任务查询
    :param task_name: 任务名称
    :param task_queue: 任务队列
    :return: task_name任务名称、task_queue任务队列、task_args任务参数、task_class任务执行类、task_cron任务定时的表达式
    """
    # 查询目前满足条件的所有周期性任务
    per_task = PeriodicTask.objects.get(name=task_name, queue=task_queue)
    data = {
        "task_name": per_task.name,
        "task_queue": per_task.queue,
        "task_kwargs": per_task.kwargs,
        "task_class": per_task.task,
        "task_cron": per_task.crontab,
    }
    return data


def queue_update(queue_name_pre, queue_name_cur):
    """
    更改任务的队列
    :param queue_name_pre: 要改的队列名称
    :param queue_name_cur: 改变后的队列名
    :return:
    """
    all_tasks = PeriodicTask.objects.filter(queue=queue_name_pre)
    all_tasks_ids = [per_task.id for per_task in all_tasks]
    for task_id in all_tasks_ids:
        task_query = PeriodicTask.objects.get(id=task_id)
        task_query.queue = queue_name_cur
        task_query.exchange = queue_name_cur
        task_query.routing_key = queue_name_cur
        task_query.save()
    PeriodicTasks.update_changed()
    all_tasks = PeriodicTask.objects.filter(queue=queue_name_cur)
    return all_tasks


def get_cron_obj(plan_time):
    """获取定时时间类型"""
    cron_obj, flag = CrontabSchedule.objects.get_or_create(minute=plan_time.minute,
                                                           hour=plan_time.hour,
                                                           day_of_week='*',
                                                           day_of_month=plan_time.day,
                                                           month_of_year=plan_time.month,
                                                           timezone=pytz.timezone('Asia/Shanghai'))
    return cron_obj


class PlanTask(object):

    def __init__(self, model, instance):
        if model == "model0":
            # task_name, task_class, task_queue, interval = None, crontab = None, args = None, kwargs = None
            self.data = {"task_name": f'model0-计划{instance.pk}',
                         "task_class": "model0.tasks.model_0",
                         }
        elif model == "model1":
            # task_name, task_class, task_queue, interval = None, crontab = None, args = None, kwargs = None
            self.data = {"task_name": f'model1-计划{instance.pk}',
                         "task_class": "model1.tasks.model_1",
                         }
        else:
            pass
        self.data.update({"task_queue": "manager", "interval": None, "crontab": self.get_cron_obj(instance.plan_time),
                          "args": [instance.pk]})
        self.instance = instance

    @staticmethod
    def get_cron_obj(plan_time):
        """获取定时时间类型"""
        cron_obj, flag = CrontabSchedule.objects.get_or_create(minute=plan_time.minute,
                                                               hour=plan_time.hour,
                                                               day_of_week='*',
                                                               day_of_month=plan_time.day,
                                                               month_of_year=plan_time.month,
                                                               timezone=pytz.timezone('Asia/Shanghai'))
        return cron_obj

    def implement_task_add(self):
        """添加Celery计划"""
        task_id = task_add(**self.data)
        self.instance.task_id = task_id
        self.instance.save(update_fields=['task_id'])

    def implement_task_update(self, validated_data):
        """更新Celery计划"""
        if self.instance.is_enable:  # 已启用
            if self.instance.task_id is None:  # 未创建celery计划任务,创建任务
                self.implement_task_add()
            if self.instance.task_id and 'plan_time' in validated_data.keys():  # 已创建celery计划任务,需变更时间
                crontab = get_cron_obj(self.instance.plan_time)
                # 更新任务时间
                task_update(self.instance.task_id, crontab)
        else:  # 未启用
            if self.instance.task_id:  # 已存在计划任务,需删除计划任务
                task_delete(self.instance.task_id)
                self.instance.task_id = None
                self.instance.save(update_fields=['task_id'])


if __name__ == '__main__':
    instance = PhoneInfo.objects.first()
    validated_data = {"plan_time": "2020-02-25T16:23:26.091538+08:00"}
    # 添加计划
    PlanTask(model='model1', instance=instance).implement_task_add()
    # 修改计划
    PlanTask(model='model1', instance=instance).implement_task_update(validated_data)
    # 删除计划
    task_delete(instance.task_id)

pypi地址

CKEDITOR_IMAGE_BACKEND = "pillow" # 图片
# 上传文件夹
CKEDITOR_UPLOAD_PATH = 'upload/'
UPLOAD_DIR_NAME = 'upload'
UPLOAD_DIR = os.path.join(BASE_DIR, UPLOAD_DIR_NAME)  # 路径
if not os.path.exists(UPLOAD_DIR):
    os.mkdir(UPLOAD_DIR)

CKEDITOR_CONFIGS = {
    'default': {
        'language': 'zh-cn',
        'image_previewText': ' ',  # 替换上传图片时显示区域出现的字符串
        'tabSpaces': 8,
        'toolbar': (
            ['Source', 'Save', 'NewPage', 'Preview', 'Templates'],
            ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', 'Print', 'SpellChecker', 'Scayt'],
            ['Undo', 'Redo', 'Find', 'Replace', 'SelectAll', 'RemoveFormat'],
            ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'],
            ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript'],
            ['NumberedList', 'BulletedList', 'Outdent', 'Indent', 'Blockquote'],
            ['JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
            ['Link', 'Unlink', 'Anchor'],
            ['Image', 'Flash', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar', 'PageBreak'],
            ['Styles', 'Format', 'Font', 'FontSize'],
            ['TextColor', 'BGColor', 'lineheight'],
            ['Maximize', 'ShowBlocks', 'About', 'pbckcode'],
        ),
        'extraPlugins': ','.join(['lineheight'])
    }
}

给插件添加行距

Ckeditor的文件夹修改其配置文件config.js并保存为utf-8格式

/**
 * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see https://ckeditor.com/legal/ckeditor-oss-license
 */

CKEDITOR.editorConfig = function( config ) {
    // Define changes to default configuration here. For example:
    // config.language = 'fr';
    // config.uiColor = '#AADC6E';
    config.extraPlugins += (config.extraPlugins ? ',lineheight' : 'lineheight');    //添加行距插件
    config.font_names='宋体/宋体;仿宋/仿宋;微软雅黑/微软雅黑;楷体/楷体;黑体/黑体;'+ config.font_names;    //字体添加
};

plugins文件夹下解压放入行距插件文件夹

  1. Supervisor官网
  2. 安装pip install supervisor
  3. 配置

    • 生成默认配置echo_supervisord_conf > /etc/supervisord.conf
    • 自定义配置
    ;django-channels配置
    [fcgi-program:my_channels]
    socket = tcp://0.0.0.0:2020
    directory = /home/my_channels
    numprocs = 8
    process_name = my_channels_2020-%(process_num)d
    command = /root/.virtualenvs/my_channels/bin/daphne -u /home/my_channels/runtime/my_channels_2020-%(process_num)d.sock --fd 0 --access-log - --proxy-headers my_channels.asgi:application
    autostart = true
    autorestart = true
    stdout_logfile = /home/my_channels/logging/my_channels.log
    stdout_logfile_maxbytes = 50MB
    stdout_logfile_backups = 10
    redirect_stderr = true
    priority = 997
    user = root
    killasgroup = true
    stopasgroup = true
    startsecs = 15
    ;CeleryWorker配置
    [program:celery-worker-my_channels]
    command = /root/.virtualenvs/my_channels/bin/celery -A my_channels worker -l info -Q default,manager
    directory = /home/my_channels
    stdout_logfile = /home/my_channels/logging/celery-worker-my_channels.log
    stdout_logfile_maxbytes = 50MB
    stdout_logfile_backups = 10
    stderr_logfile = /home/my_channels/logging/celery-worker-my_channels-error.log
    stderr_logfile_maxbytes = 50MB
    stderr_logfile_backups = 10
    autostart = true
    autorestart = true
    priority = 997
    user = root
    killasgroup = true
    stopasgroup = true
    redirect_stderr = true
    startsecs = 15
    ;Celery定时任务配置
    [program:celery-beat-my_channels]
    command = /root/.virtualenvs/my_channels/bin/celery -A my_channels beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
    directory = /home/my_channels
    stdout_logfile = /home/my_channels/logging/celery-beat-my_channels.log
    stdout_logfile_maxbytes = 50MB
    stdout_logfile_backups = 10
    stderr_logfile = /home/my_channels/logging/celery-beat-my_channels-error.log
    stderr_logfile_maxbytes = 50MB
    stderr_logfile_backups = 10
    autostart = true
    autorestart = true
    priority = 997
    user = root
    killasgroup = true
    stopasgroup = true
    redirect_stderr = true
    startsecs = 15

    启动命令supervisord -c /etc/supervisord.conf
    更新配置supervisorctl update

目的:修改APK文件的URL
环境:Java11
所需文件:https://pan.baidu.com/s/1KumNg7NoTZ5LmlypPybwfQ
提取码:bs8l

  • apk拆包

    命令:java -jar apktool.jar (-r) d 要拆的apk文件 -o 输出文件位置 -r可选

    如:C:\Users\admin>java -jar Desktop\apktool1\apktool_2.4.1.jar -r d Desktop\test.apk -o Desktop\test

    • 签名删除

      test\original\META-INF删除CERT.RSA,CERT.SF,MANIFEST.MF

  • apk打包

    命令:apktool.bat b 拆包文件夹 -o 输出apk名字.apk -o可选,不加在拆包文件夹下的dict找到apk

    如:C:\Users\admin\Desktop\apktool1>apktool.bat b ..\test -o test1.apk

  • 生成keystore

    使用Java的keystore.exe生成,位置在java安装位置\jdk-11.0.5\bin下

    命令:keytool -genkey -alias test.keystore -keyalg RSA -validity 20000 -keystore 存放test.keystore的位置(不要放在java文件夹中,会存在权限不足)

    如:C:\Program Files\Java\jdk-11.0.5\bin> keytool -genkey -alias test.keystore -keyalg RSA -validity 20000 -keystore C:\Users\admin\Desktop\test.keystore

  • 使用keystore对打包apk签名

    命令:jarsigner -verbose -keystore keystore文件 -signedjar 签名后存放apk文件.apk 要签名的apk 要使用的keystore

    如:C:\Program Files\Java\jdk-11.0.5\bin>jarsigner -verbose -keystore C:\Users\admin\Desktop\test.keystore -signedjar C:\Users\admin\Desktop\testapk_signed.apk C:\Users\admin\Desktop\test\dist\test.apk test.keystore

原网页

”Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design”. If you are building something that is similar to a e-commerce site, then you should probably go with Django. It will get your work done quick. You don’t have to worry about too many technology choices. It provides everything thing you need from template engine to ORM. It will be slightly opinionated about the way you structure your app, which is good If you ask me. And it has the strongest community of all the other libraries, which means easy help is available.

”Flask is a microframework for Python based on Werkzeug, Jinja 2 and good intentions”. Beware - “microframework” may be misleading. This does not mean that Flask is a half-baked library. This mean the core of Flask is very, very simple. Unlike Django, It will not make any Technology decisions for you. You are free to choose any template engine or ORM that pleases you. Even though it comes with Jinja template engine by default, you are always free to choose our own. As far as I know Flask comes in handy for writing APIs endpoints(RESTful rervices).

”Twisted is an event-driven networking engine written in python”. This is a high-performance engine. The main reason for its speed is something called as deferred. Twisted is built on top of deferred. For those of you who don’t know about deferred, it is the mechanism through with asynchronous architecture is achieved. Twisted is very fast. But is not suitable for writing conventional WebApps. If you want to do something low-level networking stuff, Twisted is your friend.

”Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed. By using non-blocking network I/O, Tornado can scale to tens of thousands of open connections, making it ideal for long polling, WebSockets, and other applications that require a long-lived connection to each user”. Tornado stands some where between Django and Flask. If you want to write something with Django or Flask, but if you need a better performance, you can opt for Tornado. It can handle C10k problem very well if it is architected right.

”Cyclone is a web server framework for Python that implements the Tornado API as a Twisted protocol”. Now, what if you want something with Twisted’s performance and easy to write conventional webapps? Say hello to Cyclone. I would prefer Cyclone over Tornado. It has an API that is very similar to Tornado. As a matter of fact, this is a fork of Tornado. But the problem is it has relatively small community. Alexandre Fiori is the only main commiter to the repo.

”Pyramid is a general, open source, Python web application development framework. Its primary goal is to make it easier for a Python developer to create web applications”. I haven’t really used Pyramid, but I went through the documentation. From what I understand, Pyramid is very similar to Flask and I think you can use Pyramid wherever Flask seems appropriate and vice-versa.

  1. WebServer是监听端口,负责HTTP连接管理/数据收发/HTTP协议实现等底层上的处理.
  2. Web框架定义的是单个HTTP请求处理的流程.
  3. Nginx是反向代理服务器,是一个特殊的WebServer应用,和WebServer并不是同级的概念.Tornado既是WebServer又是Web框架,这两者并不矛盾。举例来说,你写了一个Tornado应用之后,直接把Tornado端口跑在8000,这个时候,通过localhost:8000就能访问到你的网页.这里分两步,Tornado完成了底部IO事件的监听和数据接受等工作,这是Tornado完成了其作为WebServer的使命.然后你通过按照Tornado框架定义的流程,在对应的地方写了个get函数,实现了这个页面的具体内容,这是Tornado作为Web框架体现了作用.那么nginx有什么用?它是个反向代理,反向代理顾名思义,其作用就是将接收到的HTTP请求按照一定的规则转发给后端其他服务器处理.比如在你的一台机器上跑了三个Tornado应用:foo1,foo2,foo3.端口分别为8000,8001,8003.你希望用户可以直接通过80端口来访问这些应用.这个时候你就可以用Nginx来达到这个目的.让Nginx跑在80端口,当它接收到请求时,如果是/foo1,就转发给8000端口处理;如果是/foo2,就转发给8001端口处理;foo3类似.所以,Tornado和Nginx并没有什么联系.实际上,很多框架都实现了一些简易WebServer,用于调试.Tornado的WebServer是异步的,以可以处理大量的非活跃长连接著称.

# API
http://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query=123.123.123.123&co=&resource_id=6006&oe=utf8    # 这个是百度(有些不准确, 最好用的还是去百度地图的API)
http://ip-api.com/json/123.123.123.123?lang=zh-CN
http://ip.ws.126.net/ipquery?ip=123.123.123.123
http://whois.pconline.com.cn/jsFunction.jsp?callback=jsShow&ip=123.123.123.123
import json
import re

import requests


def search_sp0_baidu_com(ip):
    """http://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query=123.123.123.123&co=&resource_id=6006&oe=utf8"""
    url = f'http://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query={ip}&co=&resource_id=6006&oe=utf8'
    try:
        response = requests.get(url, timeout=5)
        json_obj = response.json()
        # json_obj数据
        """{'status': '0', 't': '', 'set_cache_time': '', 'data': [{'location': '北京市北京市 联通', 'titlecont': 
        'IP地址查询', 'origip': '123.123.123.123', 'origipquery': '123.123.123.123', 'showlamp': '1', 'showLikeShare': 1, 
        'shareImage': 1, 'ExtendedLocation': '', 'OriginQuery': '123.123.123.123', 'tplt': 'ip', 'resourceid': 
        '6006', 'fetchkey': '123.123.123.123', 'appinfo': '', 'role_id': 0, 'disp_type': 0}]} """
        ip_address = json_obj['data'][0]["location"]
    except Exception as e:
        print(e)
        return None
    else:
        return ip_address


def search_ip_api_com(ip):
    """http://ip-api.com/json/123.123.123.123?lang=zh-CN"""
    url = f'http://ip-api.com/json/{ip}?lang=zh-CN'
    try:
        response = requests.get(url, timeout=5)
        json_obj = response.json()
        # json_obj数据
        """{'status': 'success', 'country': '中国', 'countryCode': 'CN', 'region': 'BJ', 'regionName': 
        '北京市', 'city': '朝阳', 'zip': '', 'lat': 39.9771, 'lon': 116.384, 'timezone': 'Asia/Shanghai', 'isp': 'China 
        Unicom Sichuan Province Network', 'org': '', 'as': 'AS4837 CHINA UNICOM China169 Backbone', 
        'query': '123.123.123.123'} """
        ip_address = f"{json_obj['regionName']}{json_obj['city']}"
    except Exception as e:
        print(e)
        return None
    else:
        return ip_address


def search_ip_ws_126_net(ip):
    """http://ip.ws.126.net/ipquery?ip=123.123.123.123"""
    url = f'http://ip.ws.126.net/ipquery?ip={ip}'
    try:
        response = requests.get(url, timeout=5)
        text = response.text
        # text数据
        """var lo="北京市", lc="北京市";var localAddress={city:"北京市", province:"北京市"}"""
        city = re.match(r".*city:\"([\u4e00-\u9fa5]+)\".*", text, re.S).group(1)
        province = re.match(r".*province:\"([\u4e00-\u9fa5]+)\".*", text, re.S).group(1)
        ip_address = f'{province}{city}'
    except Exception as e:
        print(e)
        return None
    else:
        return ip_address


def search_whois_pconline_com_cn(ip):
    """http://whois.pconline.com.cn/jsFunction.jsp?callback=jsShow&ip=123.123.123.123"""
    url = f'http://whois.pconline.com.cn/ipJson.jsp?ip={ip}'
    try:
        response = requests.get(url, timeout=5)
        text = response.text.encode('utf-8')
        # text数据
        """if(window.IPCallBack) {IPCallBack({"ip":"123.123.123.123","pro":"北京市","proCode":"110000",
        "city":"北京市","cityCode":"110000","region":"顺义区","regionCode":"110113","addr":"北京市顺义区 联通","regionNames":"",
        "err":""});} """
        json_str = re.match(r".*?{IPCallBack\((.*)\);}.*", text, re.S).group(1)
        json_obj = json.loads(json_str)
        ip_address = f"{json_obj['pro']} {json_obj['city']} {json_obj['region']}"
    except Exception as e:
        print(e)
        return None
    else:
        return ip_address


def search_ip_address(ip):
    ip_address = search_sp0_baidu_com(ip)
    if ip_address is None:
        ip_address = search_ip_api_com(ip)
    if ip_address is None:
        ip_address = search_ip_ws_126_net(ip)
    if ip_address is None:
        ip_address = search_whois_pconline_com_cn(ip)
    return ip_address


if __name__ == '__main__':
    print(search_ip_address('123.123.123.123'))

方法一:

pip3 config set global.index-url https://mirrors.aliyun.com/pypi/simple/
#pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

方法二:

家目录创建.pip文件夹
mkdir ~/.pip
cd ~/.pip
创建pip.conf
touch pip.conf
vi pip.conf
编辑写入下列代码
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host = pypi.tuna.tsinghua.edu.cn

# 更新pip
pip3 install --upgrade pip
# 安装virtualenv、virtualenvwrapper
pip3 install virtualenv
pip3 install virtualenvwrapper
# 进入.bash_profile文件中,定义virtualenvwrapper路径
vim ~/.bashrc
# 文末添加代码
VIRTUALENVWRAPPER_PYTHON=/usr/local/python3/bin/python3.6    # virtualenvwrapper执行的python版本路径
export WORKON_HOME=$HOME/.virtualenvs    # 虚拟环境存放目录
export VIRTUALENVWRAPPER_VIRTUALENV=/usr/local/python3/bin/virtualenv    # virtualenv所在目录
source /usr/local/python3/bin/virtualenvwrapper.sh    # virtualenvwrapper.sh所在目录
# Python版本的路径用
which python3
虚拟环境存放目录可自定义
# virtualenv所在目录用
find / -name virtualenv
# virtualenvwrapper.sh所在目录可用
find / -name virtualenvwrapper.sh
# 重新加载配置文件
source ~/.bashrc
# 创建虚拟环境
mkvirtualenv py3
# 进入虚拟环境
workon py3
# 快速配置环境
pip install -r requirements.txt

yum -y groupinstall "Development tools"
# apt-get install build-essential
yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel
# 安装位置
cd /usr/local
# 下载Python3.6.8
wget https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tar.xz
# 解压
tar -xf Python-3.6.8.tar.xz
# 创建安装文件夹
mkdir python3
mv Python-3.6.8 python3
cd python3/Python-3.6.8
# 安装
./configure --prefix=/usr/local/python3 --enable-optimizations
make && make altinstall
# 创建软连接
ln -s /usr/local/python3/bin/python3.6 /usr/bin/python3
ln -s /usr/local/python3/bin/pip3.6 /usr/bin/pip3

查看已经安装的shell

cat /etc/shells

安装zsh

brew install zsh

设置默认shell

chsh -s /bin/zsh
git clone https://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc

配置zsh

vi ~/.zshrc

修改主题

ZSH_THEME="ys"

配置插件

cd .oh-my-zsh/plugins
  • zsh-syntax-highlighting语法高亮插件

    git clone https://github.com/zsh-users/zsh-syntax-highlighting.git
  • zsh-autosuggestions记录输入命令插件

    git clone https://github.com/zsh-users/zsh-autosuggestions.git

    在.zshrc中修改配置

plugins=(其他插件 zsh-syntax-highlighting zsh-autosuggestions) # 注意空格隔开
source ~/.zshrc
  • 报错

    Error: Oh My Zsh can't be loaded from: bash. You need to run zsh instead # 退出终端重进

清华大学安装教程

git安装

在终端中输入git,根据提示安装

brew安装

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

更换中科大更新源

  • 更换brew.git

    cd "$(brew --repo)"
    git remote set-url origin https://mirrors.ustc.edu.cn/brew.git
  • 更换核心软件仓库(homebrew-core.git)

    cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
    git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git
  • 更换Home cask软件仓库

    cd "$(brew --repo)"/Library/Taps/homebrew/homebrew-cask
    # 如果未找到就不执行
    git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-cask.git
  • 更换Home Bottles源
    bash终端:

    echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.bash_profile
    source ~/.bash_profile

    zhs终端:

    echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.zshrc
    source ~/.zsh
  • 更新

    brew update

    重置默认源

  • 重置brew.git

    cd "$(brew --repo)"
    git remote set-url origin https://github.com/Homebrew/brew.git
  • 重置核心软件仓库

    cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
    git remote set-url origin https://github.com/Homebrew/homebrew-core.git
  • 重置Homebrew cask软件仓库

    cd "$(brew --repo)"/Library/Taps/homebrew/homebrew-cask
    git remote set-url origin https://github.com/Homebrew/homebrew-cask
  • 重置Homebrew Bottles源

    # 注释掉终端配置文件里的有关Homebrew Bottles即可恢复官方源。 重启终端或重读配置文件
  • mac系统从Sierra后,无法安装不被认可的软件,必须恢复“任何来源”

    sudo spctl --master-disable