Flask簡易搭建

最近用python寫了個小服務,既然都用python寫了,不如順便用python的服務器來運行,簡單搜索後決定用Flask+uwsgi+nginx來實現。virtualenv的安裝就不多說了。

#新建一個python3虛擬環境emailApp
mkdir pythons
cd pythons
virtualenv --python=/usr/local/bin/python3.5 emailApp
source emailApp/bin/activate
#安裝uwsgi和Flask
pip install uwsgi Flask
cd emailApp
#新建emailApp1.py
#!/root/42/pythons/emailApp/bin/python
# -*- coding: utf8 -*-

from flask import Flask,request
import json

app = Flask(__name__)

def getTS():
    TS={}

    nowTS=int(time.time())
    TS['当前时间戳']=str(nowTS)
    localTimeString=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(nowTS)))
    TS['服務器時間']=str(localTimeString)
    gmtTimeString=time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(nowTS)))
    TS['GMT時間']=str(gmtTimeString)
    localTSToday=int(time.mktime(time.strptime(localTimeString[:10], '%Y-%m-%d')))
    TS['服務器今天時間戳']=str(localTSToday)
    print('服務器今天時間戳'+str(localTSToday))
    TS['GMT今天時間戳']=str(localTSToday+time.timezone)

    return TS

@app.route('/')
def hello_world():
    return 'Good luck!'

@app.route('/taskCms/service/getTS')
def checkTS():
    TS = getTS()


    return json.dump(TS)
            
if __name__ == '__main__':
#     app.debug = True
#     app.run(host='0.0.0.0',port=8080)
    app.run()
#此時執行
python emailApp1.py
#即可在本地http://127.0.0.1:5000/訪問到服務了。
#Ctrl+C關閉測試,新建nginx站點配置文件emailApp.conf
#nginx站點配置通常在/etc/nginx/conf.d
server {
        listen 8042;
        server_name 127.0.0.1;
        charset utf-8;

        location /  { try_files $uri @yourapplication; }
        location @yourapplication {
                include uwsgi_params;
                uwsgi_pass 127.0.0.1:3031;
        }
}
#測試nginx配置文件是否有誤
nginx -t
#重新加載nginx
nginx -s reload
#此時訪問你的ip加端口號8042,出現502 Bad Gateway則證明nginx已配置好
#若出現訪問超時則可能是有防火牆阻擋
#接下來在項目目錄下新建config.ini作為uwsgi的配置文件
[uwsgi]
socket = 127.0.0.1:3031
chdir = /root/42/pythons/emailApp
master = true
binary-path = /root/42/pythons/emailApp/bin/uwsgi
virtualenv = /root/42/pythons/emailApp
module = emailApp1:app
processes = 2
threads = 4
#使用uwsgi運行Flask程序
/root/42/pythons/emailApp/bin/uwsgi --ini /root/42/pythons/emailApp/config.ini
#如果遇到uwsgi: error while loading shared libraries: libpcre.so.1可嘗試
ln -s /usr/local/lib/libpcre.so.1 /lib64
#正常的話此時應該能通過8042訪問到服務
#開機啟動我使用的centos6自帶的Upstart
nano /etc/init/uwsgi.conf
# simple uWSGI script

description "uwsgi tiny instance"
start on runlevel [2345]
stop on runlevel [06]

respawn

exec /root/42/pythons/emailApp/bin/uwsgi --ini /root/42/pythons/emailApp/config.ini

最後可以通過screen執行uwsgi,然後退出服務器。這樣就完成了一個簡單Flask項目的搭建。Flask就是簡單快速。

如果是通過Upstart自動啟動的,可以通過initctl reload uwsgi和initctl restart uwsgi來重啟uwsgi。


Connection reset by peer鏈接被中斷

過了幾天發現接口不穩定,有時能正常返回數據,有時出現Connection reset by peer鏈接被中斷。從firebug里看發現數據返回有時是先返回個0,就是什麼也沒有然後真是數據才回來,這是瀏覽器已經報錯了。此時可嘗試在uwsgi配置中增加buffer-size=65535和post-buffering = 1。以及在nginx的conf中設置

http{
    ...
    keepalive_timeout  0;

    uwsgi_read_timeout 86400;
    uwsgi_send_timeout 86400;
    ....

}

Ubuntu16給python3.5安裝OpenCV3.2

過程略繁瑣,參考了Install OpenCV 3.0 and Python 3.4+ on Ubuntu。安裝完成可在python中import cv2.

#安裝依賴及工具
sudo apt-get install build-essential cmake git pkg-config
sudo apt-get install libjpeg8-dev libtiff4-dev libjasper-dev libpng12-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
sudo apt-get install libgtk2.0-dev
sudo apt-get install libatlas-base-dev gfortran
sudo apt-get install python3.5-dev

由於我已經有python3.5的virtualenv了,所以這里就不再說了,可以参考pip3为python3安装模块

#啓動python3.5的環境
source ~/pythons/p35/bin/activate
#安装numpy
pip install numpy -i https://pypi.douban.com/simple/
#下載並解壓OpenCV,github我克隆不下拉
cd ~
wget -O opencv.zip https://github.com/Itseez/opencv/archive/3.2.0.zip
unzip opencv.zip
wget -O opencv_contrib.zip https://github.com/Itseez/opencv_contrib/archive/3.2.0.zip
unzip opencv_contrib.zip
cd ~/opencv-3.2.0
mkdir build
cd build
#cmake中間如有終端,可參考錯誤提示直接從web下載相關文件放於提示位置
cmake -D CMAKE_BUILD_TYPE=RELEASE \
    -D CMAKE_INSTALL_PREFIX=/usr/local \
    -D INSTALL_PYTHON_EXAMPLES=ON \
    -D INSTALL_C_EXAMPLES=OFF \
    -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib-3.2.0/modules \
    -D PYTHON_EXECUTABLE=~/pythons/p35/bin/python \
    -D BUILD_EXAMPLES=ON ..
#成功執行後要留意python3的環境是否正確應有類似如下字樣
--   Python 3:
--     Interpreter:                 /home/42/pythons/p35/bin/python3 (ver 3.5.2)
--     Libraries:                   /usr/lib/x86_64-linux-gnu/libpython3.5m.so (ver 3.5.2)
--     numpy:                       /home/42/pythons/p35/lib/python3.5/site-packages/numpy/core/include (ver 1.12.0)
--     packages path:               lib/python3.5/site-packages
-- 
--   Python (for build):            /home/42/pythons/p35/bin/python3
#然後就可以編譯了
make -j$(nproc)
#編譯完成後執行安裝
sudo make install
sudo ldconfig
#查看是否安裝成功
ls -l /usr/local/lib/python3.5/site-packages/ | grep cv2
#成功的話應該會有文件出現類似
-rw-r--r-- 1 root staff 3550256 2月  17 20:36 cv2.cpython-35m-x86_64-linux-gnu.so
#把cv2關聯到python環境裏
cd ~/pythons/p35/lib/python3.5/site-packages/
ln -s /usr/local/lib/python3.5/site-packages/cv2.cpython-35m-x86_64-linux-gnu.so cv2.so
#查看是否可用
python
>>> import cv2
>>> cv2.__version__
'3.2.0'

Linux硬盤滿

如果重啟後無法進入桌面環境,很可能是硬盤滿了,此時按Ctrl+Alt+F2進入命令行模式。

#查看磁盤空間剩餘情況
df -hl
#如果確實是磁盤可用空間不足
#則查看是那個文件夾里有大文件,一般都是/tmp
cd /tmp
#以文件夾大小排序,顯示最大的15個
du -hsx * | sort -rh | head -15

釋放出200M空間就差不多可以進桌面環境了。

在頻繁使用selenium調用火狐的時候,/tmp中會出現打量類似tmpzujczqpd的文件夾,可以使用下面代碼進行刪除。

import glob,shutil
def rmFirefoxTmpFile():
    usage = shutil.disk_usage('/tmp')
    #如果磁盤可用空間小於1G則執行刪除
    if usage.free<1024*1024*1024*1:
        #火狐產生的文件夾大概長這樣
        files = glob.glob('/tmp/tmp????????')
    
        for f in files:
            #刪除最後修改時間10個小時以前的文件夾
            if time.time() - os.path.getmtime(f)>10*60*60 :
                shutil.rmtree(f,True)
            

matplotlib安裝使用

matplotlib是知名的繪圖庫,當我們需要製作圖表時就要使用它了。

#安裝matplotlib
pip install matplotlib
#使用matplotlib繪製一條直線並顯示
import matplotlib.pyplot as p
p.plot(range(20),range(20))
p.show()

如果matplotlib沒有顯示出圖像,而只顯示了[],很有可能是~/.matplotlib/matplotlibrc文件中的backend值設置不當,可嘗試修改為TkAgg或template。參考:matplotlib does not show my drawings although I call pyplot.show()。我用了virtualenv,matplotlibrc文件位於pythons/p3/lib/python3.5/site-packages/matplotlib/mpl-data/matplotlibrc。

python3字符串自增

週末喝恆大冰泉,發現掃二維碼中獎概率頗高,而且可以中獎金額直接用來給手機充值或提現到銀行卡,做的比較好。趁理髮無聊的時候寫了段python掃了一會兒,但是空手而歸。代碼也很簡單和用Python抓取大衆點評的用戶評論差不多,主要就是字符串自增這塊用了個遞歸:

from bs4 import BeautifulSoup import string,sys,time,random,urllib,http.cookiejar,socket #url="https://sao.so/t/dSTUVvjUhPHpz" baseDir="/storage/sdcard0/com.hipipal.qpyplus/scripts3/test/" base="_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" HDcode="dSTUVvjUhPIjL" bingoNo=0 failNo=0 def increase(s): sHead=s[0:-1] sFoot=s[-1:] sNew="" if(sFoot != "Z"): index=base.index(sFoot) sFootNew=base[index+1] sNew=sHead+sFootNew else: sHeadNew=increase(sHead) sFootNew="_" sNew=sHeadNew+sFootNew return sNew def getHTML(url): request = urllib.request.Request(url) request.add_header("User-Agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:37.0) Gecko/20100101 Firefox/37.0") try: response = urllib.request.urlopen(request) except (urllib.error.HTTPError, socket.error,urllib.error.URLError) as e: print('Connection error occurred when inserting data.'+str(e)) else: if response.code != 200: print("Error code:"+response.code) else: html = response.read().decode('utf-8') return html def check(html): global bingoNo global failNo #with open(baseDir+'expired.html',encoding='utf-8') as html: soup = BeautifulSoup(html) images = soup.find_all('img') for image in images: if "errorQrCode.jpg" in image.get('src') : failNo = failNo + 1 print("fake: " + HDcode + " " + str(failNo)) break elif "冰泉君已经失身啦" in soup.get_text(): print("expired" + HDcode) break else: print("bingo" + HDcode) bingoNo = bingoNo + 4 if __name__ == '__main__': #html=getHTML(url) #with open(baseDir+'fake.html', mode='w', encoding='utf-8') as html_file: #html_file.write(html) global HDcode while(bingoNo < 2): url = "https://sao.so/t/" + HDcode html = getHTML(url) check(html) HDcode = increase(HDcode) time.sleep(random.randrange(4,7)) [/code]

其實命中的概率真的非常低,拿13位編碼來說,一共有(11+26+26)^13=2.46*10^23種組合,瓶子上說中獎概率33.3%,按300億銷售目標和5元均價算,一共有2×10^10瓶是可以中獎的。除一下就發現……不用除了吧

Google Geocoding API好用

之前用qpython写了个小程序记录地理位置,反向地理编码(就是根据经纬度查询实际位置)用的是SL4A的Android模块,它就是调用底层谷歌的方法查询。但是现在一谷歌不稳定,二新手机没有装谷歌框架,所以完全无法反向地理编码。今天看了下谷歌的Geocoding API,用php转发了一下获取到的json,用起来就方便多了。而且谷歌的这个服务不用繁琐的验证,不限制客户端,甚至连帐号都不用,真是良心啊!当然由于“地理编码是一项既耗时又耗资源的任务”,所以每天发送的地理位置查询请求不得超过 2,500 个,这对于少量用户足够了。代码可以到右上角github里下载。

自动检查网页更新

需求:http://www.cnca.gov.cn/ywzl/gjgnhz/jkzl/这个网页会公布进口水产品境外生产企业注册名单,但公布日期不一定,所以想自动检查美国(2014年07月21日)这个条目是否更新了,如果更新了发邮件通知我。方法:获取网页,查看网页是否存在“美国(2014年07月21日)”若不存在则更新了。发邮件用PHPMailer的SMTP发送邮件很方便。

check.php

< ?php
ignore_user_abort();//关掉浏览器,PHP脚本也可以继续执行.
set_time_limit(0);//通过set_time_limit(0)可以让程序无限制的执行下去
$interval=60*60*10;//单位是秒,每10小时执行一次
do{
	$run = include 'config.php';
	if(!$run) die('process abort');
	
	$url = "http://www.cnca.gov.cn/ywzl/gjgnhz/jkzl/"; 
	$ch = curl_init(); 
	curl_setopt ($ch, CURLOPT_URL, $url); 
	curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1); 
	curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT,20); 
	$content = curl_exec($ch); 
	curl_close($ch); 
	$hasAutime=strpos($content,'美国(2014年07月21日'); 
	$hasAu=strpos($content,'美国');//防止没有下载到网页误触发,方法不可取
	
	 if (!$hasAutime && $hasAu){
	  require 'mail/mySendMail.php';
	  
	  $subject="内容有更新";
	  $body="内容有更新,请访问<a href='http://www.cnca.gov.cn/ywzl/gjgnhz/jkzl/'>http://www.cnca.gov.cn/ywzl/gjgnhz/jkzl/";
	  if(mySendMail("receiver@qq.com","name",$subject,$body)){
				 echo "有更新,已发送邮件提醒";
		 } else {
				 echo "有更新,邮件发送失败";
		 }
		 die('process abort');
	 } else {
		 echo "not modified";
	 }
	
	sleep($interval);
}while(true);
?>
Continue reading