Tagged: Python

Python实战之520特别版:用微信每天和她说晚安

今天是传说中的520,不知你是否已经准备好要表白的话语。为了助你撩妹成功,云厉今天也学着某些人土土的教大家用Python每天给妹纸说晚安。
没错,每天!
用对了Python,每天都过520

这次真的是面向对象编程

大致思路是这样:

  1. 调接口获取每日心灵鸡汤或撩妹话术
  2. 基于wxpy模块,授权微信登录,搜索聊天对象,发送XX消息
  3. Timer每日发送
  4. 后台挂起执行脚本

安装wxpyrequests

pip3 install wxpy
pip3 install requests

其他如果没安装,也一并安装

下面发送信息脚本send_wx.py,不到40行的代码,注释不多,相信你懂!

# -*- coding: utf-8 -*-

from threading import Timer
from wxpy import *
import requests

bot = Bot(console_qr=2, cache_path='botoo.pkl') 

# 她的昵称和你的昵称。是微信昵称,不是备注哦
ta_name = '若';
my_name = '云厉';

# 从金山词霸获取每日鸡汤,英文和翻译,如果你有更好的鸡汤数据源,也可以更换
def get_message():
    url = "http://open.iciba.com/dsapi/"
    r = requests.get(url)
    contents = r.json()['content']
    translation= r.json()['translation']
    return contents, translation

# 给TA发送晚安信息
def send_message(): 
    try:
        message = get_message()
        # 搜索聊天对象,并ensure_one保证她的昵称在你的微信好友列表里只有一个
        my_love = ensure_one(bot.search(ta_name, sex=FEMALE))
        # 发送鸡汤
        my_love.send(message[0])
        my_love.send(message[1][5:])
        my_love.send(u'亲爱的,晚安!爱你~')
        # 每86400秒(1天),发送1次
        t = Timer(86400, send_message)
        t.start()
    except:
        my_self = ensure_one(bot.search(my_name, sex=MALE))
        my_self.send(u'今天撩妹消息发送失败了')

if __name__ == '__main__':
    send_message()
# 丢后台跑起来!
nohup python3 send_wx.py > send_wx.log 2>&1 &

首次运行,脚本会生成二维码,需要授权登录。这也是为什么在脚本内用Timer定时发送而不用Linux的cron,就是为了不要每次都授权登录,太麻烦!

测试一把,效果如下:

wxpy还能干啥?

  • 控制路由器、智能家居等具有开放接口的玩意儿
  • 运行脚本时自动把日志发送到你的微信
  • 加群主为好友,自动拉进群中
  • 跨号或跨群转发消息
  • 自动陪人聊天
  • 逗人玩
  • ...

总而言之,可用来实现各种微信个人号的自动化操作

如果你有兴趣,欢迎关注微信公众号:程序员到架构师,不定期更新各种各样的Python技术

Python中被忽略的else

else, 我们再熟悉不过了。对于一个Python程序员来说,else往往都是配合 if 来使用的,像这样:

a = '12'
if a == '123':
    print(a)
else:
    print('出错了!')

但是,Python中的else并不只能用在if之后,so,这次我们讨论一下Python流程控制中的else。

else子句不仅能在 if 语句中使用,还能在 for、while 和 try 语句中使用,这个语言特性不是什么秘密,但却没有得到重视。我们看一个例子:

my_list = ['apple', 'pear', 'orange', 'banana']
for item in my_list:
    if item == 'banana':
        print('Founded!')
        break
else:
    raise ValueError('No banana flavor found!')

本例当中,循环最后找到了'banana‘,输出'Founded!',并且跳出循环,所以else字句并没有被执行。但如果,将代码修改一下,去掉列表中的'banana':

my_list = ['apple', 'pear', 'orange']
for item in my_list:
    if item == 'banana':
    print('Founded!')
    break
else:
    raise ValueError('No banana flavor found!')

运行代码就会直接抛出错误!如果不使用else字句来完成上述功能,可能我们就需要设置控制标志了,像这样:

my_list = ['apple', 'pear', 'orange']
flag = True for item in my_list:
    if item == 'banana':
        print('Founded!')
        flag = False
        break
if flag:
    raise ValueError('No banana flavor found!')

很明显,这里使用了额外的变量 flag 和 if 语句。

while 和 for 相类似,简单举个例子:

a = 'apple'
while a == 'banana':
    pass
else:
    raise ValueError('No banana flavor found!')

下面看一下try:

try:
    dangerous_call()
except OSError:
    log('OSError...')
else:
    after_call()

很明确,try 块防守的是 dangerouscall() 可能出现的错误,而且很明显,只有 try 块不抛出异常,才会执行 aftercall()。

现在,总结一下 else 子句的行为如下:

for: 仅当 for 循环运行完毕时(即 for 循环没有被 break 语句中止)才运行 else 块。
while: 仅当 while 循环因为条件为假值而退出时(即 while 循环没有被break 语句中止)才运行 else 块。
try: 仅当 try 块中没有异常抛出时才运行 else 块。

即,如果异常或者 return、break 或 continue 语句导致控制权跳到了复合语句的主块之外,那么else 子句也会被跳过。

for/else、while/else 和 try/else 的语义关系紧密,不过与if/else 差别很大。主要是else 这个单词的意思阻碍了我们对这些特性的理解。 按正常的理解应该是“要么运行这个循环,要么做那件事”。可是,在循环中,else 的语义恰好相反:“运行这个循环,然后做那件事。”不过,相信多使用几次,你会熟悉的。

准确判断文件类型方法之二进制文件头

判断文件类型在开发中非常常见的需求,很多开发者的做法是简单判断文件的扩展名,很遗憾,这种方法非常不靠谱,因为文件扩展名可以伪造,并且在Linux系统中,没有扩展名的概念!

这里推荐一种准确判断文件类型的方法:通过二进制文件头判断文件类型
代码非常简单,只需从文件流中读取前两个字节,再解包,即可判断出文件类型,并且大部分语言都支持,Python和PHP版示例参考:

Python版

# -*- coding: utf-8 -*-

import struct 

file_type_map = {
    '7790'   : 'exe',
    '7784'   : 'midi',
    '8075'   : 'zip',
    '8297'   : 'rar',
    '7173'   : 'gif',
    '6677'   : 'bmp',
    '13780'  : 'png',
    '255216' : 'jpg',
}

def get_file_type(filename):
    fp = open(filename, 'rb')
    str_info = struct.unpack_from("BB", fp.read(2))
    str_code = '%d%d' % (str_info[0], str_info[1])
    fp.close()
    return 'unknown' if str_code not in file_type_map else file_type_map[str_code]

if __name__ == '__main__':
    file_type = get_file_type('./test.png')
    print(file_type)

PHP版

PHP有一个内置的专门用于判断图像类型的方法,exif_imagetype,默认未开启,需要编译时候指定 --enable-exif 开启,并且只支持图像类型文件,所以不推荐使用。PHP同样可以通过二进制文件头判断文件类型

<?php

$file_type_map = array(
    7790   => 'exe',
    7784   => 'midi',
    8075   => 'zip',
    8297   => 'rar',
    7173   => 'gif',
    6677   => 'bmp',
    13780  => 'png',
    255216 => 'jpg',
);

function get_file_type($file) {
    $filepath = realpath($file);
    if (!($fp = @fopen($filepath, 'rb')))
        return false;
    $bin = fread($fp, 2);
    fclose($fp);
    $str_info = @unpack('C2chars', $bin);
    $str_code = intval($str_info['chars1'].$str_info['chars2']);
    global $file_type_map;
    return $file_type_map[$str_code] ?: 'unknown';
}

$file_type = get_file_type('./test.png');
print($file_type);

微信公众号:程序员到架构师

最新文章

Return Top