Python和Web–模块cgi的简单用例
这两天学习Python Web编程的相关知识,其中一项是使用CGI(通用网关接口)技术。CGI是一种标准机制,属于服务器端,Web服务器可通过它将(通常是通过Web表达提供的)查询交给专用程序(如你编写的Python程序),并以网页的方式显示查询结果。要让CGI脚本能够通过Web进行访问(和运行),必须 将其放在Web服务器能够访问的地方、添加#!并设置合适的文件权限。
- 第一步:准备Web服务器
本人使用的是macOS系统,操作系统自带Apache Web服务器,要开启这个服务。我只是想尝试使用CGI,所以只在Python中使用模块http.server直接运行一个临时Web服务器。与其他模块一样,通过向Python可执行文件提供开关-m来导入并运行这个模块。同时指定–cgi,启动的服务器支持CGI。命令如下:
(venv) liuxiaowei@MacBookAir% python -m http.server --cgi
Serving HTTP on :: port 8000 (http://[::]:8000/) ...
如果现在将浏览器地址栏输入http://127.0.0.1:8000或http://localhost:8000 ,将看到运行这个服务器所在的目录内容。CGI程序也必须放在通过Web访问的目录中。另外,必须将其标识为CGI脚本,以免Web服务器以网页的方式提供其源代码。为此有两种常用方式:
§ 将脚本放在子目录cgi-bin中
如下图:
§ 将脚本文件的扩展名指定为.cgi
- 第二步:添加#!行
将脚本放在正确的位置(还可能给它指定特定的文件扩展名)后, 必须在其开头添加一个#!行。通过添加#!行,无须显示地执行Python解释器就能执行脚本。平时的话只是提供了便利,但对CGI脚本来说意义重大,因为如果没有#!行,Web服务器将不知道如何执行脚本。一般而言,只需在脚本开头添加如下行即可:
#!/usr/bin/env python3
注意:#!必须在第一行(之前没有空行)。如果这样不管用,就得确定Python可执行文件的绝对路径。并在#!行中添加。如下:
#!/usr/bin/python3
备注:本人系统同时安装了Python2和Python3,所以我执行的是python3。
- 第三步:设置文件权限
必须确保谁都可以读取 和执行脚本文件(否则Web服务器将无法运行它),同时确保只有你才能写入(这样其他人都不能修改你的脚本)。本人的系统是macOS系统,所以修改文件权限的命令如下:
chmod 755 simeple.cgi
通常,CGI脚本不能修改计算机上的任何文件。要让它能够修改文件,必须显式地赋予它权限。
- 简单的CGI脚本
代码如下:
#!/usr/bin/env python
print("Conent-type: text/plain") # 指出这个网页是纯文本的,要指出网页是HTML的,应修改text/html
print()
print("hello, world!")
结果如下图:
- 使用模块cgi
CGI脚本不只生成输出,输入是通过HTML表单以键-值对(字段)的方式提供给CGI脚本的。在CGI脚本中, 可以使用模块cgi 中的FieldStorage类来获取这些字段。当你创建FieldStorage实例(应只创建一个)时,它将从请求中取回输入变量(字段),并通过一个类似于字典的接口将它们提供给脚本。命令格式如下:
form = cgi.FieldStorage()
name = form.getvalue('name', 'Unknown')
这里提供了一个默认值(‘Unknown’),如果没有提供,默认值就是None。从FieldStorage中获取单个值的CGI脚本,示例代码如下:
#!/usr/bin/env python
import cgi
form = cgi.FieldStorage()
name = form.getvalue("name", "world")
print("Content_type: text/plain\n")
print("Hello, {}!".format(name))
运行结果如下:
表单默认值是world,CGI脚本的输入通常来自提交的表单,但是调用CGI脚本也可以直接指定参数。也就是在浏览器地址栏输入的URL后面加上问号变量名=值。如:http://127.0.0.1:8000/cgi-bin/simple2.cgi?name=xiaowei,如下图:
- 简单的表单
创建用户提交的的表单,这个表单可以是独立的页面,在此将它放在脚本中实现。从CGI脚本中获取信息的主要方式有两种:方法GET和方法POST,GET用于获取信息并在URL中进行查询编码,而POST可用于任何类型的查询,但对查询进行编码的方式稍有不同。下面以包含HTML表单的问候脚本为例,我是用python编写一个小程序,直接生成一个cgi脚本文件。生成cgi脚本的小程序非常简单,就是利用‘with open‘,'w’模式。源码如下:
#_*_coding:utf-8_*_
# 作者 :liuxiaowei
# 创建时间 :3/9/22 11:02 AM
# 文件 :simple3.py
# IDE :PyCharm
with open('simple3.cgi', 'w') as f:
f.write('#!/usr/bin/env python\n\nimport cgi\nform = cgi.FieldStorage()\n\nname = form.getvalue("name", "world")\n'
'print("""Content-type: text/html\n\n<html>\n\t<head>\n\t\t<title>Greeting Page</title>\n\t</head>\n\t<body>\n\t\t<h1>Hello, {}!</h1>\n\n\t\t<form action="simple3.cgi">\n\t\tChange name<input type="text" name = "name"/>\n\t\t<input type = "submit" />\n\t\t</form>\n\t</body>\n</html>""".format(name))')
执行之后生成的cgi脚本文件如下:
#!/usr/bin/env python
import cgi
form = cgi.FieldStorage()
name = form.getvalue("name", "world") # 参数name,默认值world,如果在浏览器中打开这个脚本没有提交任何值
# 将使用默认值
print("""Content-type: text/html
<html>
<head>
<title>Greeting Page</title>
</head>
<body>
<h1>Hello, {
}!</h1>
<form action="simple3.cgi">
Change name<input type="text" name = "name"/>
<input type = "submit" />
</form>
</body>
</html>""".format(name))
运行之后,输出了一个简单的HTML页面,其中标题包含参数name的值,另外这个页面还包含一个HTML表单,该表单的属性action被设置为脚本的名称(simple3.cgi)。意味着提交表单后,将再次运行这个脚本。这个表单只包含一个输入元素–名为name的文本框,因此如果在文本框中输入新名字并提交表单,标题将发生变化,结果如下图: