更新了部分文档和代码
|
@ -1,93 +1,101 @@
|
|||
from turtle import*
|
||||
"""
|
||||
绘制小猪佩奇
|
||||
"""
|
||||
from turtle import *
|
||||
|
||||
|
||||
def nose(x,y):#鼻子
|
||||
penup()#提起笔
|
||||
goto(x,y)#定位
|
||||
pendown()#落笔,开始画
|
||||
setheading(-30)#将乌龟的方向设置为to_angle/为数字(0-东、90-北、180-西、270-南)
|
||||
begin_fill()#准备开始填充图形
|
||||
a=0.4
|
||||
def nose(x,y):
|
||||
"""画鼻子"""
|
||||
penup()
|
||||
# 将海龟移动到指定的坐标
|
||||
goto(x,y)
|
||||
pendown()
|
||||
# 设置海龟的方向(0-东、90-北、180-西、270-南)
|
||||
setheading(-30)
|
||||
begin_fill()
|
||||
a = 0.4
|
||||
for i in range(120):
|
||||
if 0<=i<30 or 60<=i<90:
|
||||
a=a+0.08
|
||||
left(3) #向左转3度
|
||||
forward(a) #向前走a的步长
|
||||
if 0 <= i < 30 or 60 <= i <90:
|
||||
a = a + 0.08
|
||||
# 向左转3度
|
||||
left(3)
|
||||
# 向前走
|
||||
forward(a)
|
||||
else:
|
||||
a=a-0.08
|
||||
a = a - 0.08
|
||||
left(3)
|
||||
forward(a)
|
||||
end_fill()#填充完成
|
||||
|
||||
end_fill()
|
||||
penup()
|
||||
setheading(90)
|
||||
forward(25)
|
||||
setheading(0)
|
||||
forward(10)
|
||||
pendown()
|
||||
pencolor(255,155,192)#画笔颜色
|
||||
# 设置画笔的颜色(红, 绿, 蓝)
|
||||
pencolor(255, 155, 192)
|
||||
setheading(10)
|
||||
begin_fill()
|
||||
circle(5)
|
||||
color(160,82,45)#返回或设置pencolor和fillcolor
|
||||
color(160, 82, 45)
|
||||
end_fill()
|
||||
|
||||
penup()
|
||||
setheading(0)
|
||||
forward(20)
|
||||
pendown()
|
||||
pencolor(255,155,192)
|
||||
pencolor(255, 155, 192)
|
||||
setheading(10)
|
||||
begin_fill()
|
||||
circle(5)
|
||||
color(160,82,45)
|
||||
color(160, 82, 45)
|
||||
end_fill()
|
||||
|
||||
|
||||
def head(x,y):#头
|
||||
color((255,155,192),"pink")
|
||||
def head(x, y):
|
||||
"""画头"""
|
||||
color((255, 155, 192), "pink")
|
||||
penup()
|
||||
goto(x,y)
|
||||
setheading(0)
|
||||
pendown()
|
||||
begin_fill()
|
||||
setheading(180)
|
||||
circle(300,-30)
|
||||
circle(100,-60)
|
||||
circle(80,-100)
|
||||
circle(150,-20)
|
||||
circle(60,-95)
|
||||
circle(300, -30)
|
||||
circle(100, -60)
|
||||
circle(80, -100)
|
||||
circle(150, -20)
|
||||
circle(60, -95)
|
||||
setheading(161)
|
||||
circle(-300,15)
|
||||
circle(-300, 15)
|
||||
penup()
|
||||
goto(-100,100)
|
||||
goto(-100, 100)
|
||||
pendown()
|
||||
setheading(-30)
|
||||
a=0.4
|
||||
a = 0.4
|
||||
for i in range(60):
|
||||
if 0<=i<30 or 60<=i<90:
|
||||
a=a+0.08
|
||||
if 0<= i < 30 or 60 <= i < 90:
|
||||
a = a + 0.08
|
||||
lt(3) #向左转3度
|
||||
fd(a) #向前走a的步长
|
||||
else:
|
||||
a=a-0.08
|
||||
a = a - 0.08
|
||||
lt(3)
|
||||
fd(a)
|
||||
end_fill()
|
||||
|
||||
|
||||
def ears(x,y): #耳朵
|
||||
color((255,155,192),"pink")
|
||||
def ears(x,y):
|
||||
"""画耳朵"""
|
||||
color((255, 155, 192), "pink")
|
||||
penup()
|
||||
goto(x,y)
|
||||
goto(x, y)
|
||||
pendown()
|
||||
begin_fill()
|
||||
setheading(100)
|
||||
circle(-50,50)
|
||||
circle(-10,120)
|
||||
circle(-50,54)
|
||||
circle(-50, 50)
|
||||
circle(-10, 120)
|
||||
circle(-50, 54)
|
||||
end_fill()
|
||||
|
||||
penup()
|
||||
setheading(90)
|
||||
forward(-12)
|
||||
|
@ -96,14 +104,15 @@ def ears(x,y): #耳朵
|
|||
pendown()
|
||||
begin_fill()
|
||||
setheading(100)
|
||||
circle(-50,50)
|
||||
circle(-10,120)
|
||||
circle(-50,56)
|
||||
circle(-50, 50)
|
||||
circle(-10, 120)
|
||||
circle(-50, 56)
|
||||
end_fill()
|
||||
|
||||
|
||||
def eyes(x,y):#眼睛
|
||||
color((255,155,192),"white")
|
||||
def eyes(x,y):
|
||||
"""画眼睛"""
|
||||
color((255, 155, 192), "white")
|
||||
penup()
|
||||
setheading(90)
|
||||
forward(-20)
|
||||
|
@ -113,7 +122,6 @@ def eyes(x,y):#眼睛
|
|||
begin_fill()
|
||||
circle(15)
|
||||
end_fill()
|
||||
|
||||
color("black")
|
||||
penup()
|
||||
setheading(90)
|
||||
|
@ -124,8 +132,7 @@ def eyes(x,y):#眼睛
|
|||
begin_fill()
|
||||
circle(3)
|
||||
end_fill()
|
||||
|
||||
color((255,155,192),"white")
|
||||
color((255, 155, 192), "white")
|
||||
penup()
|
||||
seth(90)
|
||||
forward(-25)
|
||||
|
@ -135,7 +142,6 @@ def eyes(x,y):#眼睛
|
|||
begin_fill()
|
||||
circle(15)
|
||||
end_fill()
|
||||
|
||||
color("black")
|
||||
penup()
|
||||
setheading(90)
|
||||
|
@ -148,8 +154,9 @@ def eyes(x,y):#眼睛
|
|||
end_fill()
|
||||
|
||||
|
||||
def cheek(x,y):#腮
|
||||
color((255,155,192))
|
||||
def cheek(x,y):
|
||||
"""画脸颊"""
|
||||
color((255, 155, 192))
|
||||
penup()
|
||||
goto(x,y)
|
||||
pendown()
|
||||
|
@ -159,35 +166,39 @@ def cheek(x,y):#腮
|
|||
end_fill()
|
||||
|
||||
|
||||
def mouth(x,y): #嘴
|
||||
color(239,69,19)
|
||||
def mouth(x,y):
|
||||
"""画嘴巴"""
|
||||
color(239, 69, 19)
|
||||
penup()
|
||||
goto(x,y)
|
||||
goto(x, y)
|
||||
pendown()
|
||||
setheading(-80)
|
||||
circle(30,40)
|
||||
circle(40,80)
|
||||
circle(30, 40)
|
||||
circle(40, 80)
|
||||
|
||||
|
||||
def setting(): #参数设置
|
||||
def setting():
|
||||
"""设置参数"""
|
||||
pensize(4)
|
||||
hideturtle() #使乌龟无形(隐藏)
|
||||
colormode(255) #将其设置为1.0或255.随后 颜色三元组的r,g,b值必须在0 .. cmode范围内
|
||||
color((255,155,192),"pink")
|
||||
setup(840,500)
|
||||
# 隐藏海龟
|
||||
hideturtle()
|
||||
colormode(255)
|
||||
color((255, 155, 192), "pink")
|
||||
setup(840, 500)
|
||||
speed(10)
|
||||
|
||||
|
||||
def main():
|
||||
setting() #画布、画笔设置
|
||||
nose(-100,100) #鼻子
|
||||
head(-69,167) #头
|
||||
ears(0,160) #耳朵
|
||||
eyes(0,140) #眼睛
|
||||
cheek(80,10) #腮
|
||||
mouth(-20,30) #嘴
|
||||
"""主函数"""
|
||||
setting()
|
||||
nose(-100, 100)
|
||||
head(-69, 167)
|
||||
ears(0, 160)
|
||||
eyes(0, 140)
|
||||
cheek(80, 10)
|
||||
mouth(-20, 30)
|
||||
done()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main()
|
||||
|
|
|
@ -7,38 +7,38 @@
|
|||
1. 1989年圣诞节:Guido von Rossum开始写Python语言的编译器。
|
||||
2. 1991年2月:第一个Python编译器(同时也是解释器)诞生,它是用C语言实现的(后面又出现了Java和C#实现的版本Jython和IronPython,以及PyPy、Brython、Pyston等其他实现),可以调用C语言的库函数。在最早的版本中,Python已经提供了对“类”,“函数”,“异常处理”等构造块的支持,同时提供了“列表”和“字典”等核心数据类型,同时支持以模块为基础的拓展系统。
|
||||
3. 1994年1月:Python 1.0正式发布。
|
||||
4. 2000年10月16日:Python 2.0发布,增加了实现完整的[垃圾回收](https://zh.wikipedia.org/wiki/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6_(%E8%A8%88%E7%AE%97%E6%A9%9F%E7%A7%91%E5%AD%B8)),并且支持[Unicode](https://zh.wikipedia.org/wiki/Unicode)。与此同时,Python的整个开发过程更加透明,社区对开发进度的影响逐渐扩大,生态圈开始慢慢形成。
|
||||
5. 2008年12月3日:Python 3.0发布,此版不完全兼容之前的Python代码,不过很多新特性后来也被移植到旧的Python 2.6/2.7版本,因为目前还有公司在项目和运维中使用Python 2.x版本的代码。
|
||||
4. 2000年10月16日:Python 2.0发布,增加了实现完整的[垃圾回收](https://zh.wikipedia.org/wiki/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6_(%E8%A8%88%E7%AE%97%E6%A9%9F%E7%A7%91%E5%AD%B8)),提供了对[Unicode](https://zh.wikipedia.org/wiki/Unicode)的支持。与此同时,Python的整个开发过程更加透明,社区对开发进度的影响逐渐扩大,生态圈开始慢慢形成。
|
||||
5. 2008年12月3日:Python 3.0发布,它并不完全兼容之前的Python代码,不过因为目前还有不少公司在项目和运维中使用Python 2.x版本,所以Python 3.x的很多新特性后来也被移植到Python 2.6/2.7版本中。
|
||||
|
||||
目前我们使用的Python 3.6.x的版本是在2016年的12月23日发布的,Python的版本号分为三段,形如A.B.C。其中A表示大版本号,一般当整体重写,或出现不向后兼容的改变时,增加A;B表示功能更新,出现新功能时增加B;C表示小的改动(如修复了某个Bug),只要有修改就增加C。如果对Python的历史感兴趣,可以查看一篇名为[《Python简史》](http://www.cnblogs.com/vamei/archive/2013/02/06/2892628.html)的博文。
|
||||
目前我们使用的Python 3.7.x的版本是在2018年发布的,Python的版本号分为三段,形如A.B.C。其中A表示大版本号,一般当整体重写,或出现不向后兼容的改变时,增加A;B表示功能更新,出现新功能时增加B;C表示小的改动(如修复了某个Bug),只要有修改就增加C。如果对Python的历史感兴趣,可以查看一篇名为[《Python简史》](http://www.cnblogs.com/vamei/archive/2013/02/06/2892628.html)的博文。
|
||||
|
||||
#### Python的优缺点
|
||||
|
||||
Python的优点很多,简单的可以总结为以下几点。
|
||||
|
||||
1. 简单和明确,做一件事只有一种方法。
|
||||
2. 学习曲线低,与其他很多语言比上手更容易。
|
||||
2. 学习曲线低,跟其他很多语言相比,Python更容易上手。
|
||||
3. 开放源代码,拥有强大的社区和生态圈。
|
||||
4. 解释型语言,完美的平台可移植性。
|
||||
5. 支持两种主流的编程范式,可以使用面向对象和函数式编程。
|
||||
6. 可扩展性和可嵌入性,可以调用C/C++代码也可以在C/C++中调用。
|
||||
4. 解释型语言,天生具有平台可移植性。
|
||||
5. 支持两种主流的编程范式(面向对象编程和函数式编程)都提供了支持。
|
||||
6. 可扩展性和可嵌入性,可以调用C/C++代码,也可以在C/C++中调用Python。
|
||||
7. 代码规范程度高,可读性强,适合有代码洁癖和强迫症的人群。
|
||||
|
||||
Python的缺点主要集中在以下几点。
|
||||
|
||||
1. 执行效率低下,因此计算密集型任务可以由C/C++编写。
|
||||
2. 代码无法加密,但是现在的公司很多都不是卖软件而是卖服务,这个问题慢慢会淡化。
|
||||
3. 在开发时可以选择的框架太多,有选择的地方就有错误。
|
||||
1. 执行效率稍低,因此计算密集型任务可以由C/C++编写。
|
||||
2. 代码无法加密,但是现在的公司很多都不是卖软件而是卖服务,这个问题会被淡化。
|
||||
3. 在开发时可以选择的框架太多(如Web框架就有100多个),有选择的地方就有错误。
|
||||
|
||||
#### Python的应用领域
|
||||
|
||||
目前Python在云基础设施、DevOps、网络爬虫开发、数据分析挖掘、机器学习等领域都有着广泛的应用,因此也产生了服务器开发、数据接口开发、自动化运维、科学计算和数据可视化、聊天机器人开发、图像识别和处理等一系列的职位。
|
||||
目前Python在云基础设施、DevOps、网络爬虫开发、数据分析挖掘、机器学习等领域都有着广泛的应用,因此也产生了Web后端开发、数据接口开发、自动化运维、自动化测试、科学计算和可视化、数据分析、量化交易、机器人开发、图像识别和处理等一系列的职位。
|
||||
|
||||
### 搭建编程环境
|
||||
|
||||
#### Windows环境
|
||||
|
||||
可以在[Python的官方网站](https://www.python.org)下载到Python的Windows安装程序(exe文件),需要注意的是如果在Windows 7环境下安装需要先安装Service Pack 1补丁包(可以通过一些工具软件自动安装系统补丁的功能来安装),安装过程建议勾选“Add Python 3.6 to PATH”(将Python 3.6添加到PATH环境变量)并选择自定义安装,在设置“Optional Features”界面最好将“pip”、“tcl/tk”、“Python test suite”等项全部勾选上。强烈建议使用自定义的安装路径并保证路径中没有中文。安装完成会看到“Setup was successful”的提示,但是在启动Python环境时可能会因为缺失一些动态链接库文件而导致Python解释器无法运行,常见的问题主要是api-ms-win-crt\*.dll缺失以及更新DirectX之后导致某些动态链接库文件缺失,前者可以参照[《api-ms-win-crt\*.dll缺失原因分析和解决方法》]()一文讲解的方法进行处理或者直接在[微软官网](https://www.microsoft.com/zh-cn/download/details.aspx?id=48145)下载Visual C++ Redistributable for Visual Studio 2015文件进行修复,后者可以下载一个DirectX修复工具进行修复。
|
||||
可以在[Python官方网站](https://www.python.org)下载到Python的Windows安装程序(exe文件),需要注意的是如果在Windows 7环境下安装需要先安装Service Pack 1补丁包(可以通过一些工具软件自动安装系统补丁的功能来安装),安装过程建议勾选“Add Python 3.6 to PATH”(将Python 3.6添加到PATH环境变量)并选择自定义安装,在设置“Optional Features”界面最好将“pip”、“tcl/tk”、“Python test suite”等项全部勾选上。强烈建议使用自定义的安装路径并保证路径中没有中文。安装完成会看到“Setup was successful”的提示,但是在启动Python环境时可能会因为缺失一些动态链接库文件而导致Python解释器无法运行,常见的问题主要是api-ms-win-crt\*.dll缺失以及更新DirectX之后导致某些动态链接库文件缺失,前者可以参照[《api-ms-win-crt\*.dll缺失原因分析和解决方法》]()一文讲解的方法进行处理或者直接在[微软官网](https://www.microsoft.com/zh-cn/download/details.aspx?id=48145)下载Visual C++ Redistributable for Visual Studio 2015文件进行修复,后者可以下载一个DirectX修复工具进行修复。
|
||||
|
||||
#### Linux环境
|
||||
|
||||
|
@ -53,15 +53,15 @@ yum -y install wget gcc zlib-devel bzip2-devel openssl-devel ncurses-devel sqlit
|
|||
下载Python源代码并解压缩到指定目录。
|
||||
|
||||
```Shell
|
||||
wget https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz
|
||||
xz -d Python-3.7.0.tar.xz
|
||||
tar -xvf Python-3.7.0.tar
|
||||
wget https://www.python.org/ftp/python/3.7.0/Python-3.7.1.tar.xz
|
||||
xz -d Python-3.7.1.tar.xz
|
||||
tar -xvf Python-3.7.1.tar
|
||||
```
|
||||
|
||||
切换至Python源代码目录并执行下面的命令进行配置和安装。
|
||||
|
||||
```Shell
|
||||
cd Python-3.7.0
|
||||
cd Python-3.7.1
|
||||
./configure --prefix=/usr/local/python37 --enable-optimizations
|
||||
make && make install
|
||||
```
|
||||
|
@ -87,7 +87,7 @@ source .bash_profile
|
|||
|
||||
#### MacOS环境
|
||||
|
||||
MacOS也是自带了Python 2.x版本的,可以通过[Python的官方网站](https://www.python.org)提供的安装文件(pkg文件)安装3.x的版本。默认安装完成后,可以通过在终端执行python命令来启动2.x版本的Python解释器,可以通过执行python3命令来启动3.x版本的Python解释器,当然也可以通过重新设置软链接来修改启动Python解释器的命令。
|
||||
MacOS也是自带了Python 2.x版本的,可以通过[Python的官方网站](https://www.python.org)提供的安装文件(pkg文件)安装3.x的版本。默认安装完成后,可以通过在终端执行python命令来启动2.x版本的Python解释器,可以通过执行python3命令来启动3.x版本的Python解释器。
|
||||
|
||||
### 从终端运行Python程序
|
||||
|
||||
|
@ -137,7 +137,6 @@ python hello.py
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-26
|
||||
"""
|
||||
|
||||
print('hello, world!')
|
||||
|
@ -179,8 +178,6 @@ python -m pip install ipython jupyter
|
|||
jupyter notebook
|
||||
```
|
||||
|
||||
![](./res/python-jupyter-1.png)
|
||||
|
||||
![](./res/python-jupyter-2.png)
|
||||
|
||||
#### Sublime - 文本编辑神器
|
||||
|
@ -203,13 +200,13 @@ jupyter notebook
|
|||
import urllib2,os;pf='Package Control.sublime-package';ipp=sublime.installed_packages_path();os.makedirs(ipp)ifnotos.path.exists(ipp)elseNone;urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler()));open(os.path.join(ipp,pf),'wb').write(urllib2.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read());print('Please restart Sublime Text to finish installation')
|
||||
```
|
||||
|
||||
- 安装插件。通过Preference菜单的Package Control或快捷键Ctrl+Shift+P打开命令面板,在面板中输入Install Package就可以找到安装插件的工具,然后再查找需要的插件。我们推荐大家安装以下几个插件。
|
||||
- 安装插件。通过Preference菜单的Package Control或快捷键Ctrl+Shift+P打开命令面板,在面板中输入Install Package就可以找到安装插件的工具,然后再查找需要的插件。我们推荐大家安装以下几个插件:
|
||||
|
||||
- SublimeCodeIntel - 代码自动补全工具插件
|
||||
- Emmet - 前端开发代码模板插件
|
||||
- Git - 版本控制工具插件
|
||||
- Python PEP8 Autoformat - PEP8规范自动格式化插件
|
||||
- ConvertToUTF8 - 将本地编码转换为UTF-8
|
||||
- SublimeCodeIntel - 代码自动补全工具插件。
|
||||
- Emmet - 前端开发代码模板插件。
|
||||
- Git - 版本控制工具插件。
|
||||
- Python PEP8 Autoformat - PEP8规范自动格式化插件。
|
||||
- ConvertToUTF8 - 将本地编码转换为UTF-8。
|
||||
|
||||
#### PyCharm - Python开发神器
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#### 指令和程序
|
||||
|
||||
计算机的硬件系统通常由五大部件构成,包括:运算器、控制器、存储器、输入设备和输出设备。其中,运算器和控制器放在一起就是我们通常所说的中央处理器,它的功能是执行各种运算和控制指令以及处理计算机软件中的数据。我们通常所说的程序实际上就是指令的集合,我们程序就是将一系列的指令按照某种方式组织到一起,然后通过这些指令去控制计算机做我们想让它做的事情。今天我们使用的计算机虽然器件做工越来越精密,处理能力越来越强大,但究其本质来说仍然属于[“冯·诺依曼结构”](https://zh.wikipedia.org/wiki/%E5%86%AF%C2%B7%E8%AF%BA%E4%BC%8A%E6%9B%BC%E7%BB%93%E6%9E%84)的计算机。“冯·诺依曼结构”有两个关键点,一是提出了将存储设备与中央处理器分开,二是提出了将数据以二进制方式编码。二进制是一种“逢二进一”的计数法,跟我们人类使用的“逢十进一”的计数法没有实质性的区别,人类因为有十根手指所以使用了十进制(因为在数数时十根手指用完之后就只能进位了,当然凡事都有例外,玛雅人可能是因为长年光着脚的原因把脚趾头也算上了,于是他们使用了二十进制的计数法,在这种计数法的指导下玛雅人的历法就与我们的不太一致,而按照玛雅人的历法,2012年是上一个所谓的“太阳纪”的最后一年,而2013年则是新的“太阳纪”的开始,后来这件事情被以讹传讹的方式误传为2012年就是玛雅人预言的世界末日这种荒诞的说法,今天我们可以大胆的猜测,玛雅文明之所以发展缓慢估计也与使用了二十进制有关),对于计算机来说,二进制在物理器件上来说是最容易实现的(高电压表示1,低电压表示0),于是在“冯·诺依曼结构”的计算机都使用了二进制。虽然我们并不需要每个程序员都能够使用二进制的思维方式来工作,但是了解二进制以及它与我们生活中的十进制之间的转换关系,以及二进制与八进制和十六进制的转换关系还是有必要的。如果你对这一点不熟悉,可以自行使用[维基百科](https://zh.wikipedia.org/wiki/%E4%BA%8C%E8%BF%9B%E5%88%B6)或者[百度百科](https://baike.baidu.com)科普一下。
|
||||
计算机的硬件系统通常由五大部件构成,包括:运算器、控制器、存储器、输入设备和输出设备。其中,运算器和控制器放在一起就是我们通常所说的中央处理器,它的功能是执行各种运算和控制指令以及处理计算机软件中的数据。我们通常所说的程序实际上就是指令的集合,我们程序就是将一系列的指令按照某种方式组织到一起,然后通过这些指令去控制计算机做我们想让它做的事情。今天我们使用的计算机虽然器件做工越来越精密,处理能力越来越强大,但究其本质来说仍然属于[“冯·诺依曼结构”](https://zh.wikipedia.org/wiki/%E5%86%AF%C2%B7%E8%AF%BA%E4%BC%8A%E6%9B%BC%E7%BB%93%E6%9E%84)的计算机。“冯·诺依曼结构”有两个关键点,一是指出要将存储设备与中央处理器分开,二是提出了将数据以二进制方式编码。二进制是一种“逢二进一”的计数法,跟我们人类使用的“逢十进一”的计数法没有实质性的区别,人类因为有十根手指所以使用了十进制(因为在数数时十根手指用完之后就只能进位了,当然凡事都有例外,玛雅人可能是因为长年光着脚的原因把脚趾头也算上了,于是他们使用了二十进制的计数法,在这种计数法的指导下玛雅人的历法就与我们平常使用的历法不一样,而按照玛雅人的历法,2012年是上一个所谓的“太阳纪”的最后一年,而2013年则是新的“太阳纪”的开始,后来这件事情被以讹传讹的方式误传为”2012年是玛雅人预言的世界末日“这种荒诞的说法,今天我们可以大胆的猜测,玛雅文明之所以发展缓慢估计也与使用了二十进制有关)。对于计算机来说,二进制在物理器件上来说是最容易实现的(高电压表示1,低电压表示0),于是在“冯·诺依曼结构”的计算机都使用了二进制。虽然我们并不需要每个程序员都能够使用二进制的思维方式来工作,但是了解二进制以及它与我们生活中的十进制之间的转换关系,以及二进制与八进制和十六进制的转换关系还是有必要的。如果你对这一点不熟悉,可以自行使用[维基百科](https://zh.wikipedia.org/wiki/%E4%BA%8C%E8%BF%9B%E5%88%B6)或者[百度百科](https://baike.baidu.com)科普一下。
|
||||
|
||||
### 变量和类型
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
|||
- 浮点型:浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,浮点数除了数学写法(如`123.456`)之外还支持科学计数法(如`1.23456e2`)。
|
||||
- 字符串型:字符串是以单引号或双引号括起来的任意文本,比如`'hello'`和`"hello"`,字符串还有原始字符串表示法、字节字符串表示法、Unicode字符串表示法,而且可以书写成多行的形式(用三个单引号或三个双引号开头,三个单引号或三个双引号结尾)。
|
||||
- 布尔型:布尔值只有`True`、`False`两种值,要么是`True`,要么是`False`,在Python中,可以直接用`True`、`False`表示布尔值(请注意大小写),也可以通过布尔运算计算出来(例如`3 < 5`会产生布尔值`True`,而`2 == 1`会产生布尔值`False`)。
|
||||
- 复数型:形如`3+5j`,跟数学上的复数表示一样,唯一不同的是虚部的i换成了j。
|
||||
- 复数型:形如`3+5j`,跟数学上的复数表示一样,唯一不同的是虚部的`i`换成了`j`。
|
||||
|
||||
#### 变量命名
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
|||
- 受保护的实例属性用单个下划线开头(后面会讲到)。
|
||||
- 私有的实例属性用两个下划线开头(后面会讲到)。
|
||||
|
||||
当然,作为一个专业的程序员,给变量(事实上应该是所有的标识符)命名做到见名知意也是非常重要的。
|
||||
当然,作为一个专业的程序员,给变量(事实上应该是所有的标识符)命名时做到见名知意也是非常重要的。
|
||||
|
||||
#### 变量的使用
|
||||
|
||||
|
@ -39,7 +39,6 @@
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-27
|
||||
"""
|
||||
|
||||
a = 321
|
||||
|
@ -62,7 +61,6 @@ print(a ** b)
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-27
|
||||
"""
|
||||
|
||||
a = int(input('a = '))
|
||||
|
@ -138,7 +136,6 @@ Python支持多种运算符,下表大致按照优先级从高到低的顺序
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-27
|
||||
"""
|
||||
|
||||
a = 5
|
||||
|
@ -178,7 +175,6 @@ F = 1.8C + 32
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-27
|
||||
"""
|
||||
|
||||
f = float(input('请输入华氏温度: '))
|
||||
|
@ -195,7 +191,6 @@ print('%.1f华氏度 = %.1f摄氏度' % (f, c))
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-27
|
||||
"""
|
||||
|
||||
import math
|
||||
|
@ -216,7 +211,6 @@ print('面积: %.2f' % area)
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-27
|
||||
"""
|
||||
|
||||
year = int(input('请输入年份: '))
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-28
|
||||
"""
|
||||
|
||||
username = input('请输入用户名: ')
|
||||
|
@ -44,7 +43,6 @@ f(x) = x + 2 (-1 <= x <= 1)
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-28
|
||||
"""
|
||||
|
||||
x = float(input('x = '))
|
||||
|
@ -68,7 +66,6 @@ f(x) = x + 2 (-1 <= x <= 1)
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-28
|
||||
"""
|
||||
|
||||
x = float(input('x = '))
|
||||
|
@ -94,7 +91,6 @@ print('f(%.2f) = %.2f' % (x, y))
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-28
|
||||
"""
|
||||
|
||||
value = float(input('请输入长度: '))
|
||||
|
@ -115,7 +111,6 @@ else:
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-28
|
||||
"""
|
||||
|
||||
from random import randint
|
||||
|
@ -150,7 +145,6 @@ print(result)
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-28
|
||||
"""
|
||||
|
||||
score = float(input('请输入成绩: '))
|
||||
|
@ -175,7 +169,6 @@ print('对应的等级是:', grade)
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-28
|
||||
"""
|
||||
|
||||
import math
|
||||
|
@ -193,7 +186,7 @@ else:
|
|||
```
|
||||
> **说明:**上面的代码中使用了`math`模块的`sqrt`函数来计算平方根。用边长计算三角形面积的公式叫做[海伦公式](https://zh.wikipedia.org/zh-hans/海伦公式)。
|
||||
|
||||
#### 练习5:实现一个个人所得税计算器。
|
||||
#### 练习5:个人所得税计算器。
|
||||
|
||||
```Python
|
||||
"""
|
||||
|
@ -201,7 +194,6 @@ else:
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-02-28
|
||||
"""
|
||||
|
||||
salary = float(input('本月收入: '))
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
### 循环结构的应用场景
|
||||
|
||||
如果在程序中我们需要重复的执行某条或某些指令,例如用程序控制机器人踢足球,如果机器人持球而且还没有进入射门范围,那么我们就要一直发出让机器人向球门方向奔跑的指令。当然你可能已经注意到了,刚才的描述中其实不仅仅有需要重复的动作,还有我们上一个章节讲到的分支结构。再举一个简单的例子,比如在我们的程序中要实现每隔1秒中在屏幕上打印一个"hello, world"这样的字符串并持续一个小时,我们肯定不能够将`print('hello, world')`这句代码写上3600遍,如果真的需要这样做那么我们的工作就太无聊了。因此,我们需要循环结构,使用循环结构我们就可以轻松的控制某件事或者某些事重复、重复、再重复的发生。在Python中构造循环结构有两种做法,一种是`for-in`循环,一种是`while`循环。
|
||||
如果在程序中我们需要重复的执行某条或某些指令,例如用程序控制机器人踢足球,如果机器人持球而且还没有进入射门范围,那么我们就要一直发出让机器人向球门方向奔跑的指令。当然你可能已经注意到了,刚才的描述中其实不仅仅有需要重复的动作,还有我们上一个章节讲到的分支结构。再举一个简单的例子,比如在我们的程序中要实现每隔1秒中在屏幕上打印一个"hello, world"这样的字符串并持续一个小时,我们肯定不能够将`print('hello, world')`这句代码写上3600遍,如果真的需要这样做那么编程的工作就太无聊了。因此,我们需要了解一下循环结构,有了循环结构我们就可以轻松的控制某件事或者某些事重复、重复、再重复的发生。在Python中构造循环结构有两种做法,一种是`for-in`循环,一种是`while`循环。
|
||||
|
||||
### for-in循环
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-03-01
|
||||
"""
|
||||
|
||||
sum = 0
|
||||
|
@ -37,7 +36,6 @@ print(sum)
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-03-01
|
||||
"""
|
||||
|
||||
sum = 0
|
||||
|
@ -54,7 +52,6 @@ print(sum)
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-03-01
|
||||
"""
|
||||
|
||||
sum = 0
|
||||
|
@ -77,7 +74,6 @@ print(sum)
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-03-01
|
||||
"""
|
||||
|
||||
import random
|
||||
|
@ -109,8 +105,6 @@ if counter > 7:
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-03-01
|
||||
|
||||
"""
|
||||
|
||||
for i in range(1, 10):
|
||||
|
@ -196,7 +190,6 @@ for factor in range(x, 0, -1):
|
|||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
||||
Date: 2018-03-01
|
||||
"""
|
||||
|
||||
row = int(input('请输入行数: '))
|
||||
|
|
|
@ -27,7 +27,6 @@ fmn = 1
|
|||
for num in range(1, m - n + 1):
|
||||
fmn *= num
|
||||
print(fm // fn // fmn)
|
||||
|
||||
```
|
||||
|
||||
### 函数的作用
|
||||
|
@ -134,7 +133,8 @@ def foo():
|
|||
print('goodbye, world!')
|
||||
|
||||
|
||||
foo() # 输出goodbye, world!
|
||||
# 下面的代码会输出什么呢?
|
||||
foo()
|
||||
```
|
||||
|
||||
当然上面的这种情况我们很容易就能避免,但是如果项目是由多人协作进行团队开发的时候,团队中可能有多个程序员都定义了名为`foo`的函数,那么怎么解决这种命名冲突呢?答案其实很简单,Python中每个文件就代表了一个模块(module),我们在不同的模块中可以有同名的函数,在使用函数的时候我们通过`import`关键字导入指定的模块就可以区分到底要使用的是哪个模块中的`foo`函数,代码如下所示。
|
||||
|
@ -158,11 +158,13 @@ test.py
|
|||
```Python
|
||||
from module1 import foo
|
||||
|
||||
foo() # 输出hello, world!
|
||||
# 输出hello, world!
|
||||
foo()
|
||||
|
||||
from module2 import foo
|
||||
|
||||
foo() # 输出goodbye, world!
|
||||
# 输出goodbye, world!
|
||||
foo()
|
||||
```
|
||||
|
||||
也可以按照如下所示的方式来区分到底要使用哪一个`foo`函数。
|
||||
|
@ -185,7 +187,8 @@ test.py
|
|||
from module1 import foo
|
||||
from module2 import foo
|
||||
|
||||
foo() # 输出goodbye, world!
|
||||
# 输出goodbye, world!
|
||||
foo()
|
||||
```
|
||||
|
||||
test.py
|
||||
|
@ -194,7 +197,8 @@ test.py
|
|||
from module2 import foo
|
||||
from module1 import foo
|
||||
|
||||
foo() # 输出hello, world!
|
||||
# 输出hello, world!
|
||||
foo()
|
||||
```
|
||||
|
||||
需要说明的是,如果我们导入的模块除了定义函数之外还中有可以执行代码,那么Python解释器在导入这个模块时就会执行这些代码,事实上我们可能并不希望如此,因此如果我们在模块中编写了执行代码,最好是将这些执行代码放入如下所示的条件中,这样的话除非直接运行该模块,if条件下的这些代码是不会执行的,因为只有直接执行的模块的名字才是“\_\_main\_\_”。
|
||||
|
|
|
@ -42,7 +42,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
下面是运行程序得到的一次运行结果。
|
||||
|
@ -86,7 +85,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
在上面的代码中,我们通过`Process`类创建了进程对象,通过`target`参数我们传入一个函数来表示进程启动后要执行的代码,后面的`args`是一个元组,它代表了传递给函数的参数。`Process`对象的`start`方法用来启动进程,而`join`方法表示等待进程执行结束。运行上面的代码可以明显发现两个下载任务“同时”启动了,而且程序的执行时间将大大缩短,不再是两个任务的时间总和。下面是程序的一次执行结果。
|
||||
|
@ -375,7 +373,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
如果使用多线程将耗时间的任务放到一个独立的线程中执行,这样就不会因为执行耗时间的任务而阻塞了主线程,修改后的代码如下所示。
|
||||
|
@ -424,7 +421,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
#### 例子2:使用多进程对复杂任务进行“分而治之”。
|
||||
|
@ -448,7 +444,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
在上面的代码中,我故意先去创建了一个列表容器然后填入了100000000个数,这一步其实是比较耗时间的,所以为了公平起见,当我们将这个任务分解到8个进程中去执行的时候,我们暂时也不考虑列表切片操作花费的时间,只是把做运算和合并运算结果的时间统计出来,代码如下所示。
|
||||
|
@ -493,7 +488,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
比较两段代码的执行结果(在我目前使用的MacBook上,上面的代码需要大概6秒左右的时间,而下面的代码只需要不到1秒的时间,再强调一次我们只是比较了运算的时间,不考虑列表创建及切片操作花费的时间),使用多进程后由于获得了更多的CPU执行时间以及更好的利用了CPU的多核特性,明显的减少了程序的执行时间,而且计算量越大效果越明显。当然,如果愿意还可以将多个进程部署在不同的计算机上,做成分布式进程,具体的做法就是通过multiprocessing.managers模块中提供的管理器将`Queue`对象通过网络共享出来(注册到网络上让其他计算机可以访问),这部分内容也留到爬虫的专题再进行讲解。
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 182 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 120 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
|
@ -126,7 +126,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
### 基于传输层协议的套接字编程
|
||||
|
@ -174,7 +173,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
运行服务器程序后我们可以通过Windows系统的telnet来访问该服务器,结果如下图所示。
|
||||
|
@ -203,7 +201,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
需要注意的是,上面的服务器并没有使用多线程或者异步I/O的处理方式,这也就意味着当服务器与一个客户端处于通信状态时,其他的客户端只能排队等待。很显然,这样的服务器并不能满足我们的需求,我们需要的服务器是能够同时接纳和处理多个用户请求的。下面我们来设计一个使用多线程技术处理多个用户请求的服务器,该服务器会向连接到服务器的客户端发送一张图片。
|
||||
|
@ -256,7 +253,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
客户端代码:
|
||||
|
@ -291,7 +287,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
在这个案例中,我们使用了JSON作为数据传输的格式(通过JSON格式对传输的数据进行了序列化和反序列化的操作),但是JSON并不能携带二进制数据,因此对图片的二进制数据进行了Base64编码的处理。Base64是一种用64个字符表示所有二进制数据的编码方式,通过将二进制数据每6位一组的方式重新组织,刚好可以使用0~9的数字、大小写字母以及“+”和“/”总共64个字符表示从`000000`到`111111`的64种状态。[维基百科](https://zh.wikipedia.org/wiki/Base64)上有关于Base64编码的详细讲解,不熟悉Base64的读者可以自行阅读。
|
|
@ -31,7 +31,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
如果要发送带有附件的邮件,那么可以按照下面的方式进行操作。
|
||||
|
@ -88,7 +87,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
### 发送短信
|
||||
|
@ -119,7 +117,5 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
```
|
||||
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
@ -1249,7 +1249,3 @@ build environment:
|
|||
3. HISTSIZE
|
||||
4. RANDOM
|
||||
5. PATH
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -115,7 +115,6 @@ HTTP响应(响应行+响应头+空行+消息体):
|
|||
3. HTTPie:命令行HTTP客户端。
|
||||
|
||||
```Shell
|
||||
|
||||
$ http --header http://www.scu.edu.cn
|
||||
HTTP/1.1 200 OK
|
||||
Accept-Ranges: bytes
|
||||
|
@ -138,8 +137,6 @@ HTTP响应(响应行+响应头+空行+消息体):
|
|||
4. BuiltWith:识别网站所用技术的工具。
|
||||
|
||||
```Python
|
||||
|
||||
>>>
|
||||
>>> import builtwith
|
||||
>>> builtwith.parse('http://www.bootcss.com/')
|
||||
{'web-servers': ['Nginx'], 'font-scripts': ['Font Awesome'], 'javascript-frameworks': ['Lo-dash', 'Underscore.js', 'Vue.js', 'Zepto', 'jQuery'], 'web-frameworks': ['Twitter Bootstrap']}
|
||||
|
@ -153,8 +150,6 @@ HTTP响应(响应行+响应头+空行+消息体):
|
|||
5. python-whois:查询网站所有者的工具。
|
||||
|
||||
```Python
|
||||
|
||||
>>>
|
||||
>>> import whois
|
||||
>>> whois.whois('baidu.com')
|
||||
{'domain_name': ['BAIDU.COM', 'baidu.com'], 'registrar': 'MarkMonitor, Inc.', 'whois_server': 'whois.markmonitor.com', 'referral_url': None, 'updated_date': [datetime.datetime(2017, 7, 28, 2, 36, 28), datetime.datetime(2017, 7, 27, 19, 36, 28)], 'creation_date': [datetime.datetime(1999, 10, 11, 11, 5, 17), datetime.datetime(1999, 10, 11, 4, 5, 17)], 'expiration_date': [datetime.datetime(2026, 10, 11, 11, 5, 17), datetime.datetime(2026, 10, 11, 0, 0)], 'name_servers': ['DNS.BAIDU.COM', 'NS2.BAIDU.COM', 'NS3.BAIDU.COM', 'NS4.BAIDU.COM', 'NS7.BAIDU.COM', 'dns.baidu.com', 'ns4.baidu.com', 'ns3.baidu.com', 'ns7.baidu.com', 'ns2.baidu.com'], 'status': ['clientDeleteProhibited https://icann.org/epp#clientDeleteProhibited', 'clientTransferProhibited https://icann.org/epp#clientTransferProhibited', 'clientUpdateProhibited https://icann.org/epp#clientUpdateProhibited', 'serverDeleteProhibited https://icann.org/epp#serverDeleteProhibited', 'serverTransferProhibited https://icann.org/epp#serverTransferProhibited', 'serverUpdateProhibited https://icann.org/epp#serverUpdateProhibited', 'clientUpdateProhibited (https://www.icann.org/epp#clientUpdateProhibited)', 'clientTransferProhibited (https://www.icann.org/epp#clientTransferProhibited)', 'clientDeleteProhibited (https://www.icann.org/epp#clientDeleteProhibited)', 'serverUpdateProhibited (https://www.icann.org/epp#serverUpdateProhibited)', 'serverTransferProhibited (https://www.icann.org/epp#serverTransferProhibited)', 'serverDeleteProhibited (https://www.icann.org/epp#serverDeleteProhibited)'], 'emails': ['abusecomplaints@markmonitor.com', 'whoisrelay@markmonitor.com'], 'dnssec': 'unsigned', 'name': None, 'org': 'Beijing Baidu Netcom Science Technology Co., Ltd.', 'address': None, 'city': None, 'state': 'Beijing', 'zipcode': None, 'country': 'CN'}
|
||||
|
@ -195,7 +190,6 @@ HTTP响应(响应行+响应头+空行+消息体):
|
|||
下面的例子给出了一个从“搜狐体育”上获取NBA新闻标题和链接的爬虫。
|
||||
|
||||
```Python
|
||||
|
||||
from urllib.error import URLError
|
||||
from urllib.request import urlopen
|
||||
|
||||
|
@ -304,7 +298,6 @@ if __name__ == '__main__':
|
|||
- 使用未经验证的上下文
|
||||
|
||||
```Python
|
||||
|
||||
import ssl
|
||||
|
||||
request = urllib.request.Request(url='...', headers={...})
|
||||
|
@ -315,10 +308,8 @@ if __name__ == '__main__':
|
|||
- 设置全局的取消证书验证
|
||||
|
||||
```Python
|
||||
|
||||
import ssl
|
||||
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
```
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
### HTML页面分析
|
||||
|
||||
```HTML
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
@ -136,7 +135,6 @@ pyquery相当于jQuery的Python实现,可以用于解析HTML网页。
|
|||
### 实例 - 获取知乎发现上的问题链接
|
||||
|
||||
```Python
|
||||
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import re
|
||||
|
@ -168,6 +166,5 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
|
|
|
@ -20,21 +20,19 @@ Redis是REmote DIctionary Server的缩写,它是一个用ANSI C编写的高性
|
|||
可以使用Linux系统的包管理工具(如yum)来安装Redis,也可以通过在Redis的[官方网站](https://redis.io/)下载Redis的[源代码](http://download.redis.io/releases/redis-3.2.11.tar.gz)解压缩解归档之后进行构件安装。
|
||||
|
||||
```Shell
|
||||
|
||||
# wget http://download.redis.io/releases/redis-3.2.11.tar.gz
|
||||
# gunzip redis-3.2.11.tar.gz
|
||||
# tar -xvf redis-3.2.11.tar
|
||||
# cd redis-3.2.11
|
||||
# make && make install
|
||||
wget http://download.redis.io/releases/redis-3.2.11.tar.gz
|
||||
gunzip redis-3.2.11.tar.gz
|
||||
tar -xvf redis-3.2.11.tar
|
||||
cd redis-3.2.11
|
||||
make && make install
|
||||
```
|
||||
|
||||
接下来我们将redis-3.2.11目录下的redis.conf配置文件复制到用户主目录下并修改配置文件(如果你对配置文件不是很有把握就不要直接修改而是先复制一份再修改这个副本)。
|
||||
|
||||
```Shell
|
||||
|
||||
# cd ..
|
||||
# cp redis-3.2.11/redis.conf redis.conf
|
||||
# vim redis.conf
|
||||
cd ..
|
||||
cp redis-3.2.11/redis.conf redis.conf
|
||||
vim redis.conf
|
||||
```
|
||||
|
||||
配置将Redis服务绑定到指定的IP地址和端口。
|
||||
|
@ -76,8 +74,7 @@ Redis是REmote DIctionary Server的缩写,它是一个用ANSI C编写的高性
|
|||
接下来启动Redis服务器,可以将服务器放在后台去运行。
|
||||
|
||||
```Shell
|
||||
|
||||
# redis-server redis.conf &
|
||||
redis-server redis.conf &
|
||||
|
||||
_.-``__ ''-._
|
||||
_.-`` `. `_. ''-._ Redis 3.2.11 (00000000/0) 64 bit
|
||||
|
@ -100,8 +97,7 @@ Redis是REmote DIctionary Server的缩写,它是一个用ANSI C编写的高性
|
|||
接下来,我们尝试用Redis客户端去连接服务器。
|
||||
|
||||
```Shell
|
||||
|
||||
# redis-cli -h 172.18.61.250 -p 6379
|
||||
redis-cli -h 172.18.61.250 -p 6379
|
||||
172.18.61.250:6379> auth 1qaz2wsx
|
||||
OK
|
||||
172.18.61.250:6379> ping
|
||||
|
@ -112,7 +108,6 @@ PONG
|
|||
Redis有着非常丰富的数据类型,也有很多的命令来操作这些数据,具体的内容可以查看[Redis命令参考](http://redisdoc.com/),在这个网站上,除了Redis的命令参考,还有Redis的详细文档,其中包括了通知、事务、主从复制、持久化、哨兵、集群等内容。
|
||||
|
||||
```Shell
|
||||
|
||||
172.18.61.250:6379> set username admin
|
||||
OK
|
||||
172.18.61.250:6379> get username
|
||||
|
@ -166,13 +161,11 @@ OK
|
|||
可以使用pip安装redis模块。redis模块的核心是名为Redis的类,该类的对象代表一个Redis客户端,通过该客户端可以向Redis服务器发送命令并获取执行的结果。上面我们在Redis客户端中使用的命令基本上就是Redis对象可以接收的消息,所以如果了解了Redis的命令就可以在Python中玩转Redis。
|
||||
|
||||
```Shell
|
||||
|
||||
$ pip3 install redis
|
||||
$ python3
|
||||
pip3 install redis
|
||||
python3
|
||||
```
|
||||
|
||||
```Python
|
||||
|
||||
>>> import redis
|
||||
>>> client = redis.Redis(host='1.2.3.4', port=6379, password='1qaz2wsx')
|
||||
>>> client.set('username', 'admin')
|
||||
|
@ -202,14 +195,14 @@ MongoDB将数据存储为一个文档,一个文档由一系列的“键值对
|
|||
可以从MongoDB的[官方下载链接](https://www.mongodb.com/download-center#community)下载MongoDB,官方为Windows系统提供了一个Installer程序,而Linux和MacOS则提供了压缩文件。下面简单说一下Linux系统如何安装和配置MongoDB。
|
||||
|
||||
```Shell
|
||||
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-amazon-3.6.5.tgz
|
||||
gunzip mongodb-linux-x86_64-amazon-3.6.5.tgz
|
||||
mkdir mongodb-3.6.5
|
||||
tar -xvf mongodb-linux-x86_64-amazon-3.6.5.tar --strip-components 1 -C mongodb-3.6.5/
|
||||
export PATH=$PATH:~/mongodb-3.6.5/bin
|
||||
mkdir -p /data/db
|
||||
mongod --bind_ip 172.18.61.250
|
||||
|
||||
# wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-amazon-3.6.5.tgz
|
||||
# gunzip mongodb-linux-x86_64-amazon-3.6.5.tgz
|
||||
# mkdir mongodb-3.6.5
|
||||
# tar -xvf mongodb-linux-x86_64-amazon-3.6.5.tar --strip-components 1 -C mongodb-3.6.5/
|
||||
# export PATH=$PATH:~/mongodb-3.6.5/bin
|
||||
# mkdir -p /data/db
|
||||
# mongod --bind_ip 172.18.61.250
|
||||
2018-06-03T18:03:28.232+0800 I CONTROL [initandlisten] MongoDB starting : pid=1163 port=27017 dbpath=/data/db 64-bit host=iZwz97tbgo9lkabnat2lo8Z
|
||||
2018-06-03T18:03:28.232+0800 I CONTROL [initandlisten] db version v3.6.5
|
||||
2018-06-03T18:03:28.232+0800 I CONTROL [initandlisten] git version: a20ecd3e3a174162052ff99913bc2ca9a839d618
|
||||
|
@ -239,7 +232,8 @@ MongoDB将数据存储为一个文档,一个文档由一系列的“键值对
|
|||
启动服务器后可以使用交互式环境跟服务器通信,如下所示。
|
||||
|
||||
```shell
|
||||
# mongo --host 172.18.61.250
|
||||
mongo --host 172.18.61.250
|
||||
|
||||
MongoDB shell version v3.6.5
|
||||
connecting to: mongodb://172.18.61.250:27017/
|
||||
...
|
||||
|
@ -249,7 +243,6 @@ connecting to: mongodb://172.18.61.250:27017/
|
|||
1. 查看、创建和删除数据库。
|
||||
|
||||
```JavaScript
|
||||
|
||||
> // 显示所有数据库
|
||||
> show dbs
|
||||
admin 0.000GB
|
||||
|
@ -267,7 +260,6 @@ connecting to: mongodb://172.18.61.250:27017/
|
|||
2. 创建、删除和查看集合。
|
||||
|
||||
```JavaScript
|
||||
|
||||
> // 创建并切换到school数据库
|
||||
> use school
|
||||
switched to db school
|
||||
|
@ -292,7 +284,6 @@ connecting to: mongodb://172.18.61.250:27017/
|
|||
3. 文档的CRUD操作。
|
||||
|
||||
```JavaScript
|
||||
|
||||
> // 向students集合插入文档
|
||||
> db.students.insert({stuid: 1001, name: '骆昊', age: 38})
|
||||
WriteResult({ "nInserted" : 1 })
|
||||
|
@ -394,13 +385,11 @@ connecting to: mongodb://172.18.61.250:27017/
|
|||
可以通过pip安装pymongo来实现对MongoDB的操作。
|
||||
|
||||
```Shell
|
||||
|
||||
$ pip3 install pymongo
|
||||
$ python3
|
||||
pip3 install pymongo
|
||||
python3
|
||||
```
|
||||
|
||||
```Python
|
||||
|
||||
>>> from pymongo import MongoClient
|
||||
>>> client = MongoClient('mongodb://120.77.222.217:27017')
|
||||
>>> db = client.school
|
||||
|
@ -451,7 +440,6 @@ $ python3
|
|||
### 实例 - 缓存知乎发现上的链接和页面代码
|
||||
|
||||
```Python
|
||||
|
||||
from hashlib import sha1
|
||||
from urllib.parse import urljoin
|
||||
|
||||
|
@ -501,7 +489,6 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ Python3.2带来了`concurrent.futures` 模块,这个模块包含了线程池
|
|||
1. 生成器 - 数据的生产者。
|
||||
|
||||
```Python
|
||||
|
||||
from time import sleep
|
||||
|
||||
|
||||
|
@ -70,7 +69,6 @@ Python3.2带来了`concurrent.futures` 模块,这个模块包含了线程池
|
|||
生成器还可以叠加来组成生成器管道,代码如下所示。
|
||||
|
||||
```Python
|
||||
|
||||
# Fibonacci数生成器
|
||||
def fib():
|
||||
a, b = 0, 1
|
||||
|
@ -94,13 +92,11 @@ Python3.2带来了`concurrent.futures` 模块,这个模块包含了线程池
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
2. 协程 - 数据的消费者。
|
||||
|
||||
```Python
|
||||
|
||||
from time import sleep
|
||||
|
||||
|
||||
|
@ -130,13 +126,11 @@ Python3.2带来了`concurrent.futures` 模块,这个模块包含了线程池
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
> 说明:上面代码中countdown_gen函数中的第1行consumer.send(None)是为了激活生成器,通俗的说就是让生成器执行到有yield关键字的地方挂起,当然也可以通过next(consumer)来达到同样的效果。如果不愿意每次都用这样的代码来“预激”生成器,可以写一个包装器来完成该操作,代码如下所示。
|
||||
|
||||
```Python
|
||||
|
||||
from functools import wraps
|
||||
|
||||
|
||||
|
@ -156,7 +150,6 @@ Python3.2带来了`concurrent.futures` 模块,这个模块包含了线程池
|
|||
3. 异步I/O - 非阻塞式I/O操作。
|
||||
|
||||
```Python
|
||||
|
||||
import asyncio
|
||||
|
||||
|
||||
|
@ -179,13 +172,11 @@ Python3.2带来了`concurrent.futures` 模块,这个模块包含了线程池
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
4. `async`和`await`。
|
||||
4. `async`和`await`。
|
||||
|
||||
```Python
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
|
||||
|
@ -215,7 +206,6 @@ Python3.2带来了`concurrent.futures` 模块,这个模块包含了线程池
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
上面的代码使用了[AIOHTTP](https://github.com/aio-libs/aiohttp)这个非常著名的第三方库,它实现了HTTP客户端和HTTP服务器的功能,对异步操作提供了非常好的支持,有兴趣可以阅读它的[官方文档](https://aiohttp.readthedocs.io/en/stable/)。
|
||||
|
@ -225,7 +215,6 @@ Python3.2带来了`concurrent.futures` 模块,这个模块包含了线程池
|
|||
下面我们把之间讲的所有知识结合起来,用面向对象的方式实现一个爬取“手机搜狐网”的多线程爬虫。
|
||||
|
||||
```Python
|
||||
|
||||
import pickle
|
||||
import zlib
|
||||
from enum import Enum, unique
|
||||
|
@ -382,6 +371,5 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
|
|
|
@ -25,14 +25,12 @@ WebKit的代码始于1998年的KHTML项目,当时它是Konqueror浏览器的
|
|||
如果没有打算用上面所说的方式来渲染页面并获得动态内容,其实还有一种替代方案就是使用自动化测试工具Selenium,它提供了浏览器自动化的API接口,这样就可以通过操控浏览器来获取动态内容。首先可以使用pip来安装Selenium。
|
||||
|
||||
```Shell
|
||||
|
||||
$ pip3 install selenium
|
||||
pip3 install selenium
|
||||
```
|
||||
|
||||
下面以“阿里V任务”的“直播服务”为例,来演示如何使用Selenium获取到动态内容并抓取主播图片。
|
||||
|
||||
```Python
|
||||
|
||||
import requests
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
|
@ -47,13 +45,11 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
运行上面的程序会发现没有任何的输出,因为页面的HTML代码上根本找不到`<img>`标签。接下来我们使用Selenium来获取到页面上的动态内容,再提取主播图片。
|
||||
|
||||
```Python
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
|
@ -69,21 +65,18 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
在上面的程序中,我们通过Selenium实现对Chrome浏览器的操控,如果要操控其他的浏览器,可以创对应的浏览器对象,例如Firefox、IE等。运行上面的程序,如果看到如下所示的错误提示,那是说明我们还没有将Chrome浏览器的驱动添加到PATH环境变量中,也没有在程序中指定Chrome浏览器驱动所在的位置。
|
||||
|
||||
```Shell
|
||||
|
||||
selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/chromedriver/home
|
||||
```
|
||||
|
||||
为了解决上面的问题,可以到Selenium的[官方网站]()找到浏览器驱动的下载链接并下载需要的驱动,在Linux或macOS系统下可以通过下面的命令来设置PATH环境变量,Windows下配置环境变量也非常简单,不清楚的可以自行了解。
|
||||
|
||||
```Shell
|
||||
|
||||
$ export PATH=$PATH:/Users/Hao/Downloads/Tools/chromedriver/
|
||||
export PATH=$PATH:/Users/Hao/Downloads/Tools/chromedriver/
|
||||
```
|
||||
|
||||
其中`/Users/Hao/Downloads/Tools/chromedriver/ `就是chromedriver所在的路径。
|
|
@ -43,13 +43,11 @@ Scrapy的整个数据处理流程由Scrapy引擎进行控制,通常的运转
|
|||
|
||||
```Shell
|
||||
|
||||
$
|
||||
```
|
||||
|
||||
项目的目录结构如下图所示。
|
||||
|
||||
```Shell
|
||||
|
||||
(venv) $ tree
|
||||
.
|
||||
|____ scrapy.cfg
|
||||
|
@ -78,7 +76,6 @@ $
|
|||
1. 在items.py文件中定义字段,这些字段用来保存数据,方便后续的操作。
|
||||
|
||||
```Python
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Define here the models for your scraped items
|
||||
|
@ -102,12 +99,10 @@ $
|
|||
2. 在spiders文件夹中编写自己的爬虫。
|
||||
|
||||
```Shell
|
||||
|
||||
(venv) $ scrapy genspider movie movie.douban.com --template=crawl
|
||||
```
|
||||
|
||||
```Python
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import scrapy
|
||||
from scrapy.selector import Selector
|
||||
|
@ -136,28 +131,24 @@ $
|
|||
item['classification']= sel.xpath('//span[@property="v:genre"]/text()').extract()
|
||||
item['actor']= sel.xpath('//*[@id="info"]/span[3]/a[1]/text()').extract()
|
||||
return item
|
||||
|
||||
```
|
||||
> 说明:上面我们通过Scrapy提供的爬虫模板创建了Spider,其中的rules中的LinkExtractor对象会自动完成对新的链接的解析,该对象中有一个名为extract_link的回调方法。Scrapy支持用XPath语法和CSS选择器进行数据解析,对应的方法分别是xpath和css,上面我们使用了XPath语法对页面进行解析,如果不熟悉XPath语法可以看看后面的补充说明。
|
||||
|
||||
到这里,我们已经可以通过下面的命令让爬虫运转起来。
|
||||
|
||||
```Shell
|
||||
|
||||
(venv)$ scrapy crawl movie
|
||||
```
|
||||
|
||||
可以在控制台看到爬取到的数据,如果想将这些数据保存到文件中,可以通过`-o`参数来指定文件名,Scrapy支持我们将爬取到的数据导出成JSON、CSV、XML、pickle、marshal等格式。
|
||||
|
||||
```Shell
|
||||
|
||||
(venv)$ scrapy crawl moive -o result.json
|
||||
```
|
||||
|
||||
3. 在pipelines.py中完成对数据进行持久化的操作。
|
||||
|
||||
```Python
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Define your item pipelines here
|
||||
|
@ -211,7 +202,6 @@ $
|
|||
4. 修改settings.py文件对项目进行配置。
|
||||
|
||||
```Python
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Scrapy settings for douban project
|
||||
|
@ -325,7 +315,6 @@ $
|
|||
XML文件。
|
||||
|
||||
```XML
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<bookstore>
|
||||
|
|
|
@ -0,0 +1,764 @@
|
|||
## 项目部署上线指南
|
||||
|
||||
### 准备上线
|
||||
|
||||
1. 上线前的检查工作。
|
||||
|
||||
```Shell
|
||||
python manage.py check --deploy
|
||||
```
|
||||
|
||||
2. 将DEBUG设置为False并配置ALLOWED_HOSTS。
|
||||
|
||||
```Python
|
||||
DEBUG = False
|
||||
ALLOWED_HOSTS = ['*']
|
||||
```
|
||||
|
||||
3. 安全相关的配置。
|
||||
|
||||
```Python
|
||||
# 保持HTTPS连接的时间
|
||||
SECURE_HSTS_SECONDS = 3600
|
||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
||||
SECURE_HSTS_PRELOAD = True
|
||||
|
||||
# 自动重定向到安全连接
|
||||
SECURE_SSL_REDIRECT = True
|
||||
|
||||
# 避免浏览器自作聪明推断内容类型
|
||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||
|
||||
# 避免跨站脚本攻击
|
||||
SECURE_BROWSER_XSS_FILTER = True
|
||||
|
||||
# COOKIE只能通过HTTPS进行传输
|
||||
SESSION_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_SECURE = True
|
||||
|
||||
# 防止点击劫持攻击手段 - 修改HTTP协议响应头
|
||||
# 当前网站是不允许使用<iframe>标签进行加载的
|
||||
X_FRAME_OPTIONS = 'DENY'
|
||||
```
|
||||
|
||||
4. 敏感信息放到环境变量或文件中。
|
||||
|
||||
```Python
|
||||
SECRET_KEY = os.environ['SECRET_KEY']
|
||||
|
||||
DB_USER = os.environ['DB_USER']
|
||||
DB_PASS = os.environ['DB_PASS']
|
||||
|
||||
REDIS_AUTH = os.environ['REDIS_AUTH']
|
||||
```
|
||||
|
||||
### 更新服务器Python环境到3.x
|
||||
|
||||
> 说明:如果需要清除之前的安装,就删除对应的文件和文件夹即可
|
||||
|
||||
1. 安装底层依赖库。
|
||||
|
||||
```Shell
|
||||
yum -y install wget gcc zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel
|
||||
```
|
||||
|
||||
2. 下载Python源代码。
|
||||
|
||||
```Shell
|
||||
wget https://www.python.org/ftp/python/3.7.1/Python-3.7.1.tar.xz
|
||||
```
|
||||
|
||||
3. 解压缩和解归档。
|
||||
|
||||
```Shell
|
||||
xz -d Python-3.7.1.tar.xz
|
||||
tar -xvf Python-3.7.1.tar
|
||||
```
|
||||
|
||||
4. 执行配置生成Makefile(构建文件)。
|
||||
|
||||
```Shell
|
||||
cd Python-3.7.1
|
||||
./configure --prefix=/usr/local/python37 --enable-optimizations
|
||||
```
|
||||
|
||||
5. 构建和安装。
|
||||
|
||||
```Shell
|
||||
make && make install
|
||||
```
|
||||
|
||||
6. 配置PATH环境变量并激活。
|
||||
|
||||
```Shell
|
||||
cd ~
|
||||
vim .bash_profile
|
||||
```
|
||||
|
||||
```INI
|
||||
... 此处省略上面的代码...
|
||||
|
||||
export PATH=$PATH:/usr/local/python37/bin
|
||||
|
||||
... 此处省略下面的代码...
|
||||
```
|
||||
|
||||
```Shell
|
||||
source .bash_profile
|
||||
```
|
||||
|
||||
7. 注册软链接(符号链接)- 这一步不是必须的。
|
||||
|
||||
```Shell
|
||||
ln -s /usr/local/python37/bin/python3 /usr/bin/python3
|
||||
ln -s /usr/local/python37/bin/pip3 /usr/bin/pip3
|
||||
```
|
||||
|
||||
8. 测试Python环境是否更新成功。
|
||||
|
||||
```Shell
|
||||
python3 --version
|
||||
python --version
|
||||
```
|
||||
|
||||
### 项目目录结构
|
||||
|
||||
假设项目文件夹为`project`,下面的四个子目录分别是:`conf`、`logs`、`src`和`venv`分别用来保存项目的配置文件、日志文件、源代码和虚拟环境。其中,`conf`目录下的子目录`cert`中保存了配置HTTPS需要使用的证书和密钥;`src`目录下的项目代码可以通过版本控制工具从代码仓库中检出;虚拟环境可以通过venv或其他工具进行创建。
|
||||
|
||||
```
|
||||
project
|
||||
├── conf
|
||||
│ ├── cert
|
||||
│ │ ├── 214915882850706.key
|
||||
│ │ └── 214915882850706.pem
|
||||
│ ├── nginx.conf
|
||||
│ └── uwsgi.ini
|
||||
├── logs
|
||||
│ ├── access.log
|
||||
│ ├── error.log
|
||||
│ └── uwsgi.log
|
||||
├── code
|
||||
│ └── fangall
|
||||
│ ├── api
|
||||
│ ├── common
|
||||
│ ├── fang
|
||||
│ ├── rent
|
||||
│ ├── user
|
||||
│ ├── manage.py
|
||||
│ ├── README.md
|
||||
│ ├── static
|
||||
│ └── templates
|
||||
└── venv
|
||||
├── bin
|
||||
│ ├── activate
|
||||
│ ├── activate.csh
|
||||
│ ├── activate.fish
|
||||
│ ├── celery
|
||||
│ ├── celerybeat
|
||||
│ ├── celeryd
|
||||
│ ├── celeryd-multi
|
||||
│ ├── coverage
|
||||
│ ├── coverage3
|
||||
│ ├── coverage-3.7
|
||||
│ ├── django-admin
|
||||
│ ├── django-admin.py
|
||||
│ ├── easy_install
|
||||
│ ├── easy_install-3.7
|
||||
│ ├── pip
|
||||
│ ├── pip3
|
||||
│ ├── pip3.7
|
||||
│ ├── __pycache__
|
||||
│ ├── pyrsa-decrypt
|
||||
│ ├── pyrsa-decrypt-bigfile
|
||||
│ ├── pyrsa-encrypt
|
||||
│ ├── pyrsa-encrypt-bigfile
|
||||
│ ├── pyrsa-keygen
|
||||
│ ├── pyrsa-priv2pub
|
||||
│ ├── pyrsa-sign
|
||||
│ ├── pyrsa-verify
|
||||
│ ├── python -> python3
|
||||
│ ├── python3 -> /usr/bin/python3
|
||||
│ └── uwsgi
|
||||
├── include
|
||||
├── lib
|
||||
│ └── python3.7
|
||||
├── lib64 -> lib
|
||||
├── pip-selfcheck.json
|
||||
└── pyvenv.cfg
|
||||
```
|
||||
|
||||
下面以阿里云为例,简单说明如何为项目注册域名、解析域名以及购买权威机构颁发的证书。
|
||||
|
||||
1. [注册域名](https://wanwang.aliyun.com/domain/)。
|
||||
|
||||
![](./res/aliyun-domain.png)
|
||||
|
||||
2. [域名备案](https://beian.aliyun.com/)。
|
||||
|
||||
![](./res/aliyun-keeprecord.png)
|
||||
|
||||
3. [域名解析](https://dns.console.aliyun.com/#/dns/domainList)。
|
||||
|
||||
![](./res/aliyun-dnslist.png)
|
||||
|
||||
![](./res/aliyun-resolve-settings.png)
|
||||
|
||||
4. [购买证书](https://www.aliyun.com/product/cas)。
|
||||
|
||||
![](./res/aliyun-certificate.png)
|
||||
|
||||
### uWSGI的配置
|
||||
|
||||
1. 在`project`目录下创建并激活虚拟环境。
|
||||
|
||||
```Shell
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
```
|
||||
|
||||
2. 安装项目依赖项。
|
||||
|
||||
```Shell
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
3. 通过pip安装uWSGI。
|
||||
|
||||
```Shell
|
||||
pip install uwsgi
|
||||
```
|
||||
|
||||
4. 修改uWSGI的配置文件(`/root/project/conf/uwsgi.ini`)。
|
||||
|
||||
```INI
|
||||
[uwsgi]
|
||||
# 配置前导路径
|
||||
base=/root/project
|
||||
# 配置项目名称
|
||||
name=fangtx
|
||||
# 守护进程
|
||||
master=true
|
||||
# 进程个数
|
||||
processes=4
|
||||
# 虚拟环境
|
||||
pythonhome=%(base)/venv
|
||||
# 项目地址
|
||||
chdir=%(base)/code/%(name)
|
||||
# 指定python解释器
|
||||
pythonpath=%(pythonhome)/bin/python
|
||||
# 指定uwsgi文件
|
||||
module=%(name).wsgi
|
||||
# 通信的地址和端口(自己服务器的IP地址和端口)
|
||||
socket=172.18.61.250:8000
|
||||
# 日志文件地址
|
||||
logto=%(base)/logs/uwsgi.log
|
||||
```
|
||||
|
||||
> 说明:可以先将“通信的地址和端口”项等号前面改为http来进行测试,如果没有问题再改回成socket,然后通过Nginx来实现项目的“动静分离”(静态资源交给Nginx处理,动态内容交给 uWSGI处理)。按照下面的方式可以启动uWSGI服务器。
|
||||
|
||||
5. 启动服务器。
|
||||
|
||||
```Shell
|
||||
uwsgi --ini conf/uwsgi.ini
|
||||
```
|
||||
|
||||
### Nginx的配置
|
||||
|
||||
1. 安装Nginx。
|
||||
|
||||
```Shell
|
||||
yum -y install nginx
|
||||
```
|
||||
|
||||
2. 修改全局配置文件(`/etc/nginx/nginx.conf`)。
|
||||
|
||||
```Nginx
|
||||
# 配置用户
|
||||
user root;
|
||||
# 工作进程数(建议跟CPU的核数量一致)
|
||||
worker_processes auto;
|
||||
# 错误日志
|
||||
error_log /var/log/nginx/error.log;
|
||||
# 进程文件
|
||||
pid /run/nginx.pid;
|
||||
# 包含其他的配置
|
||||
include /usr/share/nginx/modules/*.conf;
|
||||
# 工作模式(多路IO复用方式)和连接上限
|
||||
events {
|
||||
use epoll;
|
||||
worker_connections 1024;
|
||||
}
|
||||
# HTTP服务器相关配置
|
||||
http {
|
||||
# 日志格式
|
||||
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 /var/log/nginx/access.log main;
|
||||
# 开启高效文件传输模式
|
||||
sendfile on;
|
||||
# 用sendfile传输文件时有利于改善性能
|
||||
tcp_nopush on;
|
||||
# 禁用Nagle来解决交互性问题
|
||||
tcp_nodelay on;
|
||||
# 客户端保持连接时间
|
||||
keepalive_timeout 30;
|
||||
types_hash_max_size 2048;
|
||||
# 包含MIME类型的配置
|
||||
include /etc/nginx/mime.types;
|
||||
# 默认使用二进制流格式
|
||||
default_type application/octet-stream;
|
||||
# 包含其他配置文件
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
# 包含项目的Nginx配置文件
|
||||
include /root/project/conf/*.conf;
|
||||
}
|
||||
```
|
||||
|
||||
3. 编辑局部配置文件(`/root/project/conf/nginx.conf`)。
|
||||
|
||||
```Nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
access_log /root/project/logs/access.log;
|
||||
error_log /root/project/logs/error.log;
|
||||
location / {
|
||||
include uwsgi_params;
|
||||
uwsgi_pass 172.18.61.250:8000;
|
||||
}
|
||||
location /static/ {
|
||||
alias /root/project/static/;
|
||||
expires 30d;
|
||||
}
|
||||
}
|
||||
server {
|
||||
listen 443;
|
||||
server_name _;
|
||||
ssl on;
|
||||
access_log /root/project/logs/access.log;
|
||||
error_log /root/project/logs/error.log;
|
||||
ssl_certificate /root/project/conf/cert/214915882850706.pem;
|
||||
ssl_certificate_key /root/project/conf/cert/214915882850706.key;
|
||||
ssl_session_timeout 5m;
|
||||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
location / {
|
||||
include uwsgi_params;
|
||||
uwsgi_pass 172.18.61.250:8000;
|
||||
}
|
||||
location /static/ {
|
||||
alias /root/project/static/;
|
||||
expires 30d;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
到此为止,我们可以启动Nginx来访问我们的应用程序,HTTP和HTTPS都是没有问题的,如果Nginx已经运行,在修改配置文件后,我们可以用下面的命令重新启动Nginx。
|
||||
|
||||
4. 重启Nginx服务器。
|
||||
|
||||
```Shell
|
||||
nginx -s reload
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```Shell
|
||||
systemctl restart nginx
|
||||
```
|
||||
|
||||
> 说明:可以对Django项目使用`python manage.py collectstatic`命令将静态资源收集到指定目录下,要做到这点只需要在项目的配置文件`settings.py`中添加`STATIC_ROOT`配置即可。
|
||||
|
||||
#### 负载均衡配置
|
||||
|
||||
下面的配置中我们使用Nginx实现负载均衡,为另外的三个Nginx服务器(通过Docker创建)提供反向代理服务。
|
||||
|
||||
```Shell
|
||||
docker run -d -p 801:80 --name nginx1 nginx:latest
|
||||
docker run -d -p 802:80 --name nginx2 nginx:latest
|
||||
docker run -d -p 803:80 --name nginx3 nginx:latest
|
||||
```
|
||||
|
||||
```Nginx
|
||||
user root;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log;
|
||||
pid /run/nginx.pid;
|
||||
|
||||
include /usr/share/nginx/modules/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
# 为HTTP服务配置负载均衡
|
||||
http {
|
||||
upstream fangtx {
|
||||
server 172.18.61.250:801 weight=4;
|
||||
server 172.18.61.250:802 weight=2;
|
||||
server 172.18.61.250:803 weight=2;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
|
||||
ssl on;
|
||||
access_log /root/project/logs/access.log;
|
||||
error_log /root/project/logs/error.log;
|
||||
ssl_certificate /root/project/conf/cert/214915882850706.pem;
|
||||
ssl_certificate_key /root/project/conf/cert/214915882850706.key;
|
||||
ssl_session_timeout 5m;
|
||||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
location / {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_buffering off;
|
||||
proxy_pass http://fangtx;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 说明:Nginx在配置负载均衡时,默认使用WRR(加权轮询算法),除此之外还支持ip_hash、fair(需要安装upstream_fair模块)和url_hash算法。此外,在配置upstream模块时可以指定服务器的状态值,包括:backup(备份机器,其他服务器不可用时才将请求分配到该机器)、down、fail_timeout(请求失败达到max_fails后的暂停服务时间)、max_fails(允许请求失败的次数)和weight(轮询的权重)。
|
||||
|
||||
### Keepalived
|
||||
|
||||
当使用Nginx进行负载均衡配置时,要考虑负载均衡服务器宕机的情况。为此可以使用Keepalived来实现负载均衡主机和备机的热切换,从而保证系统的高可用性。Keepalived的配置还是比较复杂,通常由专门做运维的人进行配置,一个基本的配置可以参照[《Keepalived的配置和使用》](https://www.jianshu.com/p/dd93bc6d45f5)。
|
||||
|
||||
### MySQL主从复制
|
||||
|
||||
下面还是基于Docker来演示如何配置MySQL主从复制。我们事先准备好MySQL的配置文件以及保存MySQL数据和运行日志的目录,然后通过Docker的数据卷映射来指定容器的配置、数据和日志文件的位置。
|
||||
|
||||
```Shell
|
||||
root
|
||||
└── mysql
|
||||
├── conf
|
||||
│ ├── master
|
||||
│ │ └── mysqld.cnf
|
||||
│ ├── slave1
|
||||
│ │ └── mysqld.cnf
|
||||
│ ├── slave2
|
||||
│ │ └── mysqld.cnf
|
||||
│ └── slave3
|
||||
│ └── mysqld.cnf
|
||||
└── data
|
||||
├── master
|
||||
├── slave1
|
||||
├── slave2
|
||||
└── slave3
|
||||
```
|
||||
|
||||
1. MySQL的配置文件(master和slave的配置文件需要不同的server-id)。
|
||||
|
||||
```
|
||||
[mysqld]
|
||||
pid-file=/var/run/mysqld/mysqld.pid
|
||||
socket=/var/run/mysqld/mysqld.sock
|
||||
datadir=/var/lib/mysql
|
||||
log-error=/var/log/mysql/error.log
|
||||
server-id=1
|
||||
log_bin=/var/log/mysql/mysql-bin.log
|
||||
expire_logs_days=30
|
||||
max_binlog_size=256M
|
||||
symbolic-links=0
|
||||
```
|
||||
|
||||
2. 创建和配置master。
|
||||
|
||||
```Shell
|
||||
docker run -d -p 3306:3306 --name mysql57 \
|
||||
-v /root/mysql/conf/master:/etc/mysql/mysql.conf.d \
|
||||
-v /root/mysql/data/master:/var/lib/mysql \
|
||||
-e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
|
||||
docker exec -it mysql57 /bin/bash
|
||||
```
|
||||
|
||||
```Shell
|
||||
mysql -u root -p
|
||||
Enter password:
|
||||
Welcome to the MySQL monitor. Commands end with ; or \g.
|
||||
Your MySQL connection id is 1
|
||||
Server version: 5.7.23-log MySQL Community Server (GPL)
|
||||
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
Oracle is a registered trademark of Oracle Corporation and/or its
|
||||
affiliates. Other names may be trademarks of their respective
|
||||
owners.
|
||||
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
|
||||
|
||||
mysql> grant replication slave on *.* to 'slave'@'%' identified by 'iamslave';
|
||||
Query OK, 0 rows affected, 1 warning (0.00 sec)
|
||||
|
||||
mysql> flush privileges;
|
||||
Query OK, 0 rows affected (0.00 sec)
|
||||
|
||||
mysql> show master status;
|
||||
+------------------+----------+--------------+------------------+-------------------+
|
||||
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
|
||||
+------------------+----------+--------------+------------------+-------------------+
|
||||
| mysql-bin.000001 | 590 | | | |
|
||||
+------------------+----------+--------------+------------------+-------------------+
|
||||
1 row in set (0.00 sec)
|
||||
|
||||
mysql> quit
|
||||
Bye
|
||||
exit
|
||||
```
|
||||
|
||||
上面创建Docker容器时使用的`-v`参数(`--volume`)表示映射数据卷,冒号前是宿主机的目录,冒号后是容器中的目录,这样相当于将宿主机中的目录挂载到了容器中。
|
||||
|
||||
3. 创建和配置slave。
|
||||
|
||||
```Shell
|
||||
docker run -d -p 3307:3306 --name mysql57-slave-1 \
|
||||
-v /root/mysql/conf/slave1:/etc/mysql/mysql.conf.d \
|
||||
-v /root/mysql/data/slave1:/var/lib/mysql \
|
||||
-e MYSQL_ROOT_PASSWORD=123456 \
|
||||
--link mysql57:mysql57 mysql:5.7
|
||||
docker exec -it mysql57-slave-1 /bin/bash
|
||||
```
|
||||
|
||||
```Shell
|
||||
mysql -u root -p
|
||||
Enter password:
|
||||
Welcome to the MySQL monitor. Commands end with ; or \g.
|
||||
Your MySQL connection id is 2
|
||||
Server version: 5.7.23-log MySQL Community Server (GPL)
|
||||
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
Oracle is a registered trademark of Oracle Corporation and/or its
|
||||
affiliates. Other names may be trademarks of their respective
|
||||
owners.
|
||||
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
|
||||
|
||||
mysql> reset slave;
|
||||
Query OK, 0 rows affected (0.02 sec)
|
||||
|
||||
mysql> change master to master_host='mysql57', master_user='slave', master_password='iamslave', master_log_file='mysql-bin.000003', master_log_pos=590;
|
||||
Query OK, 0 rows affected, 2 warnings (0.03 sec)
|
||||
|
||||
mysql> start slave;
|
||||
Query OK, 0 rows affected (0.01 sec)
|
||||
|
||||
mysql> show slave status\G
|
||||
*************************** 1. row ***************************
|
||||
Slave_IO_State: Waiting for master to send event
|
||||
Master_Host: mysql57
|
||||
Master_User: slave
|
||||
Master_Port: 3306
|
||||
Connect_Retry: 60
|
||||
Master_Log_File: mysql-bin.000001
|
||||
Read_Master_Log_Pos: 590
|
||||
Relay_Log_File: f352f05eb9d0-relay-bin.000002
|
||||
Relay_Log_Pos: 320
|
||||
Relay_Master_Log_File: mysql-bin.000001
|
||||
Slave_IO_Running: Yes
|
||||
Slave_SQL_Running: Yes
|
||||
Replicate_Do_DB:
|
||||
Replicate_Ignore_DB:
|
||||
Replicate_Do_Table:
|
||||
Replicate_Ignore_Table:
|
||||
Replicate_Wild_Do_Table:
|
||||
Replicate_Wild_Ignore_Table:
|
||||
Last_Errno: 0
|
||||
Last_Error:
|
||||
Skip_Counter: 0
|
||||
Exec_Master_Log_Pos: 590
|
||||
Relay_Log_Space: 534
|
||||
Until_Condition: None
|
||||
Until_Log_File:
|
||||
Until_Log_Pos: 0
|
||||
Master_SSL_Allowed: No
|
||||
Master_SSL_CA_File:
|
||||
Master_SSL_CA_Path:
|
||||
Master_SSL_Cert:
|
||||
Master_SSL_Cipher:
|
||||
Master_SSL_Key:
|
||||
Seconds_Behind_Master: 0
|
||||
Master_SSL_Verify_Server_Cert: No
|
||||
Last_IO_Errno: 0
|
||||
Last_IO_Error:
|
||||
Last_SQL_Errno: 0
|
||||
Last_SQL_Error:
|
||||
Replicate_Ignore_Server_Ids:
|
||||
Master_Server_Id: 1
|
||||
Master_UUID: 30c38043-ada1-11e8-8fa1-0242ac110002
|
||||
Master_Info_File: /var/lib/mysql/master.info
|
||||
SQL_Delay: 0
|
||||
SQL_Remaining_Delay: NULL
|
||||
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
|
||||
Master_Retry_Count: 86400
|
||||
Master_Bind:
|
||||
Last_IO_Error_Timestamp:
|
||||
Last_SQL_Error_Timestamp:
|
||||
Master_SSL_Crl:
|
||||
Master_SSL_Crlpath:
|
||||
Retrieved_Gtid_Set:
|
||||
Executed_Gtid_Set:
|
||||
Auto_Position: 0
|
||||
Replicate_Rewrite_DB:
|
||||
Channel_Name:
|
||||
Master_TLS_Version:
|
||||
1 row in set (0.00 sec)
|
||||
|
||||
mysql> quit
|
||||
Bye
|
||||
exit
|
||||
```
|
||||
|
||||
接下来可以如法炮制配置出slave2和slave3,这样就可以搭建起一个“一主带三从”的主从复制环境。上面创建创建容器时使用的`--link`参数用来配置容器在网络上的主机名(网络地址别名),下一节有这个知识点的介绍。
|
||||
|
||||
### Docker
|
||||
|
||||
事实上,项目上线中最为麻烦的事情就是配置软件运行环境,环境的差异会给软件的安装和部署带来诸多的麻烦,而Docker正好可以解决这个问题。关于Docker在之前的文档中我们已经介绍过了,接下来我们对Docker的知识做一些必要的补充。
|
||||
|
||||
1. 创建镜像文件。
|
||||
|
||||
将容器保存成镜像:
|
||||
|
||||
```Shell
|
||||
docker commit -m "..." -a "..." <container-name> jackfrued/<image-name>
|
||||
```
|
||||
|
||||
使用Dockerfile构建镜像:
|
||||
|
||||
```Dockerfile
|
||||
# 指定基础镜像文件
|
||||
FROM centos:latest
|
||||
|
||||
# 指定维护者信息
|
||||
MAINTAINER jackfrued
|
||||
|
||||
# 执行命令
|
||||
RUN yum -y install gcc
|
||||
RUN cd ~
|
||||
RUN mkdir -p project/code
|
||||
RUN mkdir -p project/logs
|
||||
|
||||
# 拷贝文件
|
||||
COPY ...
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE ...
|
||||
|
||||
# 在容器启动时执行命令
|
||||
CMD ~/init.sh
|
||||
```
|
||||
|
||||
```Shell
|
||||
docker build -t jackfrued/<image-name> .
|
||||
```
|
||||
|
||||
2. 镜像的导入和导出。
|
||||
|
||||
```Shell
|
||||
docker save -o <file-name>.tar <image-name>:<version>
|
||||
docker load -i <file-name>.tar
|
||||
```
|
||||
|
||||
3. 推送到DockerHub服务器。
|
||||
|
||||
```Shell
|
||||
docker tag <image-name>:<version> jackfrued/<name>
|
||||
docker login
|
||||
docker push jackfrued/<name>
|
||||
```
|
||||
|
||||
4. 容器之间的通信。
|
||||
|
||||
```Shell
|
||||
docker run --link <container-name>:<alias-name>
|
||||
```
|
||||
|
||||
|
||||
如果我们能够在Docker中完成项目的部署,并且将整个部署好的容器打包成镜像文件进行分发和安装,这样就可以解决项目在多个节点上进行部署时可能遇到的麻烦,而且整个部署可以在很短的时间内完成。
|
||||
|
||||
### Supervisor
|
||||
|
||||
[Supervisor](https://github.com/Supervisor/supervisor)是一个用Python写的进程管理工具,可以很方便的用来在类Unix系统下启动、重启(自动重启程序)和关闭进程。
|
||||
|
||||
1. 安装Supervisor。
|
||||
|
||||
```Shell
|
||||
yum -y install supervisor
|
||||
```
|
||||
|
||||
2. 查看Supervisor的配置文件。
|
||||
|
||||
```Shell
|
||||
vim /etc/supervisord.conf
|
||||
```
|
||||
|
||||
```INI
|
||||
; 此处省略上面的代码
|
||||
; The [include] section can just contain the "files" setting. This
|
||||
; setting can list multiple files (separated by whitespace or
|
||||
; newlines). It can also contain wildcards. The filenames are
|
||||
; interpreted as relative to this file. Included files *cannot*
|
||||
; include files themselves.
|
||||
[include]
|
||||
files = supervisord.d/*.ini
|
||||
```
|
||||
|
||||
可以看出自定义的管理配置代码可以放在`/etc/supervisord.d`目录中,并且文件名以`ini`作为后缀即可。
|
||||
|
||||
3. 编写管理配置代码。
|
||||
|
||||
```Shell
|
||||
cd /etc/supervisord.d
|
||||
vim fangtx.ini
|
||||
```
|
||||
|
||||
```INI
|
||||
|
||||
```
|
||||
|
||||
4. 启动Supervisor服务和查看状态。
|
||||
|
||||
```Shell
|
||||
systemctl start supervisord
|
||||
supervisorctl status
|
||||
```
|
||||
|
||||
### 其他服务
|
||||
|
||||
1. 常用开源软件。
|
||||
|
||||
| 功能 | 开源方案 |
|
||||
| ------------------- | ------------------------- |
|
||||
| 版本控制工具 | Git、Mercurial、SVN |
|
||||
| 缺陷管理 | Redmine、Mantis |
|
||||
| 负载均衡 | Nginx、LVS、HAProxy |
|
||||
| 邮件服务 | Postfix、Sendmail |
|
||||
| HTTP服务 | Nginx、Apache |
|
||||
| 消息队列 | RabbitMQ、ZeroMQ、Redis |
|
||||
| 文件系统 | FastDFS |
|
||||
| 基于位置服务(LBS) | MongoDB、Redis |
|
||||
| 监控服务 | Nagios、Zabbix |
|
||||
| 关系型数据库 | MySQL、PostgreSQL |
|
||||
| 非关系型数据库 | MongoDB、Redis、Cassandra |
|
||||
| 搜索引擎 | ElasticSearch、Solr |
|
||||
| 缓存服务 | Mamcached、Redis |
|
||||
|
||||
2. 常用云服务。
|
||||
|
||||
| 功能 | 可用的云服务 |
|
||||
| -------------- | --------------------------------------- |
|
||||
| 团队协作工具 | Teambition、钉钉 |
|
||||
| 代码托管平台 | Github、Gitee、CODING |
|
||||
| 邮件服务 | SendCloud |
|
||||
| 云存储(CDN) | 七牛、OSS、LeanCloud、Bmob、又拍云、AWS |
|
||||
| 移动端推送 | 极光、友盟、百度 |
|
||||
| 即时通信 | 环信、融云 |
|
||||
| 短信服务 | 云片、极光、Luosimao、又拍云 |
|
||||
| 第三方登录 | 友盟、ShareSDK |
|
||||
| 网站监控和统计 | 阿里云监控、监控宝、百度云观测、小鸟云 |
|
||||
|
11
README.md
|
@ -145,19 +145,26 @@
|
|||
- 使用进程 - fork函数 / multiprocessing模块 / 进程池 / 进程间通信
|
||||
- 使用线程 - thread模块 / threading模块 / Thread类 / Lock类
|
||||
|
||||
#### Day14 - [网络编程入门](./Day01-15/Day14/网络编程入门.md)
|
||||
#### Day14-A - [网络编程入门](./Day01-15/Day14/网络编程入门.md)
|
||||
|
||||
- 计算机网络基础 - 计算机网络发展史 / “TCP-IP”模型 / IP地址 / 端口 / 协议 / 其他相关概念
|
||||
- 网络应用架构 - “客户端-服务器”架构 / “浏览器-服务器”架构
|
||||
- Python网络编程 - 套接字的概念 / socket模块 / socket函数 / 创建TCP服务器 / 创建TCP客户端 / 创建UDP服务器 / 创建UDP客户端 / SocketServer模块
|
||||
|
||||
#### Day15 - [网络应用开发](./Day01-15/Day15/网络应用开发.md)
|
||||
#### Day14-B - [网络应用开发](./Day01-15/Day15/网络应用开发.md)
|
||||
|
||||
- 访问网络API - 网络API概述 / 访问URL / requests模块 / 解析JSON格式数据
|
||||
- 文件传输 - FTP协议 / ftplib模块 / 交互式FTP应用
|
||||
- 电子邮件 - SMTP协议 / POP3协议 / IMAP协议 / smtplib模块 / poplib模块 / imaplib模块
|
||||
- 短信服务 - twilio模块 / 国内的短信服务
|
||||
|
||||
#### Day15 - 图像和文档处理
|
||||
|
||||
- 用Pillow处理图片
|
||||
- 读写Word文档
|
||||
- 读写Excel文件
|
||||
- 生成PDF文件
|
||||
|
||||
### Day16~Day20 - [Python语言进阶 ](./Day16-20/Python语言进阶.md)
|
||||
|
||||
- 常用数据结构
|
||||
|
|
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 110 KiB |
Before Width: | Height: | Size: 113 KiB |
Before Width: | Height: | Size: 158 KiB |
Before Width: | Height: | Size: 1.0 MiB |
|
@ -1,4 +1,4 @@
|
|||
## 玩转PyCharm(上)
|
||||
## 玩转PyCharm
|
||||
|
||||
PyCharm是由JetBrains公司开发的提供给Python专业的开发者的一个集成开发环境,它最大的优点是能够大大提升Python开发者的工作效率,为开发者集成了很多用起来非常顺手的功能,包括代码调试、高亮语法、代码跳转、智能提示、自动补全、单元测试、版本控制等等。此外,PyCharm还提供了对一些高级功能的支持,包括支持基于Django框架的Web开发、。
|
||||
|
||||
|
|