Linux:配置SSL遇到的问题

问题是这样的

环境:Centos,Flask,Let’s Encrypt.

使用下面的方式,来安装SSL,发现在Wordpress程序上没有任何问题,而在安装Flask程序时,则出现了问题。具体往下看。

在Flask程序上申请SSL证书,出现下面的提示:

Failed authorization procedure.
The following errors were reported by the server

内容来自:https://www.freehao123.com/lets-encrypt/

问题已经解决了,用的是Certbot,我把我的方法贴一下:
首先要说明一下几点:
1.存在一个已经建立的虚拟主机
2.我用的是oneinstack
3.Python的版本是2.7以下(如果是2.7以上SSL证书会自动安装,不用手动的)
4.使用Certbot脚本
————-分界线————————————–
过程:
1.去Certbot的官网找到与web环境相应的脚本(官网qi姐已经贴出来了)
2.按照官网的步骤来:(这是CentOS6 ,Nginx的脚本,不要直接复制哦,要按照自己的情况来)
# wget https://dl.eff.org/certbot-auto
# chmod a+x certbot-auto
$ ./certbot-auto
——————-分界线———————–
然后Python版本低于2.7的服务器就会出现问题了
Certbot会报错,代码如下:
Installing Python packages…
Installation succeeded.
/root/.local/share/letsencrypt/lib/python2.6/site-packages/cryptography/__init__.py:26: DeprecationWarning: Python 2.6 is no longer supported by the Python core team, please upgrade your Python. A future version of cryptography will drop support for Python 2.6
DeprecationWarning
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Failed to find apachectl in PATH: /usr/local/nginx/sbin:/usr/local/php/bin:/usr/local/mysql/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
/root/.local/share/letsencrypt/lib/python2.6/site-packages/certbot/main.py:568: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
return e.message
Certbot doesn’t know how to automatically configure the web server on this system. However, it can still get a certificate for you. Please run “certbot-auto certonly” to do so. You’ll need to manually configure your web server to use the resulting certificate.
——————-分界线————————–
我们不用管它,因为他说了,你可以手动安装SSL,那我们就手动安装
——————-分界线——————————
输入命令:
# ./certbot-auto certonly
然后它依旧会报错,那我们依旧不管他
继续进行命令,因为我们是手动配置
——————–分界线——————————–
再输入上面的命令以后,会出现选项,一个是独立服务器,一个是web服务
我们选择1,web服务
它会要求我们输入email(可以不输入),那我们输入email
———————–分界线—————————–
接下来它会要求我们输入域名
输入域名
————————分界线—————————
然后它会要求我们给出域名所在的根目录
用的oneinstack的话就输入
/data/wwwroot/你的域名
————————-分界线———————–
返回如下代码,获得SSL 证书:
IMPORTANT NOTES:
– Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/ex.acgbuster.com/fullchain.pem. Your cert
will expire on 2017-05-02. To obtain a new or tweaked version of
this certificate in the future, simply run certbot-auto again. To
non-interactively renew *all* of your certificates, run
“certbot-auto renew”
– If you like Certbot, please consider supporting our work by: 
 
Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donate
Donating to EFF:
————————–分界线——————————-

众所周知,Flask的目录结构是:

Flask项目目录结构

在使用

./certbot-auto certonly

命令之后,如果输入的是/flaskxxx这个目录,那么就会生成红色框内的目录(Let’s Encrypt会在网站根目录生成一个目录里面会放一个验证程序[类似于验证文件],随后程序会进行访问相关地址进行匹配),用过Flask的都知道,这个红色的目录肯定是不对的(Flask一般读取templates目录下面的文件)。

所以,在Flask上申请SSL的时候,就遇到了这个问题。

我们只能从侧面去解决这个问题。

Linux+Nginx+PHP+MySQL

解决方案

在你的Flask文件中加入下面的代码,然后再次执行

./certbot-auto certonly

就可以实现验证,也就可以申请到SSL证书了。

2017.5.15更新:当文件不存在时,不显示详细路径(加入try/except处理).

from flask import make_response
import os

@app.route('/.well-known/acme-challenge/<checkinfo>')
def checkSSL(checkinfo):
    base_dir = os.path.dirname(__file__)
    checkinfo = 'templates/.well-known/acme-challenge/'+checkinfo
    try:
        resp = make_response(open(os.path.join(base_dir,checkinfo)).read())
        return resp
    except IOError as err:
        return 'File Error'
    return 'hi'

修改Python文件之后,如果使用的是uwsgi+nginx架构,只需要重启uwsgi即可.

ps -ef | grep uwsgi
root      9977     1  0 19:41 ?        00:00:00 uwsgi -x xxx.xml -d uwsgi.log --pidfile /tmp/uwsgi.pid
kill -9 9977
# 9977 是程序的进程号.
# 在下面再次运行uwsgi即可.

折腾一下午这个问题……

另外,下午将目前的几个站全都升级了SSL。只是遗憾的是,国内的淘宝联盟不支持SSL,代码只能显示空白了。(百度统计,CNZZ都支持SSL,而51LA目前还不支持SSL),还好GG支持SSL,直接就可以用了。

Python:清除文件内容

问题

在Linux或者Windows服务器下面(当然,个人电脑可能也存在此问题),有时候系统运行时间长了,会存在很多日志文件(或者其它缓存文件)。而这些文件,可能在不同的目录中。当然,这时,也可以直接删除相关日志文件和目录,那么这样会导致一个问题——程序可能会因为找不到日志目录而报错。因此,想到一个更简单的办法:

只清除指定目录下面的所有文件的内容(但还是要注意配置目录,数据无价),而不对目录、文件进行删改(只清除文件内容)操作。

python Logo

源码

**********数据无价,请谨慎操作*********
*********针对程序的使用,不承担任何责任***********

请注意以下几点:

  1. 程序需要配置需要清除的目录(请谨慎配置)、日志文件(默认当前目录)地址
  2. 程序基于Python3(我使用Python3.6)
  3. 程序提供日志功能,可自行修改相关代码配置格式.

源码如下:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import os
from pathlib import Path
from datetime import datetime,timedelta
import time
import io

'''

-- 数据无价,请谨慎使用.

Python3 清空文件内容.

主要用于:清除服务器或网站的日志文件.
此程序不会执行任何删除操作,但会清除数据日志记录.

程序自带日志记录.
默认日志记录在当前文件夹下面.

-- 请谨慎使用.

author:prd.
date:2017-02-17 v0.1
Python Version:3.6

'''

def formatDateToStr(dateTimeValue=datetime.now(),formatv='%Y-%m-%d %H:%M:%S'):
        return dateTimeValue.strftime(formatv)

if __name__ == '__main__':
	print("先配置在使用.*********数据无价,谨慎操作**********")
	exit(0)
	# 日志文件名称,默认当前目录
	logPath = "delloginfo.log"
	'''

	数据无价,谨慎操作

	*:配置需要清除的目录,可配置多个.

	'''
	pathList =["/var/log"]
	delFileLog = []
	for path in pathList:
		for root, dirs, files in os.walk(path, topdown=False):
			for name in files:
				delFileLog.append('[{0}]&&[{1}]  clear file content.\n'.format(formatDateToStr(),os.path.join(root,name)))
				p = Path(os.path.join(root, name))
				p.write_text('')
	logW = Path(logPath)
	# 如果日志文件不存在,则新创建.
	if not logW.exists():
		logW.touch()
	# 日志文件大小.
	# 单位为整数M.
	logFileSize = logW.stat().st_size//1024//1024
	if logFileSize>=5:
		# 当日志文件大小超过5M时,清空日志文件内容.
		# 之后在写入.
		logW.write_text('')
	# 记录日志文件数据.
	with logW.open(mode='a') as f:
		f.write(''.join(delFileLog))

Linux 定时任务参考:

5 * * * * ls 指定每小时的第5分钟执行一次ls命令
30 5 * * * ls 指定每天的 5:30 执行ls命令
30 7 8 * * ls 指定每月8号的7:30分执行ls命令
30 5 8 6 * ls 指定每年的6月8日5:30执行ls命令
30 6 * * 0 ls 指定每星期日的6:30执行ls命令[注:0表示星期天,1表示星期1,

以此类推,也可以用英文来表示,sun表示星期天,mon表示星期一等。]

30 3 10,20 * * ls 每月10号及20号的3:30执行ls命令[注:“,”用来连接多个不连续的时段]

25 8-11 * * * ls 每天8-11点的第25分钟执行ls命令[注:“-”用来连接连续的时段]

*/15 * * * * ls 每15分钟执行一次ls命令 [即每个小时的第0 15 30 45 60分钟执行ls命令 ]

30 6 */10 * * ls 每个月中,每隔10天6:30执行一次ls命令[即每月的1、11、21、31日是的6:30执行一次ls 命令。 ]

每天7:50以root 身份执行/etc/cron.daily目录中的所有可执行文件

50 7 * * * root run-parts /etc/cron.daily [ 注:run-parts参数表示,执行后面目录中的所有可执行文件。 ]

Python:抓取One每天一句话作为随机名言

在很多年前…

我以前看到过不少随机名言,但是碍于当时没有技术不会做,虽然很喜欢.但是也不知道怎么去实现.还好现在技术可以实现,而且也有一个比较好的平台.提供了每天一句话.刚好就用来作名言的数据源了.[地址]

如果要查看效果,可以在页面底部看到相应效果(每次刷新显示的内容都不一样).

还需要…

因为使用了Python的两个库,因此必须安装:requests,BeautifulSoup.这两个库.

安装如下:

1
2
pip install requests
pip install beautifulsoup4

安装之后,就可以使用了.

python Logo
image-2482

简单说一下…

首先,这个程序并没有做到非常”智能”,有些地方使用了print(大概是两个地方).因此,你需要自行复制到某个地方,在继续…..

简单说一下核心的一个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def _getMessage(self):
        messagedata = {}
        for x in range(self.start_index,self.end_index):
            url = 'http://wufazhuce.com/one/%d'
            print("%d--------&amp;gt;正在执行......" % (x))
            r = requests.get(url % (x))
            soup = BeautifulSoup(r.text,"html.parser")
            if soup and soup.select(".one-cita"):
                #print()
                message = (str(soup.select(".one-cita")[0].contents[0])).strip()
                if message:
                    messagedata[str(x)]=message
            soup = None
            r = None
            url = None
        print(messagedata)
        print(len(messagedata))

没错上面这个就是核心函数了,

  1. 首先使用了for循环对数据进行循环读取(self.start_index,self.end_index分别是开始的期号和结束的期号,可以自己设定,具体要看源码(源码在下面)..).
  2. 定义了一个messagedata的dict,dict的key存的是相应期号,value存的是名言内容.(好像这一句才是第一步…)
  3. 在循环中,动态定义url,并且使用了requests第三方库进行网页的获取网页内容.[关于requests]
  4. 拿到内容之后,基本就放心了.
  5. 然后使用了BeautifulSoup对HTML进行解析,话说……BeautifulSoup是个很神奇,很厉害,很霸气的HTML解析库..(反正,正反就是很厉害)
  6. 使用了Python自带的HTML解析引擎,”html.parser”,也有很多第三方的可选.[关于BeautifulSoup]
  7. 这一句可能是最复杂的,message = (str(soup.select(“.one-cita”)[0].contents[0])).strip(),这一句首先是从soup对象中select了class=”.one-cita”的div的数据(select函数是BeautifulSoup提供的使用HTML的class方式选取内容,这一点就方便了很多,select返回的是list,因此使用了[0]获取第一个,跟着使用contents来获取其中的内容,contents继续返回list,接着继续获取[0]),获取到数据之后,str函数将其转换为str类型,并且使用strip()函数对其特殊符号(比如:\t,\n,空格)这些进行清理.返回一个干干净净的文本..OYeah.
  8. 然后就是将期号作为key,名言内容作为value放到dict里面.
  9. 说完了.

源码

源码使用如下:

必须安装requests和BeautifulSoup这两个库,否则..运行不了.

使用步骤如下:

懒得写了,直接看源码里面的吧.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#-*- coding=utf-8 -*-
import os
import requests
import time
from bs4 import BeautifulSoup

'''
通过Python的dict生成JavaScript的数组.


'''
class GeneratorJsArray(object):

    def main(self):
                # 内容太多,删掉一堆.
        message = {'26': '跟我去北方吧,逃离爱情的肤浅,南方的江山太妩媚,腐蚀了我的热血。from 左小祖咒《爱情的枪》', '776': '到死之前,我们都是需要发育的孩子,从未长大,也从未停止生长。就算改变不了这个世界,这个世界也别想将我们改变。by 大冰', '275': '青春就是不停地告别,告别就是死亡一点点。by 赵西栋', '30': '很高兴又见到你。by 韩寒', '78': '我不知道庆典之后的日子该怎么过。 by 村上龙', '264': '只有不快乐的人才想知道未来。by 凯特·莫顿', '58': '即使头上长出鹿角,口琴的魔力依然无法停止。今日宜留齐刘海,忌独立小桥。by 张冠仁'}
        print("var mingyan=new Array();")
        for key,value in message.items():
            print("mingyan.push("{\'index\':%d,\'content\':'%s'}");" % (int(key),value))



'''
抓取One的名言.

'''
class One(object):

    def __init__(self):
        self.start_index = 14
        self.end_index = 1384

    def _getMessage(self):
        messagedata = {}
        for x in range(self.start_index,self.end_index):
            url = 'http://wufazhuce.com/one/%d'
            print("%d--------&gt;正在执行......" % (x))
            r = requests.get(url % (x))
            soup = BeautifulSoup(r.text,"html.parser")
            if soup and soup.select(".one-cita"):
                #print()
                message = (str(soup.select(".one-cita")[0].contents[0])).strip()
                if message:
                    messagedata[str(x)]=message
            soup = None
            r = None
            url = None
        print(messagedata)
        print(len(messagedata))

    def main(self):
        print("1.先使用我......:")
        #self._getMessage()

if __name__ == '__main__':
        # 1.先使用One的main函数获取输出结果.
        # 2.将输出结果复制出来,注意是复制...
        # 3.粘贴给GeneratorJsArray类的main函数的message变量......
        # 4.注释掉One的调用.
        # 5.调用GeneratorJsArray类的main函数获取js的输出.
        # 6.新建一个js文件,把刚才输出的结果粘贴进去.
        # 7.搞定.
    gj = GeneratorJsArray()
    gj.main()

另外,我已经生成了一个了.可以直接用的.

调用方式,将下面的内容保存成mingyan.js,然后在页面中创建一个<p id=”showMingyan”></p>,然后使用js:$(“#showMingYan”).html(getMingYanHref());进行调用即可.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
  随机获取名言.

  author:prd.
  version:2016.7.22
  note:名言均来自[一个](http://www.wufazhuce.com)

  使用示例(关于使用的调用,请参考最底部的函数.):
        1.先引入本js.
        2.在想使用的地方,调用getMingYan()函数即可获取名言.[getMingYanHref()获取可以跳转至One的名言,getMingYanContent():只获取名言内容]
        3.名言中存储为json数据,index对应One的每一期号,content是名言.
        4.请尊重版权,在展示名言的同时,可将名言链接至One.例如:&lt;a href="http://wufazhuce.com/one/14"&gt;是狼是人,日久见心。by 小饭&lt;/a&gt;其中的14为期号.
*/
var mingyan=new Array();
mingyan.push("{'index':1165,'content':'失眠就像是,一个无人认领的梦,一段言无所向的人生,和一场明知故犯的恋情。你不愿这些发生,但你也清楚这些早晚要发生,就像终于盼来了困意,却也迎来了黎明。by 郑执'}");
mingyan.push("{'index':1212,'content':'道路虽然拥挤,却是寂寞的,因为它不是被爱的。 from 《像个孩子》'}");
mingyan.push("{'index':563,'content':'如果我不想被悲伤和怀疑打倒,就非得好好吃饭不可。by 方悄悄'}");
mingyan.push("{'index':1291,'content':'每个人都是孤独发光的星体,至亲、爱人、朋友,构成了我们的星系。星辰会陨落,轨道会迁移,或许再也见不到你。我会记得,你的光芒温暖过我的眼睛。而我,也曾闪耀在你的夜空里。 by 路明'}");
mingyan.push("{'index':855,'content':'我觉得世界上所有事情都在你没有准备好的时候,就开始;在你准备好的时候,就结束了。from《年华似水》'}");
mingyan.push("{'index':1068,'content':'天青色等烟雨,而我在等你。by 方文山'}");
mingyan.push("{'index':435,'content':'不能一直踮着脚爱一个人,重心不稳,撑不了太久的。by 佚名'}");
mingyan.push("{'index':342,'content':'没有深夜痛哭过的人,不足以谈人生。by 高秉涵'}");
mingyan.push("{'index':918,'content':'毁掉我们的不是我们所憎恨的东西,而恰恰是我们所热爱的东西。by 尼尔·波兹曼'}");
mingyan.push("{'index':1258,'content':'信任这种东西有时候挺奇怪的,就是那种你在我背后开了一枪,我依然觉得是枪走了火的感觉。by 暖小团'}");
mingyan.push("{'index':889,'content':'原来生命从头到尾都是一场浪费,你需要判断的仅仅在于,这次浪费是否是“美好”的。后来,当我每做一件事情的时候,我便问自己,你认为它是美好的吗?如果是,那就去做吧,从这里出发,我们去抵抗命运,享受生活。by 吴晓波'}");
mingyan.push("{'index':449,'content':'世上只有一种真正的英雄主义,那就是认清生活的真相后依然热爱生活。by 罗曼·罗兰'}");
mingyan.push("{'index':1164,'content':'有时候我们认为生活背叛了我们,但是很久以后我们才发现,其实是我们自己背叛了自己。 from 《西伯利亚的理发师》'}");
mingyan.push("{'index':717,'content':'所有的悲伤,总会留下一丝欢乐的线索。所有的遗憾,总会留下一处完美的角落。我在冰封的深海,找寻希望的缺口。却在午夜惊醒时,蓦然瞥见绝美的月光。from 《缺口》'}");
mingyan.push("{'index':1279,'content':'不管怎么费尽心力,人会受伤的时候就会受伤。by 村上春树'}");
mingyan.push("{'index':913,'content':'有人说:真正的爱情,背后没有秘密。说这话的人,既不明白爱情,也不明白秘密。from《北京乐与路》'}");
// ... 部分数据.

/**
    随机获取名言.

    直接调用此函数即可.
*/
function getMingYan(){
  return (mingyan[parseInt(Math.random()*(mingyan.length-1)+1)]);
}

/*
  获取名言,并链接至One.
*/
function getMingYanHref(){
  var item = getItem();
  return "&lt;a href='http://wufazhuce.com/one/"+item.index+"' target='_blank'&gt;"+item.content+"&lt;/a&gt;";
}

function getItem(){
  return eval('(' +(mingyan[parseInt(Math.random()*(mingyan.length-1)+1)])+ ')');
}

/*
  只获取内容.
*/
function getMingYanContent(){
  var item = getItem();
  return item['content'];
}

到此.

Python:简单操作一下SQLite3

SQLite3

关于SQLite,下面引用:

SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月。 至2015年已经有15个年头,SQLite也迎来了一个版本 SQLite 3已经发布。[更多]

以下引用自网络:

SQLite3 可使用 sqlite3 模块与 Python 进行集成。sqlite3 模块是由 Gerhard Haring 编写的。它提供了一个与 PEP 249 描述的 DB-API 2.0 规范兼容的 SQL 接口。您不需要单独安装该模块,因为 Python 2.5.x 以上版本默认自带了该模块。
为了使用 sqlite3 模块,您首先必须创建一个表示数据库的连接对象,然后您可以有选择地创建光标对象,这将帮助您执行所有的 SQL 语句。[更多]

其实,上面这一堆,只是说明:Python 2.5+的版本,自带了SQLite.你可以直接使用!

python Logo
image-2438

简单工具

抽了一小会时间,简单写了个工具,只是简单封装了一下增删改查.在文件下面有示例,使用Python 3.5.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/env python3
#! -*-coding=utf-8-*-

import sqlite3

'''


专注操作SQLite3.


-- SQLite3,方便.

@py-version 3.5
@version 2016.4.10
@author prd.

@version --> 0.1 初始.

'''
class SQLite3Tools(object):

    # 获取数据库
    def getDB(self):
        if not self.dbconn: # 如果还未赋值,则直接给一个
            self.dbconn = sqlite3.connect(self.dbFileName)
            return sqlite3.connect(self.dbFileName)
        else: # 已经赋值则直接返回.
            return self.dbconn
   
    # 关闭数据库连接.
    def closeDB(self):
        self.dbconn.close()
        self.dbconn = None

    # 工具入口函数getDB()
    def main(self,dbFileName):
        self.dbFileName = dbFileName
        self.dbconn = None

    # 执行:创建表
    def createTable(self,sql):
        self.getDB().execute(sql)
        self.closeDB()

    '''
    执行:插入数据

    @sql :可以为list类型(其中每个项均为str格式的sql语句)
          也可以为str类型.
    '''
    def insert(self,sql):
        if isinstance(sql,list):
            for xsqlitem in sql:
                self.getDB().execute(xsqlitem)
        else:
            self.getDB().execute(sql)
        self.getDB().commit()
        self.closeDB()

    # 执行:查询数据
    def select(self,sql):
        cursor = self.getDB().execute(sql)
        resultDict = cursor
        self.closeDB()
        return resultDict

    # 执行:更新或删除.
    def updateOrDelete(self,sql):
        print(self.getDB())
        self.getDB().execute(sql)
        print(self.getDB())
        self.getDB().commit()
        print(self.getDB())
        result = self.getDB().total_changes
        print(result)
        self.closeDB()
        return result

if __name__ == '__main__':
    print("仅用作演示,供参考.~")
    # 先获取实例
    # tools = SQLite3Tools()
   
    # 传入数据库文件路径.
    # tools.main("test.db")

    # 创建表.
    # tools.createTable('''
    # CREATE TABLE COMPANY
    #        (ID INT PRIMARY KEY     NOT NULL,
    #        NAME           TEXT    NOT NULL,
    #        AGE            INT     NOT NULL,
    #        ADDRESS        CHAR(50),
    #        SALARY         REAL);
    #       ''')
    # 创建表.END.

    # 单条插入.
    #sqllist = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (1, 'Paul', 32, 'California', 20000.00 )"
    #tools.insert(sqllist)
    # END.

    # 多条插入.
    # sqllist = ["INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (2, 'Allen', 25, 'Texas', 15000.00 )",\
    #   "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)    VALUES (3, 'Teddy', 23, 'Norway', 20000.00 )",\
    #   "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)   VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 )"]
    # tools.insert(sqllist)
    # END.

    # 查询
    # sqlselect = '''SELECT id, name, address, salary  from COMPANY'''
    # for x in tools.select(sqlselect):
    #   print(x)   
    # 查询END.

    # 更新
    # updatesql = "UPDATE COMPANY set NAME = 'wzretffgf' where ID=1 ;"
    # tools.updateOrDelete(updatesql)
    # 更新END.

    # 删除
    # updatesql = "DELETE FROM COMPANY  where ID=1 ;"
    # tools.updateOrDelete(updatesql)
    # 删除END.

    # 查询
    # sqlselect = '''SELECT id, name, address, salary  from COMPANY'''
    # for x in tools.select(sqlselect):
    #   print(x)   
    # 查询END.

Flask:在Centos上配置两个Flask项目

源于

一开始我是只有一个项目的,非常好配置,而且也简单。但是后来发现,又有一个新项目需要新增上去。结果配置搞了好几天,今天终于搞定。(在网上的提问

其实精髓很简单,配置两个类似的就行,端口,日志文件,项目路径分开就行。

在这里不谈如何安装环境,关于安装环境可以参考(地址)。

Python flask
image-2417

开始操作

这里使用:Nginx + Uwsgi + virtualenv 进行配置操作.

首先是要配置Nginx,那么安装好之后,Nginx一般是在/usr/local/nginx这个目录下面,配置文件则在/usr/local/nginx/conf下面,因为我们需要配置多个站点,因此需要新建/usr/local/nginx/conf/vhost目录,然后把相关文件放在这个目录下面即可.

首先看nginx.conf的文件[/usr/local/nginx/conf/nginx.conf]:
下面这个配置文件基本只是改动了几个地方,第一行需要注意,这是使用www用户进行操作.所以需要新建用户.另外就是
include /usr/local/nginx/conf/vhost/*.conf;很关键,这一行表示加载vhost目录下面所有conf结尾的文件(在Nginx上配置子站点就是这样操作的).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
user  www;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
include   /usr/local/nginx/conf/vhost/*.conf;
}

下面是子站点A的conf[目录:/usr/local/nginx/conf/vhost/A.conf]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 server {
        listen       80;
        server_name  A;
        #charset koi8-r;
        access_log  /var/www/venv/logs/access.log;
        error_log  /var/www/venv/logs/error.log;

        location / {
            include        uwsgi_params; # 引入
            uwsgi_pass     127.0.0.1:3031;# 监听端口,此处不同
            uwsgi_param UWSGI_PYHOME /var/www/venv/A;# 项目根目录,此处不同
            uwsgi_param UWSGI_CHDIR  /var/www/venv;# venv虚拟根目录
            uwsgi_param UWSGI_SCRIPT main:app; # 启动文件和Flask实例名称(通常都是app)
        }
    }

下面是子站点B的conf[目录:/usr/local/nginx/conf/vhost/B.conf]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 server {
        listen       80;
        server_name  A;
        #charset koi8-r;
        access_log  /var/www/venv/logs/access.log;
        error_log  /var/www/venv/logs/error.log;

        location / {
            include        uwsgi_params; # 引入
            uwsgi_pass     127.0.0.1:8081;# 监听端口,此处不同
            uwsgi_param UWSGI_PYHOME /var/www/venv/B;# 项目根目录,此处不同
            uwsgi_param UWSGI_CHDIR  /var/www/venv;# venv虚拟根目录
            uwsgi_param UWSGI_SCRIPT main:app; # 启动文件和Flask实例名称(通常都是app)
        }
    }

配置文件都搞定之后,新建/var/www/venv目录,使用mkdir /var/www/venv -p.之后virtualenv A 创建虚拟环境A,完成之后,virtualenv B创建虚拟环境B.都依次创建完之后,分别在项目根目录[就是A,B两个目录]里面新建一个main.py文件.

切换到A目录,使用cd A .

main.py[目录:/var/www/venv/A]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python3
# coding=utf-8
# -*-coding:utf-8-*-

from flask import Flask


app = Flask(__name__)


@app.route('/')
def show():
    return "A.............."


if __name__ == '__main__':
    app.run()

之后需要创建一个xml配置文件,指出如何初始化A项目.
文件:app_config.xml[目录:/var/www/venv/A/]
下面的文件不能有空格,切记切记!!!

1
2
3
4
5
6
7
8
9
<uwsgi>
<pythonpath>/var/www/venv/A</pythonpath>
<module>main</module>
<callable>app</callable>
<socket>127.0.0.1:3031</socket>
<master/>
<processes>4</processes>
<memory-report/>
</uwsgi>

至此,A项目创建完成.

接着来B项目.切换到B目录,使用cd ../B

main.py[目录:/var/www/venv/B]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python3
# coding=utf-8
# -*-coding:utf-8-*-

from flask import Flask


app = Flask(__name__)


@app.route('/')
def show():
    return "B.............."


if __name__ == '__main__':
    app.run()

之后需要创建一个xml配置文件,指出如何初始化B项目.
文件:app_config.xml[目录:/var/www/venv/B/]
下面的文件不能有空格,切记切记!!!

1
2
3
4
5
6
7
8
9
<uwsgi>
<pythonpath>/var/www/venv/B</pythonpath>
<module>main</module>
<callable>app</callable>
<socket>127.0.0.1:8081</socket>
<master/>
<processes>4</processes>
<memory-report/>
</uwsgi>

至此,B项目创建完成.

都搞定之后,可以写一个启动脚本.
如下[startserver.sh]:

1
2
3
4
5
6
7
#!/bin/bash
# Startup script for the nginx Web Server
# ?P.~J?wsgi
/usr/local/python3.4/bin/uwsgi -x /var/www/venv/A/app_config.xml -d /var/log/uwsgi/uwsgiA.log --pidfile /tmp/uwsgiA.pid
/usr/local/python3.4/bin/uwsgi -x /var/www/venv/B/app_config.xml -d /var/log/uwsgi/uwsgiB.log --pidfile /tmp/uwsgiB.pid
# 启动nginx
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf

之后使用chmod +x startserver.sh 即可启动.

总结

一共使用了如下目录或文件:

Nginx

服务器配置文件:
/usr/local/nginx/conf/nginx.conf
/usr/local/nginx/conf/vhost/A.conf
/usr/local/nginx/conf/vhost/B.conf

Flask

项目文件[项目中还有其它自动生成的文件,忽略不计]:
/var/www/venv/A/app_config.xml
/var/www/venv/A/main.py
/var/www/venv/B/main.py
/var/www/venv/B/app_config.xml

之后就是启动脚本了,可以放在你想放的地方,比如/pyscript/startserver.sh,到此,大功告成!

参考: