月度归档: 2019 年 10 月

  • 2019年各云厂家双11活动汇总

    腾讯云

    腾讯云双11活动地址链接直达

    • 标准型S4/S3 1核/2G/50G 1M宽带 88元/每年
    • 标准型S2 2核/4G/50G 5M宽带 998元/3年
    • 国内短信套餐包 10000条 360元/2年
    • 标准型S2 企业版 2核/4G/50G 3M宽带 688元/3年
    • 标准型S2 企业版 2核/8G/50G 5M宽带 1288元/3年
    • 标准型S2 企业版 4核/8G/50G 5M宽带 2888元/3年

    阿里云

    阿里云双11活动地址链接直达

    • ECS突发性能型t5 1核/2G/40G 1M宽带 86元/每年
    • ECS突发性能型t5 1核/2G/40G 1M宽带 229元3年
    • ECS共享型n4 2核/4G/40G 3M宽带 799元3年
    • ECS共享通用型mn4 2核/8G/40G 5M宽带 1399元3年
    • 突发性能t5 香港 1核/1G/40G 1M宽带 119元/每年
    • 国内短信套餐包 5000条 160元/2年

    滴滴云

    滴滴云双11活动地址链接直达

    • DC2爆款秒杀 1核 / 2GB内存 / 40GB高效云盘 / 1MB带宽 68元/年
    • DC2性价比之王 2核 / 4GB内存 / 40GB高效云盘 / 2MB带宽 468元/3年
    • DC2爆款必抢 2核 / 4GB内存 / 40GB高效云盘 / 5MB带宽 668元/3年
    • GPU入门基础P4版 2核 / 8GB内存 / 80GB高效云盘 / 1MB带宽/8GB显卡 1068元/年

    华为云

    华为云双11活动链接直达链接直达

    • 1核 / 2G 1MB宽带 ¥81.00/年
    • 2核 / 4G 1MB宽带 ¥388.22/年

  • 华为云双11活动 1核2G 年付仅¥81/元

    华为云双11活动 1核2G 年付仅¥81/元

    一年一度的双11到了,我们这里写一下华为云的活动,1核2G 年付仅¥81/元。还有¥49一年的域名注册服务还是相当给力的。

    华为云活动:华为云双11活动直达链接

    云服务器

    最低1核心 2GB 1M带宽 可选北京、上海、广州三个国内机房之一,年付只需要81元,这有点看谁价格低的态势。对于我们用户而言,管你如何竞争,谁价格低,配置高,稳定就用谁。

    华为云服务器直接购买的2折优惠活动81元年付套餐需要等待到九点才开始,如果我们有需要的网友到时候开始之后选择,需要是新注册用户。对于后面需要邀请才可以购买的套餐基本没有兴趣,作为一个新商家活动,居然这么套路用户,肯定没有人去邀请购买。所以直接81元的套餐限时活动还是有可能有人需要的。

    S6服务器新老用户都可以购买没有限制,这个配置是比较大的,属于中等用户项目需求。

    域名

    同时,有需要便宜域名的华为云49元.COM域名目前看还是比较便宜的。

  • Linux查找/根目录依次查找大文件 思路分析

    Linux查找/根目录依次查找大文件 思路分析

    前面我们写了BT宝塔面板 磁盘爆满处理方法 图文教程,近日发现服务器被莫名其妙的塞满了,下面我们记录一下如何从/根目录下手查找大文件的位置。

    根目录/查找大文件

    du -h --max-depth=1 /

    依次查找进入 /www 目录

    du -h --max-depth=1 /www/

    这里可以适当的调整 --max-depth 得参数,就是文件夹深度。

    依次往下进一步查找即可。

  • Python微信红包代码实例 微信红包的架构设计

    Python微信红包代码实例 微信红包的架构设计

    Python微信红包算法实例

    #!/usr/bin/env python
    # coding: utf-8
    import random
    # m : 红包个数
    # n : 红包人数
    # packet : 本次抢到的金额 , 所有金额以分为计算
    def redEnvelope(m,n):
        remain = m*100 #剩余金额
        nn = n #剩余人数
        for i in range(1,n):
            if remain == 0 :
                print('已经全部发完了')
            else :
                packet = random.randint(1,int(remain/nn*2))
                nn -= 1
                remain -= packet 
                print('第%d位成员红包的金额为%.2f元 , 余额为%.2f , 剩余%d人未领红包'%(i,packet/100,remain/100,nn))
        print('最后一个成员红包金额为%.2f元'%(remain/100))

    Python调用方法

    redEnvelope(100,4)

    运行结果

    第1位成员红包的金额为45.65元 , 余额为54.35 , 剩余3人未领红包
    第2位成员红包的金额为16.10元 , 余额为38.25 , 剩余2人未领红包
    第3位成员红包的金额为20.98元 , 余额为17.27 , 剩余1人未领红包
    最后一个成员红包金额为17.27元

    概况:2014年微信红包使用数据库硬抗整个流量,2015年使用cache抗流量。

    微信的金额什么时候算?

    答:微信金额是拆的时候实时算出来,不是预先分配的,采用的是纯内存计算,不需要预算空间存储。。
    采取实时计算金额的考虑:预算需要占存储,实时效率很高,预算才效率低。

    实时性:为什么明明抢到红包,点开后发现没有?

    答:2014年的红包一点开就知道金额,分两次操作,先抢到金额,然后再转账。
    2015年的红包的拆和抢是分离的,需要点两次,因此会出现抢到红包了,但点开后告知红包已经被领完的状况。进入到第一个页面不代表抢到,只表示当时红包还有。

    分配:红包里的金额怎么算?为什么出现各个红包金额相差很大?

    答:随机,额度在0.01和剩余平均值*2之间。
    例如:发100块钱,总共10个红包,那么平均值是10块钱一个,那么发出来的红包的额度在0.01元~20元之间波动。
    当前面3个红包总共被领了40块钱时,剩下60块钱,总共7个红包,那么这7个红包的额度在:0.01~(60/7*2)=17.14之间。
    注意:这里的算法是每被抢一个后,剩下的会再次执行上面的这样的算法(Tim老师也觉得上述算法太复杂,不知基于什么样的考虑)。 这样算下去,会超过最开始的全部金额,因此到了最后面如果不够这么算,那么会采取如下算法:保证剩余用户能拿到最低1分钱即可。 如果前面的人手气不好,那么后面的余额越多,红包额度也就越多,因此实际概率一样的。

    红包的设计

    答:微信从财付通拉取金额数据郭莱,生成个数/红包类型/金额放到redis集群里,app端将红包ID的请求放入请求队列中,如果发现超过红包的个数,直接返回。根据红包的裸祭处理成功得到令牌请求,则由财付通进行一致性调用,通过像比特币一样,两边保存交易记录,交易后交给第三方服务审计,如果交易过程中出现不一致就强制回归。

    发性处理:红包如何计算被抢完?

    答:cache会抵抗无效请求,将无效的请求过滤掉,实际进入到后台的量不大。cache记录红包个数,原子操作进行个数递减,到0表示被抢光。财付通按照20万笔每秒入账准备,但实际还不到8万每秒。

    通如何保持8w每秒的写入?

    答:多主sharding,水平扩展机器。

    据容量多少?

    答:一个红包只占一条记录,有效期只有几天,因此不需要太多空间。

    询红包分配,压力大不?

    答:抢到红包的人数和红包都在一条cache记录上,没有太大的查询压力。

    一个红包一个队列?

    答:没有队列,一个红包一条数据,数据上有一个计数器字段。

    有没有从数据上证明每个红包的概率是不是均等?

    答:不是绝对均等,就是一个简单的拍脑袋算法。

    拍脑袋算法,会不会出现两个最佳?

    答:会出现金额一样的,但是手气最佳只有一个,先抢到的那个最佳。

    每领一个红包就更新数据么?

    答:每抢到一个红包,就cas更新剩余金额和红包个数。

    红包如何入库入账?

    数据库会累加已经领取的个数与金额,插入一条领取记录。入账则是后台异步操作。

  • MySQL int类型 最大值范围 关于mysql 使用int类型出现 1264 Out of range value for column 错误的解决办法

    MySQL int类型 最大值范围 关于mysql 使用int类型出现 1264 Out of range value for column 错误的解决办法

    关于mysql 出现 1264 Out of range value for column , 首先我们了解一下MySQL中int类型的基础知识。

    字节

    我们都知道计算机是以二进制为基础。存储的基本单位是 Bit,也称为比特二进制位。1bit 可以表示 0 或者 1 两个数字,是可能存在的最小的信息量,任何小于1 bit 的内容都算不上信息。

    复杂的内容就要用多 bit 来表示。Byte ,也称为字节,通常用作计量单位。1 byte 等于 8 bit,即 1 byte 可以表示 28 内容。

    MySQL 中的字节

    先说明一下,在 MySQL 中的整数类型,可以分为 unsigned 和 signed 两种,即无符号和有符号,具体内容这里不展开。tinyint 的大小就是 1 byte,在 signed 类型能表示的数字以下表为例。(注:表格根据《编码》修改,仅做举例说明,不代表 MySQL 实际存储)

    二进制数十进制数
    10000000-128
    10000001-127
    10000010-126
    10000011-125
    11111101-3
    11111110-2
    11111111-1
    000000000
    000000011
    000000102
    011111100124
    011111101125
    011111110126
    011111111127

    int 最大值

    在上表中我们看到,首位的 bit 用来表示符号,因此在 sigend 是少一位 bit 来存储内容。int 是 4 byte,结合上述,可以得出 int 在 signed 最大值为

    2**31−1=2147483647

    在 unsigned 中,无需首位 bit 表示符号,因此为

    2**32−1=4294967295

    解决办法

    此时可能是数据值超出了范围,我们可能需要将 int 类型 改成 bigint .

  • Linux下关闭 MySQL 的binlog日志功能 图文教程

    Linux下关闭 MySQL 的binlog日志功能 图文教程

    LNMP一键安装包安装的MySQL默认是开启了日志文件的,如果数据操作比较频繁就会产生大量的日志,在/usr/local/mysql /var/下面产生mysql-bin.0000* 类似的文件,而且一般都在几十MB到几个GB,更甚会吃掉整个硬盘空间,从来导致mysql无法启动或报错,下面我们来说一说如何关闭MySQL的日志功能?

    删除日志 

    /usr/local/mysql/bin/mysql -u root -p
    reset master;

    修改/etc/my.cnf 文件

    log-bin=mysql-bin 
    binlog_format=mixed   

    这两行前面加上#,将其注释掉。

    重启mysql数据库

    /etc/init.d/mysql restart

    本文以LNMP一件安装包安装的环境为例 除MySQL重启命令和配置文件路径可能略有不同,其他一样。

  • Mysql查询某字段值重复的数据

    Mysql查询某字段值重复的数据

    查询user表中,user_name字段值重复的数据及重复次数

    select user_name,count(*) as count from user group by user_name having count>1;

  • Python3 中如何实现冒泡排序算法?

    Python3 中如何实现冒泡排序算法?

    什么是冒泡排序算法?

    临近的两个元素进行比较,然后互换顺序,一趟走完之后最大的或者最小的元素排在第一个或者最后一个位置(最大或者最小看实际需求),给的的感觉就是一个小泡泡一直冒啊冒,所以有个好听的名字叫冒泡算法

    举个例子,有数组[10, 1, 18, 30, 23, 12, 7, 5, 18, 17],我们使用从小到大的排序方法

    第一趟,外排下标为0,对应的值为10

    内排开始

    ①下标0和下标1的值进行比较。10和1比,发现1比10小,进行互换,内排一次完成,结果是[1, 10, 18, 30, 23, 12, 7, 5, 18, 17]

    ②下标1和下标2的值进行比较。10和18比,10比18小,保持不变,结果是[1, 10, 18, 30, 23, 12, 7, 5, 18, 17]

    ③下标2和下标3的值进行比较。18和30比,18比30小,保持不变,结果是[1, 10, 18, 30, 23, 12, 7, 5, 18, 17]

    ④下标3和下标4的值进行比较。30和23比,30比23大,进行互换,结果是[1, 10, 18, 23, 30, 12, 7, 5, 18, 17]

    ……一直这样紧邻的两个数比下去,第一趟外排结束,结果是[1, 10, 18, 23, 12, 7, 5, 18, 17, 30],我们发现,我们经过了这一次排序,把最大值30送到了右侧

    第二趟,外排下标是1

    内排开始

    ①下标0和下标1的值进行比较。1和10比,1比10小,保持不变,内排一次完成,结果是[1, 10, 18, 23, 12, 7, 5, 18, 17, 30]

    ②下标1和下标2的值进行比较。10和18比,10比18小,保持不变,内排二次完成,结果是[1, 10, 18, 23, 12, 7, 5, 18, 17, 30]

    …………

    ④下标3和下标4的值进行比较。12和23比,23比12小,进行互换,内排四次完成,结果是[1, 10, 18, 12, 23, 7, 5, 18, 17, 30]

    ⑤下标4和下标5的值进行比较。23和7比较,23比7大,进行互换,内排五次完成,结果是[1, 10, 18, 12, 7, 23, 5, 18, 17, 30]

    …………经过一系列排序,结束,结果为[1, 10, 18, 12, 7, 5, 18, 17, 23, 30],这个时候我们把第二大的数据23放到正确的位置

    第三趟

    …………结果为[1, 10, 12, 7, 5, 18, 17, 18, 23, 30]

    …………

    …………

    最终结果为[1, 5, 7, 10, 12, 17, 18, 18, 23, 30]

    至此,排序完成。

    Python3 代码实例

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    #冒泡排序
     
    def bubble_sort(the_list):
        i = 0
        while i < len(the_list):
            j = 0
            while j < len(the_list)-1:
                print(the_list[j],the_list[j+1])
                if the_list[j] > the_list[j+1]:
                    the_list[j], the_list[j+1] = the_list[j+1], the_list[j]
                j = j+1
                print(the_list)
            print("======"+str(the_list))
            i = i+1
        return the_list
    if __name__ == '__main__':
        the_list = [10, 1, 18, 30, 23, 12, 7, 5, 18, 17]
        print("排序前:" + str(the_list))
        print("排序后:" + str(bubble_sort(the_list)))
    

    运行结果

    排序前:[10, 1, 18, 30, 23, 12, 7, 5, 18, 17]
    10 1
    [1, 10, 18, 30, 23, 12, 7, 5, 18, 17]
    10 18
    [1, 10, 18, 30, 23, 12, 7, 5, 18, 17]
    18 30
    [1, 10, 18, 30, 23, 12, 7, 5, 18, 17]
    30 23
    [1, 10, 18, 23, 30, 12, 7, 5, 18, 17]
    30 12
    [1, 10, 18, 23, 12, 30, 7, 5, 18, 17]
    30 7
    [1, 10, 18, 23, 12, 7, 30, 5, 18, 17]
    30 5
    [1, 10, 18, 23, 12, 7, 5, 30, 18, 17]
    30 18
    [1, 10, 18, 23, 12, 7, 5, 18, 30, 17]
    30 17
    [1, 10, 18, 23, 12, 7, 5, 18, 17, 30]
    ======[1, 10, 18, 23, 12, 7, 5, 18, 17, 30]
    1 10
    [1, 10, 18, 23, 12, 7, 5, 18, 17, 30]
    10 18
    [1, 10, 18, 23, 12, 7, 5, 18, 17, 30]
    18 23
    [1, 10, 18, 23, 12, 7, 5, 18, 17, 30]
    23 12
    [1, 10, 18, 12, 23, 7, 5, 18, 17, 30]
    23 7
    [1, 10, 18, 12, 7, 23, 5, 18, 17, 30]
    23 5
    [1, 10, 18, 12, 7, 5, 23, 18, 17, 30]
    23 18
    [1, 10, 18, 12, 7, 5, 18, 23, 17, 30]
    23 17
    [1, 10, 18, 12, 7, 5, 18, 17, 23, 30]
    23 30
    [1, 10, 18, 12, 7, 5, 18, 17, 23, 30]
    ======[1, 10, 18, 12, 7, 5, 18, 17, 23, 30]
    1 10
    [1, 10, 18, 12, 7, 5, 18, 17, 23, 30]
    10 18
    [1, 10, 18, 12, 7, 5, 18, 17, 23, 30]
    18 12
    [1, 10, 12, 18, 7, 5, 18, 17, 23, 30]
    18 7
    [1, 10, 12, 7, 18, 5, 18, 17, 23, 30]
    18 5
    [1, 10, 12, 7, 5, 18, 18, 17, 23, 30]
    18 18
    [1, 10, 12, 7, 5, 18, 18, 17, 23, 30]
    18 17
    [1, 10, 12, 7, 5, 18, 17, 18, 23, 30]
    18 23
    [1, 10, 12, 7, 5, 18, 17, 18, 23, 30]
    23 30
    [1, 10, 12, 7, 5, 18, 17, 18, 23, 30]
    ======[1, 10, 12, 7, 5, 18, 17, 18, 23, 30]
    1 10
    [1, 10, 12, 7, 5, 18, 17, 18, 23, 30]
    10 12
    [1, 10, 12, 7, 5, 18, 17, 18, 23, 30]
    12 7
    [1, 10, 7, 12, 5, 18, 17, 18, 23, 30]
    12 5
    [1, 10, 7, 5, 12, 18, 17, 18, 23, 30]
    12 18
    [1, 10, 7, 5, 12, 18, 17, 18, 23, 30]
    18 17
    [1, 10, 7, 5, 12, 17, 18, 18, 23, 30]
    18 18
    [1, 10, 7, 5, 12, 17, 18, 18, 23, 30]
    18 23
    [1, 10, 7, 5, 12, 17, 18, 18, 23, 30]
    23 30
    [1, 10, 7, 5, 12, 17, 18, 18, 23, 30]
    ======[1, 10, 7, 5, 12, 17, 18, 18, 23, 30]
    1 10
    [1, 10, 7, 5, 12, 17, 18, 18, 23, 30]
    10 7
    [1, 7, 10, 5, 12, 17, 18, 18, 23, 30]
    10 5
    [1, 7, 5, 10, 12, 17, 18, 18, 23, 30]
    10 12
    [1, 7, 5, 10, 12, 17, 18, 18, 23, 30]
    12 17
    [1, 7, 5, 10, 12, 17, 18, 18, 23, 30]
    17 18
    [1, 7, 5, 10, 12, 17, 18, 18, 23, 30]
    18 18
    [1, 7, 5, 10, 12, 17, 18, 18, 23, 30]
    18 23
    [1, 7, 5, 10, 12, 17, 18, 18, 23, 30]
    23 30
    [1, 7, 5, 10, 12, 17, 18, 18, 23, 30]
    ======[1, 7, 5, 10, 12, 17, 18, 18, 23, 30]
    1 7
    [1, 7, 5, 10, 12, 17, 18, 18, 23, 30]
    7 5
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    7 10
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    10 12
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    12 17
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    17 18
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    18 18
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    18 23
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    23 30
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    ======[1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    1 5
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    5 7
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    7 10
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    10 12
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    12 17
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    17 18
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    18 18
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    18 23
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    23 30
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    ======[1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    1 5
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    5 7
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    7 10
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    10 12
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    12 17
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    17 18
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    18 18
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    18 23
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    23 30
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    ======[1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    1 5
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    5 7
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    7 10
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    10 12
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    12 17
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    17 18
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    18 18
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    18 23
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    23 30
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    ======[1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    1 5
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    5 7
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    7 10
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    10 12
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    12 17
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    17 18
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    18 18
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    18 23
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    23 30
    [1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    ======[1, 5, 7, 10, 12, 17, 18, 18, 23, 30]
    排序后:[1, 5, 7, 10, 12, 17, 18, 18, 23, 30]

  • 在Python3 Django框架 模板中如何使用条件判断?

    在Python3 Django框架 模板中如何使用条件判断?

    老季在本篇记录一下在Django的开发中,如何在模板中使用if判断条件。

    views.py

    # view 文件
    def func(request):
        ...
        return render(request,"index.html",{
            'current_user':"alex",
            'user_list':['alex','eric',
            'user_dict':{'k1':'v1','k2':'v2'}]
        })

    .html 模板

    # html 文件
    <html>
        ....
    <body>
        <div>{{current_user}}</div>
        <a>{{ user_list.0}}</a>
        # 条件判断
        {% if age %}
            <a> 有年龄<a>
        {% else %}
            <a> 无年龄<a>
        {% endif %}
        # 嵌套条件判断
        {% if age %}
            <a> 有年龄<a>
        {% if age > 16 %}
            <a>老男人<a>
        {% else %}
            <a>小男孩<a>
        {% else %}
            <a> 无年龄<a>
        {% endif %}
        <body>
    </html>
  • Python 登录交换机switch 巡检 拉取交换机配置信息

    Python 登录交换机switch 巡检 拉取交换机配置信息

    场景需求

    前面老季写了一个 PHP如何登录连接TELNET并执行交换机命令类 图文教程 ,最近项目中遇到了要换python3来登录交换机并拉取配置。这里我们直接贴出相关代码使用telnetlib类来登录交换机并拉取配置。

    我们在代码中可以处理交换机拉取配置时,内容过长,出现 --- More --- 需要按空格的场景。并且将所有交换机命令的返回值都进行了返回给调用方法。

    代码实例

    class TelnetClient():
        def __init__(self,):
            self.tn = telnetlib.Telnet()
            time.sleep(0.2)
        # 此函数实现telnet登录主机
        def login(self,host_ip,username,password,port=23):
            try:
                # self.tn = telnetlib.Telnet(host_ip,port=23)
                self.tn.open(host_ip,port)
            except:
                logging.critical('网络连接失败'+repr(host_ip))
                return False
            # 等待login出现后输入用户名,最多等待10秒
            self.tn.read_until(b'Username: ',timeout=1)
            self.tn.write(username.encode('ascii') + b'\n')
            self.tn.read_until(b'Password: ',timeout=1)
            self.tn.write(password.encode('ascii') + b'\n')
            # 延时两秒再收取返回结果,给服务端足够响应时间
            time.sleep(0.2)
            # 获取登录结果
            # read_very_eager()获取到的是的是上次获取之后本次获取之前的所有输出
            command_result = self.tn.read_very_eager().decode('ascii')
            if 'Login incorrect' not in command_result:
                return True
            else:
                return False
        # 此函数实现执行传过来的命令,并输出其执行结果
        def execute_some_command(self,command):
            logging.info('开始执行交换机命令:'+command)
            # 执行命令
            self.tn.write(command.encode('ascii')+b'\n')
            time.sleep(0.2)
            # 获取命令结果
            a = []
            a.append(('--- More ---').encode('ascii'))
            command_result = self.tn.read_very_eager().decode('ascii')
            while True:
                b,c,d = self.tn.expect(a,timeout=1)
                command_result += d.decode('ascii')
                if 0 == b:
                    time.sleep(0.2)
                    self.tn.write(b' \n') #不用\r\n来继续
                else:
                    break
            logging.info('命令执行结果:'+repr(command_result))
            if 'Error:' in command_result :
                logging.critical('执行结果中可能包含错误`Error:`,脚本强制退出')
                sendWxMsg('流量调度系统交换机命令执行出现错误,请及时处理!')
                sys.exit()
            return command_result
        # 退出telnet
        def logout(self):
            self.tn.write(b"exit\n")
            self.tn.close()
    

    多个交换机命令时封装调用(可自行封装)

    # 执行多条交换机命令
    def execSwitchCmd( host , username , password , commands , extra = '1' ) :
        '''
        :param host:主机地址
        :param username:用户名
        :param password:密码
        :param commands:列表命令集
        :param extra: 是否需要执行 system-view , commit 命令
        '''
        logging.info('开始执行交换机命令【'+repr(commands)+'】')
        # return True
        telnet_client = TelnetClient()
        msg = ''
        # 如果登录结果返加True,则执行命令,然后退出
        if telnet_client.login(host,username,password) :
            if extra == 1:
                msg += telnet_client.execute_some_command( 'system-view' )
            for command in commands :
                msg += telnet_client.execute_some_command( command )
            if extra == 1:            
                msg += telnet_client.execute_some_command( 'commit' )
            telnet_client.logout()    
        return msg

    调用方法

    cmd = []
    cmd.append('dis traffic-policy applied-record TO_TrafficCenter')
    res = func.execSwitchCmd(room['host'],room['username'],room['password'],cmd , '0')
    if 'xxxxx' in res :
        # 某些配置在交换机中,做什么处理
        ......

    交换机命令过多时,建议使用\r\n拼接命令并分组

    def centerSchedulingOut95( destination_id , pieces ) :
        # .....
        #.......
        cmd = []
        i = 1
        divided = 12
        tmpCmd = ''
        for policy in policys :
            from_room = getRoomById( policy['destination_id'] )
            if i % divided == 0 :
                cmd.append( tmpCmd )
                tmpCmd = ''
            else :
                tmpCmd += '\r\n' + policy['name'] + '\r\n' + 'UNDO traffic-policy TO_'+from_room['abbr']+' inbound' + '\r\n' + 'traffic-policy TO_'+to_room['abbr']+' inbound' + '\r\n'
            i += 1
            config.cursor.execute("UPDATE center_policy SET status = 2 ,destination_id = %s , update_time=%s WHERE id = %s" , [ destination_id , getNow() , policy['id'] ] )
            logging.info('|----已更改 %s 状态为:使用中,去向机房ID:%s',policy['name'] , to_room['id'])
        if tmpCmd != '' :
            cmd.append( tmpCmd )
        logging.info('|----开始登录调度中心交换机,批量执行调出POLICY命令')
        config.cursor.execute("SELECT * FROM center")
        centerObj = config.cursor.fetchone()
        if len(cmd) > 0 :
            logging.info('|----本次实际调度POLICY规则条数:%s',repr( len(policys) ) )
            execSwitchCmd( host = centerObj['host'] , username = centerObj['username'] , password = centerObj['password'] , commands = cmd )

    我们这里将命令拼接成 \r\n的格式拼接,每12个命令一组,传入到交换机里执行。

  • Python3 半自动使用 ChromeDriver 采集豆瓣图片 并提交到 Chevereto 图床

    Python3 半自动使用 ChromeDriver 采集豆瓣图片 并提交到 Chevereto 图床

    前面我们写了Python 爬虫 抓取豆瓣小组图片 通过api提交入库到 Chevereto 图床,但是现在有些群组需要登录才行,所以我们这里做了一个半自动脚本并使用chromedriver自动登录豆瓣并提交图片到 Chevereto 图床。

    注:老季是Python新手,且本脚本大部分内容来自网络。

    chormedriver下载地址

    http://npm.taobao.org/mirrors/chromedriver/

    Python代码实例

    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    # 作者:老季
    # 网址:https://www.laoji.org
    #导入所需的库
    import logging
    import random
    import time
    import urllib.request
    import requests , json
    from selenium import webdriver
    # 实例化driver
    # option= webdriver.ChromeOptions()
    # driver = webdriver.Chrome(chrome_options=option)
    driver = webdriver.Chrome('D:\\Downloads\\chromedriver.exe') # chromedirver所在路径
    # 登陆
    driver.get('https://accounts.douban.com/passport/login')
    driver.find_element_by_class_name('account-tab-account').click()  # 模拟点击
    time.sleep(2)
    driver.find_element_by_id('username').send_keys('豆瓣用户名')  # 输入用户名
    driver.find_element_by_id('password').send_keys('豆瓣密码')  # 输入密码
    driver.find_element_by_css_selector("[class='btn btn-account btn-active']").click()  # 模拟点击
    time.sleep(5)
    '''
    TODO:验证码
    '''
    # 获取cookie
    session = requests.Session()
    cookies = driver.get_cookies()
    for cookie in cookies:
        session.cookies.set(cookie['name'], cookie['value'])
    # print(cookies)
    time.sleep(3)
    logging.FileHandler(filename='Selenium_img_douban.log', encoding='utf-8')
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                        datefmt='%Y-%m-%d %A %H:%M:%S',
                        # filename='F:\\豆瓣下载\\Selenium_img_douban.log', # 日志保存路径
                        filemode='w')
    # 模拟浏览器提交图片
    def submit_img(url):
        submit_url = 'http://tutie.org/api/1/upload/?key='+urllib.parse.quote_plus('f14fe8e8b11c08902a489706d7d99941')+'&source='+urllib.parse.quote_plus(url)
    #    print(submit_url)
        req = urllib.request.Request(submit_url)
        try:
            res = urllib.request.urlopen(req)
            data = json.loads(res.read().decode())
            return str(data['status_code'])        
        except urllib.error.HTTPError as e:
            print(e.read())      
    
    def get_headers():
        '''
        随机获取一个headers
        '''
        user_agents = ['Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
                       'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
                       'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11']
        headers = {'User-Agent': random.choice(user_agents)}
        return headers
    
    def get(url,group_url, start_page, end_page, params=None):
        '''
        向一个url发送get请求,返回response对象
        :param url: 网页链接
        :param params: URL参数字典
        :return: 发送请求后获取的response对象
        '''
        # 等待一个随机的时间,防止被封IP,这里随机等待0~6秒,亲测可有效地避免触发豆瓣的反爬虫机制
        time.sleep(6 * random.random())
        resp = session.get(url, params=params, headers=get_headers())
        print(resp)
        logging.info(resp)
        if resp:
            logging.info(
                '[get] url = {0}, status_code = {1}'.format(url, resp.status_code))
            resp.encoding = 'utf-8'
            # 这里很重要,每次发送请求后,都更新session的cookie,防止cookie过期
            if resp.cookies.get_dict():
                session.cookies.update(resp.cookies)
                logging.info('[get] updated cookies, new cookies = {0}'.format(
                    resp.cookies.get_dict()))
        else:
            logging.info('[get] url = {0}, response is None'.format(url))
        logging.info('[info] 寻找小组列表地址...')
        logging.info('[get] 已进入小组首页')
        while start_page <= end_page:
            driver.get(group_url + str((start_page - 1) * 25)) # 晒晒你最性感的照片小组
            logging.info('已进入第' + str(start_page) + '页')
            print('已进入第' + str(start_page) + '页')
            # 每一页讨论链接列表
            links = driver.find_elements_by_xpath(r"//tbody/tr/td[@class='title']/a")
            topic_links = {}
            for link in links:
                topic_link = link.get_attribute('href')
                title_name = link.get_attribute('title')
                # 获取的图片以小组话题名称命名
                img_name = title_name.replace('?', '?').replace('\\', '').replace('/', '').replace('"', '').replace(':','').replace('*','').replace('<', '').replace('>', '').replace('|', '').replace('\n', '')
                topic_links[topic_link] = img_name
                topic_num = 0
            for topic_link, img_name in topic_links.items():
                logging.info('进入第' + str(start_page) + '页,第' + str(topic_num + 1) + '话题。')
                topic_num += 1
                driver.get(topic_link)
                # 判断该话题下有无图片
                img_links = driver.find_elements_by_class_name('image-wrapper')
                if len(img_links) > 0:
                    i = 0
                    for img_link in img_links:
                        img_name = topic_links[topic_link] + '_' + str(i)
                        img_src = img_link.find_element_by_xpath('./img').get_attribute('src')
                        print('[get] 话题:' + img_name + ', 图片链接:' + img_src)
                        img = img_src.replace('.webp','.jpg')
                        print('提交图片链接:'+img)
                        submit_img( img )
                        # download_img = urllib.request.urlretrieve(img_src, 'F:\\豆瓣下载\\%s.jpg' % img_name)
                        # time.sleep(3 * random.random())
                        i += 1
                else:
                    print('该标题下无图片')
                img_links2 = driver.find_elements_by_css_selector("[class='topic-figure cc']")
                time.sleep(3 * random.random())
            start_page += 1
            time.sleep(3 * random.random())
        time.sleep(5)
        driver.quit()
    
    if __name__ == '__main__':
        home_url = 'https://www.douban.com/'
        group_url = 'https://www.douban.com/group/481977/discussion?start='
        get(home_url , group_url, 0, 10000)
    
  • Python3 Django admin后台中设置某个字段可以选择显示H5自定义颜色的选项卡

    Python3 Django admin后台中设置某个字段可以选择显示H5自定义颜色的选项卡

    场景需求

    在Django的项目开发中,如何在后台设置将某个字段使用H5的自定义颜色选择器,实现效果如下图所示:

    可以根据HTML5自定义颜色的设置自定义显示。

    这边我们记录一下如何才能实现

    安装Python扩展

    在终端中执行如下命令

    pip install django-colorfield
    python .\manage.py collectstatic

    设置 settings.py

    打开 settings.py ,将 colorfield 添加到 INSTALLED_APPS 配置中

    models.py 中使用

    from django.db import models
    from colorfield.fields import ColorField
    class ComputerRoom(models.Model):
        name = models.CharField(max_length=256,verbose_name = "名称")
        abbr = models.CharField(max_length=128, blank=True, null=True,verbose_name = "缩写")
        type = models.CharField(max_length=256,verbose_name='类型', choices=typeChoices)
        color = ColorField(default='#FF0000',verbose_name='显示颜色')

    然后在Django后台打开对应的模块就可以看到颜色选择器了。

WeChat