在树莓派上部署微信机器人

第二季度接了一个有意思的任务——用机器学习算法做数据拟合,算法本身没什么,但是如何让一个在python中的算法变成一个有界面的服务就比较有意思了。我刚好又买了一块树莓派3,于是打算把后端程序放在树莓派上运行。经过上一篇的工作,树莓派已经具备web发布功能,我们可以部署一个微信机器人用来监视树莓派上的计算任务……

说实在的,这篇文章算是一个闲篇。就是最近帮一个做期货的朋友做了一个盯盘小程序,这个程序是需要24小时运行的,而且没有什么计算量,主要就是抓数据,是一个非常适合树莓派的应用场景。

1. 安装itchat

itchat是一个通过抓包分析并实现的基于python的微信客户端(个人感觉相当给力)。
首先是安装:

1
sudo pip3 install itchat

然后按照官方教程写一个测试小程序:

1
2
3
4
5
6
7
8
import itchat

@itchat.msg_register(itchat.content.TEXT)
def print_content(msg):
print(msg['Text'])

itchat.auto_login()
itchat.run()

将小程序拷贝到树莓派上(貌似VNC客户端也可以通过图形界面拷贝,但我没试过,在使用scp命令前最好在树莓派上配置ssh,以后会比较方便):

1
scp -r test pi@192.168.1.106:webapp/

这时候测试发现问题来了,不论是用树莓派自带的python3.4、或是用conda中的python3.4、甚至是树莓派自带的python2.7运行测试脚本,都会报一河滩错,大致类似:

1
requests.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'SSL3_GET_SERVER_CERTIFICATE', 'certificate verify failed')],)",)

乍一看是requests的报错,觉得是小事,没想到接下来是长达几小时的填坑[捂脸]……

1.1 尝试解决requests报错

为了解决上面这个requests报错,需要安装相关库(操作依据Raspbian (latest) + Python : SSL error when trying to send data):

1
2
sudo apt-get install libffi-dev libssl-dev
pip install requests[security]

经测试发现上面这个方法对报错没有任何影响(-_-)

1.2 尝试解决OpenSSL报错

考虑更新树莓派上的OpenSSL(操作依据SSL Error: bad handshake #3212的第一种方法):

测试OpenSSL时可以直接使用openssl命令,会发现能够正常连接的主机(比如github.com:443)与会产生证书错误的主机(比如login.weixin.qq.com:443)的返回信息状态不同(正常是0,微信非正常的返回了20):

1
openssl s_client -connect "<url>:443" -showcerts -servername "<url>"

更新方法参考How to install OpenSSL 1.0.2 on Raspberry Pi3

为包管理器手动新增源:

1
echo "deb-src http://httpredir.debian.org/debian jessie-backports main contrib non-free" | sudo tee /etc/apt/sources.list.d/jessie-backports.list

更新包管理器:

1
sudo apt-get update

下载jessie-backports中的OpenSSL源码:

1
apt-get source --allow-unauthenticated openssl/jessie-backports

安装debain构建程序:

1
2
3
4
5
sudo apt-get install devscripts
cd openssl-1.0.2l/
export DEB_BUILD_OPTIONS=nocheck; debuild -us -uc -aarmhf
sudo dpkg -i libssl1.0.0_1.0.2l-1~bpo8+1_armhf.deb
sudo dpkg -i openssl_1.0.2l-1~bpo8+1_armhf.deb

一步一步执行这个过程会用掉几个小时[捂脸]……结束后就可以测试安装结果了:

1
2
/usr/bin/openssl version
OpenSSL 1.0.2l 25 May 2017

此时在使用openssl命令会发现刚才提到的两个主机的返回值一致了。然而并没有什么卵用,用python运行程序依然是一样的报错(这时候已经是凌晨了[捂脸]此时我是崩溃的)。

这时候突然意识到,python本身build的时候是需要使用OpenSSL源码的,也就是说,python本身有自己的OpenSSL。到python的/bin文件夹下一看,果然是有openssl,检查一下:

1
2
python -c "import ssl; print(ssl.OPENSSL_VERSION)"
OpenSSL 1.0.1k 8 Jan 2015

因为python本身的OpenSSL版本和系统OpenSSL版本不同,要使用这种方法解决问题,必须使用当前树莓派的OpenSSL版本(我们升级过的1.0.2l)源码编译python[捂脸]……

1.3 将requests的环境变量指向旧证书

我真是懒得在树莓派上编译python,于是只好再试另一种补丁试的方法,虽然不彻底,但是能解决问题(操作依据SSL Error: bad handshake #3212的第二种方法):
找到当前python的weak.pem:

1
2
python -c "import certifi; print(certifi.old_where())"
/home/pi/miniconda3/envs/webenv/lib/python3.4/site-packages/certifi/weak.pem

此时,要为requests配置环境变量:

1
export REQUESTS_CA_BUNDLE=/home/pi/miniconda3/envs/webenv/lib/python3.4/site-packages/certifi/weak.pem

再使用python的requests.get测试连接微信主机,成功!在以后的python代码的requests发送https请求之前,加上以下几行代码即可:

1
2
import os, certifi
os.environ['REQUESTS_CA_BUNDLE'] = certifi.old_where()

如果像我一样在Flask程序中使用celery异步处理作业,则需要在celery运行入口中(比如我的就是在app/__init__)加入上面这段代码。

2. 安装终端复用程序Tmux

上面这个小程序需要同时开三四个终端监视运行状态(redis-serverceleryflaskredis-cli等),所以安装一个tmux会非常方便。

1
sudo apt-get install tmux

配置鼠标模式参考:https://gist.github.com/niun/c7fd6abb5c0d5e847890
tmux重新连接会话:session:tmux attach [-t target-session] <host>
tmux退出连接的会话:^b+d或者^b+命令:detach
另外,将wget的内容输出到终端的命令时:wget -qO- <url>-q为quiet模式,屏蔽request header信息的回显;-O指定输出文件,后面加-,就定向为标准输出了)。

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×