page 使用python做web_python page中控件的使用 - CSDN
精华内容
参与话题
  • 50.[Python]使用Selenium包做Web页面自动化测试详解

    万次阅读 多人点赞 2020-04-19 13:41:29
    详细介绍使用Python的Selenium包操作selenium进行web页面自动化测试的方法,包括操作各种浏览器(FF、Chrome、Opera、Safari),定位元素、上传文件、保存截图、处理弹窗等的技巧。

    载*请注明原始出处:http://blog.csdn.net/a464057216/article/details/52717464

    后续此博客不再更新,欢迎大家搜索关注微信公众号“测开之美”,测试开发工程师技术修炼小站,持续学习持续进步。
    在这里插入图片描述

    简介

    Selenium是ThoughtWorks公司为Web自动化测试开发的工具,除支持多种操作系统如Linux、Mac OS X、Windows外,还支持Chrome、Firefox、Safari、Opera、IE等多种浏览器,适合做Web应用的兼容性测试及自动化测试。在Web开发的持续集成中,如果每次迭代都采用手工方式对已有的功能进行回归测试,需要的人力、时间成本将是非常巨大的,采用Selenium进行自动化地回归测试,可以让团队的精力集中在新功能的测试上,提升工作效率。

    本文主要介绍在Python中使用Selenium包进行自动化测试的方法,您需要具备一些HTML的知识及搭建Web服务器的方法,这样才能在学习的过程中亲手做实验,另外完整的示例代码放在我的github项目上,欢迎大家访问。首先使用pip install selenium命令安装Python的Selenium包。针对不同的浏览器及其版本使用Selenium的方法会有所不同,如下是我的版本信息:

    • 操作系统:Mac OS Sierra
    • Python: 2.7.10
    • Selenium: 2.53.6
    • Firefox: 47.0.1
    • Safari: 10.0
    • Opera: 39.0
    • Chrome: 53

    使用方法

    访问页面

    Selenium运行自动化测试的方法是打开浏览器,按照脚本规定的步骤模拟人的操作,如点击按钮、在文本框输入文本等,然后检查期望结果。第一步就是要知道访问什么页面,比如测试使用Firefox访问百度:

    # -*- coding: utf-8 -*-
    
    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    
    # 目前支持的driver有Firefox, Chrome, IE和Remote等
    driver = webdriver.Firefox(executable_path="./geckodriver")
    # 直到页面被加载完(onload事件被触发)才将控制权返回脚本
    driver.get('https://www.baidu.com')
    assert u'百度一下,你就知道' in driver.title
    print u"当前URL:", driver.current_url
    

    对于使用了大量AJAX的页面,webdriver并不知道页面何时真正加载完成,这时需要使用waits告诉Selenium等待时间。

    Webdriver是Selenium能够实现跨浏览器自动化测试的关键,通常简称wd。不同浏览器有不同的wd,但对外提供了统一的接口调用各个浏览器自身的自动化测试接口。上面Firefox的webdriver请在此下载

    定位元素

    打开页面后,第二件事情就是定位到我们要操作的页面元素,定位单个页面元素有如下方法(下面的方法,如果没有定位到相应的元素,抛出NoSuchElementException异常):

    • find_element_by_id:通过id属性定位元素(返回第一个匹配的)。
    • find_element_by_name:通过name属性定位元素(返回第一个匹配的)。
    • find_element_by_xpath:通过xpath定位元素(返回第一个匹配的)。
    • find_element_by_link_text:通过超链接文本定位超链接元素,必须是完全匹配(返回第一个匹配的)。
    • find_element_by_partial_link_text:通过超链接文本定位超链接元素,可以是部分匹配(返回第一个匹配的)。
    • find_element_by_tag_name:通过标签名字定位元素(返回第一个匹配的)。
    • find_element_by_class_name:通过class属性定位元素(返回第一个匹配的)。
    • find_element_by_css_selector:使用CSS选择器语法定位元素(返回第一个匹配的)。

    上面的方法,对应的批量定位方法如下(返回对应网页元素的列表):

    • find_elements_by_name
    • find_elements_by_xpath
    • find_elements_by_link_text
    • find_elements_by_partial_link_text
    • find_elements_by_tag_name
    • find_elements_by_class_name
    • find_elements_by_css_selector

    此外,webdriver还有find_elementfind_elements方法定位元素:

    from selenium.webdriver.common.by import By
    
    driver.find_element(By.XPATH, '//button[text()="Some text"]')
    driver.find_elements(By.XPATH, '//button')
    

    By对象含有如下属性:

    • ID :元素id属性。
    • XPATH:xpath。
    • LINK_TEXT :超链接文本。
    • PARTIAL_LINK_TEXT :部分超链接文本。
    • NAME :元素name属性。
    • TAG_NAME :元素标签名字。
    • CLASS_NAME :元素class属性。
    • CSS_SELECTOR :使用CSS元素选择器语法。

    操作文本框元素

    比如在百度的输入框查询信息:

    elem = driver.find_element_by_name('wd')
    
    # 清空预填充内容
    elem.clear()
    # Keys对象表示键盘按键,如F1、ALT、ARROW_DOWN等
    elem.send_keys(u'48.HTTP基本认证与摘要认证', Keys.RETURN)
    
    assert u'Mars Loo的博客' in driver.page_source
    
    # quit方法关闭整个浏览器
    driver.quit()
    

    上传文件也可以采用send_keys方法,此时参数提供为文件的路径即可。

    操作表单元素

    定位到一个表单元素后,可以调用其submit方法提交表单:

    form = ff.find_element_by_name('survey')
    form.submit()
    

    如果调用submit方法的元素不是表单,抛出异常NoSuchElementException。提交表单也可以定位到提交按钮元素后,调用其click方法:

    submit = ff.find_element_by_id('submit')
    submit.click()
    

    操作select元素

    # 采用xpath获取第一个select元素(即使有多个也返回第一个)
    element = ff.find_element_by_xpath("//select[@name='car']")
    # 获取所有选项,打印选项值并点击
    all_options = element.find_elements_by_tag_name("option")
    for option in all_options:
        print "Value is: %s" % option.get_attribute("value")
        option.click()
    

    Selenium还提供了对<select>元素的抽象——Select对象:

    from selenium.webdriver.support.ui import Select
    
    select = Select(ff.find_element_by_xpath("//select[@name='car']"))
    select.select_by_visible_text("infinity")
    select.select_by_value("bmw")
    # 按照option的索引选择,第一个option的index为0
    select.select_by_index("0")
    

    对于允许多选以及有预选值的场景,可以做如下处理:

    select = Select(ff.find_element_by_xpath("//select[@name='car']"))
    # 获取所有已选项
    print select.all_selected_options
    # 去选所有选项
    select.deselect_all()
    # 获取所有可选项
    print select.options
    

    拖放元素

    selenium包目前还不支持HTML 5的拖放,一种解决方案是通过Javascript脚本及jQuery解决:

    jquery_url = "http://upcdn.b0.upaiyun.com/libs/jquery/jquery-2.0.2.min.js"
    
    ff = webdriver.Firefox(executable_path="./geckodriver")
    ff.get('http://html5demos.com/drag')
    
    ff.set_script_timeout(30)
    with open("load_jquery.js") as f:
        load_jquery_js = f.read()
    with open("drag_and_drop.js") as f:
        drag_and_drop_js = f.read()
    ff.execute_async_script(load_jquery_js, jquery_url)
    
    ff.execute_script(drag_and_drop_js +
                      "$('#one').simulateDragDrop({dropTarget:'#bin'});")
    

    load_jquery.jsdrag_and_drop.js请在我的github项目获取。

    在窗口和frame间切换

    在浏览器不同窗口之间切换的方法如下:

    a = ff.find_element_by_tag_name("a")
    
    # 保存原始窗口,window_handlers是目前wd打开的所有窗口的句柄列表
    prev = ff.window_handles[-1]
    
    # 点击超链接(targe="_blank")后,浏览器新窗口被激活
    a.click()
    
    # 保存新窗口
    new = ff.window_handles[-1]
    
    # 切换到原始窗口
    ff.switch_to_window(prev)
    print "Switch to prev success"
    
    # 切换到新窗口
    ff.switch_to_window(new)
    print "Switch to new success"
    

    因为HTML 5中不再建议使用<frameset>标签,所以以<iframe>为例说明如何在框架间切换:

    ff.switch_to_frame('frame1')
    element = ff.find_element_by_name('wd')
    element.clear()
    element.send_keys("This is a test")
    
    # 切换到顶级frame,然后才可以切换到其他iframe
    ff.switch_to_default_content()
    ff.switch_to_frame('frame2')
    element = ff.find_element_by_name('email')
    element.clear()
    element.send_keys("Input to Sohu")
    

    处理弹窗

    Javascript的角度,弹窗分为三种:alert、confirm和prompt。使用webdriver的switch_to_alert方法可以将焦点切换到当前的弹窗上,并返回一个Alert对象。
    如果是alert类型的窗口,点击取消或者确定都可以关闭该窗口:

    # 切换到当前弹出框并返回Alert对象
    alert = ff.switch_to_alert()
    # 获取弹出框的文本内容
    print "Alert text:", alert.text
    # 点击弹出框的确定按钮
    alert.accept()
    # 点击弹出框的取消按钮
    # alert.dismiss()
    

    如果是confirm类型的窗口,点击确定会给Javascript返回true,点击取消会给javascript返回false。如果是prompt类型的窗口,可以输入一段文本后再点击取消还是确定,如果点击取消会给Javascript返回null,如果点击确定会给Javascript返回输入的文本,因为弹出的prompt框默认会将其中可编辑的文本内容覆盖选中(见下图),所以Alert对象没有clear方法:

    这里写图片描述

    alert = ff.switch_to_alert()
    
    # 如果是prompt类型的弹出框,直接向其中输入内容
    alert.send_keys("This is my choice")
    # 然后点击prompt框的确定按钮
    alert.accept()
    

    处理HTTP基本认证及摘要认证

    HTTP基本认证和摘要认证的基本原理可以参考我的博文,这种认证弹窗不需要按照上面的方法处理,如果是Firefox浏览器,可以在浏览器中访问about:config进入配置界面将browser.safebrowsing.malware.enabled设置为true,此时Firefox就允许我们以scheme://username:password@domain/path?query#segment的形式访问网页了。设置好了以后,Selenium的脚本可以这样写:

    ff = webdriver.Firefox(executable_path="./geckodriver")
    ff.get('http://mars:loo@localhost:5000/')
    

    历史记录前进及后退

    通过webdriver的backforward方法,可以很方便地在历史记录中前进及后退:

    a = ff.find_element_by_tag_name('a')
    a.click()
    print "Go back"
    ff.back()
    print "Go forward"
    ff.forward()
    

    cookie

    处理cookie时,需要webdriver先访问到合法的cookie域,添加cookie然后重新访问即可,比如(namevalue字段分别表示cookie的键和值):

     ff.get('http://localhost:5000/')
     ff.add_cookie({'name': 'username', 'value': 'marsloo'})
     ff.get('http://localhost:5000/')
     # 获取当前域的cookies
     print ff.get_cookies()
    

    上述代码的输出可能为:

    [{u'domain': u'localhost', u'name': u'username', u'value': u'marsloo', u'expiry': None, u'path': u'', u'httpOnly': False, u'secure': False}]
    

    等待元素加载

    如果请求的页面使用了大量的AJAX,Selenium不会等待其请求完成后再将控制权交给脚本。为了正确定位到所需的元素,需要使用Selenium的等待功能,最简单的是这样:

    # 对于所有元素获取,会等待3秒
    ff.implicitly_wait(3)
    try:
        a = ff.find_element_by_partial_link_text('g')
        a.click()
    except NoSuchElementException:
        print "Page load fail or no such element"
    

    在每一个浏览器会话中只需要调用一次implicitly_wait方法。如果相对每个元素获取设置不同的超时时间,可以这样做(其他更详细的代码可以在我的github项目获取):

    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.common.exceptions import TimeoutException
    
    
    @auto_close
    def func():
        try:
            a = WebDriverWait(ff, 3).until(
                EC.presence_of_element_located((By.TAG_NAME, "p")))
            a.click()
        except TimeoutException:
            print "No such element"
    

    上述代码中的(By.TAG_NAME, "p")元组,在下面的解释中以locator参数代替。expected_conditions对象还有很多方法可以使用:

    • title_is(title):标题是title(完全匹配)。
    • title_contains(title):标题包含title(部分匹配)。
    • presence_of_element_located(locator):元素在DOM树上存在(但是不一定可见)。
    • visibility_of_element_located(locator):元素在DOM树上存在并且肉眼可见。
    • visibility_of(element):检查元素的肉眼可见性。
    • presence_of_all_elements_located(locator):元素们在DOM树上存在(但是不一定可见),locator返回的是元素的列表。
    • text_to_be_present_in_element(locator, text):某个元素的文本中是否包含text
    • text_to_be_present_in_element_value(locator, text):某个元素的value属性中是否包含text
    • frame_to_be_available_and_switch_to_it(locator):判断某个frame是否可操作,如果可以的话切换到该frame并返回True,否则返回False
    • invisibility_of_element_located(locator):元素不存在于DOM树或者不可见。
    • element_to_be_clickable(locator) :元素可见且是可点击状态。
    • staleness_of(element):元素从DOM树上移除。
    • element_to_be_selected(element):元素被选中。
    • element_located_to_be_selected(locator):元素被选中。
    • element_selection_state_to_be(element, bool):判断元素被选中的状体,bool参数中True表示选中,False表示未选中。
    • element_located_selection_state_to_be(locator, bool):判断元素被选中的状体,bool参数中True表示选中,False表示未选中。
    • alert_is_present:弹出了一个窗口。

    使用其他浏览器

    Chrome

    使用Chrome进行测试,需要先下载Chrome Driver (可能需要翻墙),解压缩后代码如下:

    driver = webdriver.Chrome(executable_path="./chromedriver")
    

    Opera

    首先下载Opera Driver,解压缩后代码如下:

    webdriver_service = service.Service('./operadriver')
    webdriver_service.start()
    driver = webdriver.Remote(webdriver_service.service_url,
                              webdriver.DesiredCapabilities.OPERA)
    
    driver.get('https://www.baidu.com')
    
    

    Safari

    Safari 10已经开始内置自动化测试的支持,Safari偏好设置->高级->在菜单栏中显示“开发”菜单,然后开发->允许远程自动化,最后下载Selenium Server的jar包,测试脚本如下:

    # -*- coding: utf-8 -*-
    
    from selenium import webdriver
    import time
    import os
    
    os.environ["SELENIUM_SERVER_JAR"] = "selenium-server-standalone-2.53.1.jar"
    
    # 设置quiet模式,否则会打印很多log
    driver = webdriver.Safari(quiet=True)
    driver.get('https://www.baidu.com')
    assert u'百度一下,你就知道' in driver.title
    print u"当前URL:", driver.current_url
    time.sleep(4)
    driver.quit()
    

    保存屏幕截图

    使用driver.save_screenshot(filename)可以保存浏览器的运行截图(默认是覆盖写入)。

    滚动至屏幕底部

    使用ff.execute_script("window.scrollTo(0, document.body.scrollHeight);")可以滚动至屏幕底部。

    如果觉得我的文章对您有帮助,欢迎关注我(CSDN:Mars Loo的博客)或者为这篇文章点赞,谢谢!

    展开全文
  • Python Flask Web 框架入门

    万次阅读 多人点赞 2019-03-11 15:03:27
    Flask是一个轻量级的基于Pythonweb框架。 本文适合有一定HTML、Python、网络基础的同学阅读。 1. 简介 这份文档中的代码使用 Python 3 运行。 是的,所以读者需要自己在电脑上安装Python 3 和 pip3。建议安装...

    Flask是一个轻量级的基于Python的web框架。

    本文适合有一定HTML、Python、网络基础的同学阅读。

    1. 简介

    这份文档中的代码使用 Python 3 运行。
    是的,所以读者需要自己在电脑上安装Python 3 和 pip3。建议安装最新版本,我使用的是Python 3.6.4
    安装方法,可以自行谷歌或者百度。
    建议在 linux 下实践本教程中命令行操作、执行代码。

    2. 安装

    通过pip3安装Flask即可:

    $ sudo pip3 install Flask
    

    进入python交互模式看下Flask的介绍和版本:

    $ python3
    
    >>> import flask
    >>> print(flask.__doc__)
    
        flask
        ~~~~~
    
        A microframework based on Werkzeug.  It's extensively documented
        and follows best practice patterns.
    
        :copyright: © 2010 by the Pallets team.
        :license: BSD, see LICENSE for more details.
    
    >>> print(flask.__version__)
    1.0.2
    

    3. 从 Hello World 开始

    本节主要内容:使用Flask写一个显示”Hello World!”的web程序,如何配置、调试Flask。

    3.1 Hello World

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    statictemplates目录是默认配置,其中static用来存放静态资源,例如图片、js、css文件等。templates存放模板文件。
    我们的网站逻辑基本在server.py文件中,当然,也可以给这个文件起其他的名字。

    server.py中加入以下内容:

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        return 'Hello World!'
    
    if __name__ == '__main__':
        app.run()
    

    运行server.py

    $ python3 server.py 
     * Running on http://127.0.0.1:5000/
    

    打开浏览器访问http://127.0.0.1:5000/,浏览页面上将出现Hello World!
    终端里会显示下面的信息:

    127.0.0.1 - - [16/May/2014 10:29:08] "GET / HTTP/1.1" 200 -
    

    变量app是一个Flask实例,通过下面的方式:

    @app.route('/')
    def hello_world():
        return 'Hello World!'
    

    当客户端访问/时,将响应hello_world()函数返回的内容。注意,这不是返回Hello World!这么简单,Hello World!只是HTTP响应报文的实体部分,状态码等信息既可以由Flask自动处理,也可以通过编程来制定。

    3.2 修改Flask的配置

    app = Flask(__name__)
    

    上面的代码中,python内置变量__name__的值是字符串__main__ 。Flask类将这个参数作为程序名称。当然这个是可以自定义的,比如app = Flask("my-app")

    Flask默认使用static目录存放静态资源,templates目录存放模板,这是可以通过设置参数更改的:

    app = Flask("my-app", static_folder="path1", template_folder="path2")
    

    更多参数请参考__doc__

    from flask import Flask
    print(Flask.__doc__)
    

    3.3 调试模式

    上面的server.py中以app.run()方式运行,这种方式下,如果服务器端出现错误是不会在客户端显示的。但是在开发环境中,显示错误信息是很有必要的,要显示错误信息,应该以下面的方式运行Flask:

    app.run(debug=True)
    

    debug设置为True的另一个好处是,程序启动后,会自动检测源码是否发生变化,若有变化则自动重启程序。这可以帮我们省下很多时间。

    3.4 绑定IP和端口

    默认情况下,Flask绑定IP为127.0.0.1,端口为5000。我们也可以通过下面的方式自定义:

    app.run(host='0.0.0.0', port=80, debug=True)
    

    0.0.0.0代表电脑所有的IP。80是HTTP网站服务的默认端口。什么是默认?比如,我们访问网站http://www.example.com,其实是访问的http://www.example.com:80,只不过:80可以省略不写。

    由于绑定了80端口,需要使用root权限运行server.py。也就是:

    $ sudo python3 server.py
    

    3.5 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-001

    4. 获取 URL 参数

    URL参数是出现在url中的键值对,例如http://127.0.0.1:5000/?disp=3中的url参数是{'disp':3}

    4.1 建立Flask项目

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    4.2 列出所有的url参数

    在server.py中添加以下内容:

    from flask import Flask, request
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_world():
        return request.args.__str__()
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    在浏览器中访问http://127.0.0.1:5000/?user=Flask&time&p=7&p=8,将显示:

    ImmutableMultiDict([('user', 'Flask'), ('time', ''), ('p', '7'), ('p', '8')])
    

    较新的浏览器也支持直接在url中输入中文(最新的火狐浏览器内部会帮忙将中文转换成符合URL规范的数据),在浏览器中访问http://127.0.0.1:5000/?info=这是爱,,将显示:

    ImmutableMultiDict([('info', '这是爱,')])
    

    浏览器传给我们的Flask服务的数据长什么样子呢?可以通过request.full_pathrequest.path来看一下:

    from flask import Flask, request
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_world():
        print(request.path)
        print(request.full_path)
        return request.args.__str__()
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    浏览器访问http://127.0.0.1:5000/?info=这是爱,,运行server.py的终端会输出:

    /
    /?info=%E8%BF%99%E6%98%AF%E7%88%B1%EF%BC%8C
    

    4.3 获取某个指定的参数

    例如,要获取键info对应的值,如下修改server.py

    from flask import Flask, request
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        return request.args.get('info')
    
    if __name__ == '__main__':
        app.run(port=5000)
    

    运行server.py,在浏览器中访问http://127.0.0.1:5000/?info=hello,浏览器将显示:

    hello
    

    不过,当我们访问http://127.0.0.1:5000/时候却出现了500错误,浏览器显示:

    如果开启了Debug模式,会显示:

    为什么为这样?

    这是因为没有在URL参数中找到info。所以request.args.get('info')返回Python内置的None,而Flask不允许返回None。

    解决方法很简单,我们先判断下它是不是None:

    from flask import Flask, request
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        r = request.args.get('info')
        if r==None:
            # do something
            return ''
        return r
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    
    

    另外一个方法是,设置默认值,也就是取不到数据时用这个值:

    from flask import Flask, request
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        r = request.args.get('info', 'hi')
        return r
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    函数request.args.get的第二个参数用来设置默认值。此时在浏览器访问http://127.0.0.1:5000/,将显示:

    hi
    

    4.4 如何处理多值

    还记得上面有一次请求是这样的吗? http://127.0.0.1:5000/?user=Flask&time&p=7&p=8,仔细看下,p有两个值。

    如果我们的代码是:

    from flask import Flask, request
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        r = request.args.get('p')
        return r
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    在浏览器中请求时,我们只会看到7。如果我们需要把p的所有值都获取到,该怎么办?

    不用get,用getlist

    from flask import Flask, request
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_world():
        r = request.args.getlist('p')  # 返回一个list
        return str(r)
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    浏览器输入 http://127.0.0.1:5000/?user=Flask&time&p=7&p=8,我们会看到['7', '8']

    4.5 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-002

    5. 获取POST方法传送的数据

    作为一种HTTP请求方法,POST用于向指定的资源提交要被处理的数据。我们在某网站注册用户、写文章等时候,需要将数据传递到网站服务器中。并不适合将数据放到URL参数中,密码放到URL参数中容易被看到,文章数据又太多,浏览器不一定支持太长长度的URL。这时,一般使用POST方法。

    本文使用python的requests库模拟浏览器。

    安装方法:

    $ sudo pip3 install requests
    

    5.1 建立Flask项目

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    5.2 查看POST数据内容

    以用户注册为例子,我们需要向服务器/register传送用户名name和密码password。如下编写HelloWorld/server.py

    from flask import Flask, request
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    
    @app.route('/register', methods=['POST'])
    def register():
        print(request.headers)
        print(request.stream.read())
        return 'welcome'
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    `@app.route(‘/register’, methods=[‘POST’])是指url/register只接受POST方法。可以根据需要修改methods`参数,例如如果想要让它同时支持GET和POST,这样写:

    @app.route('/register', methods=['GET', 'POST']) 
    

    浏览器模拟工具client.py内容如下:

    import requests
    
    user_info = {'name': 'letian', 'password': '123'}
    r = requests.post("http://127.0.0.1:5000/register", data=user_info)
    
    print(r.text)
    

    运行HelloWorld/server.py,然后运行client.pyclient.py将输出:

    welcome
    

    HelloWorld/server.py在终端中输出以下调试信息(通过print输出):

    Host: 127.0.0.1:5000
    User-Agent: python-requests/2.19.1
    Accept-Encoding: gzip, deflate
    Accept: */*
    Connection: keep-alive
    Content-Length: 24
    Content-Type: application/x-www-form-urlencoded
    
    
    b'name=letian&password=123'
    

    前6行是client.py生成的HTTP请求头,由print(request.headers)输出。

    请求体的数据,我们通过print(request.stream.read())输出,结果是:

    b'name=letian&password=123'
    

    5.3 解析POST数据

    上面,我们看到post的数据内容是:

    b'name=letian&password=123'
    

    我们要想办法把我们要的name、password提取出来,怎么做呢?自己写?不用,Flask已经内置了解析器request.form

    我们将服务代码改成:

    from flask import Flask, request
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    
    @app.route('/register', methods=['POST'])
    def register():
        print(request.headers)
        # print(request.stream.read()) # 不要用,否则下面的form取不到数据
        print(request.form)
        print(request.form['name'])
        print(request.form.get('name'))
        print(request.form.getlist('name'))
        print(request.form.get('nickname', default='little apple'))
        return 'welcome'
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    执行client.py请求数据,服务器代码会在终端输出:

    Host: 127.0.0.1:5000
    User-Agent: python-requests/2.19.1
    Accept-Encoding: gzip, deflate
    Accept: */*
    Connection: keep-alive
    Content-Length: 24
    Content-Type: application/x-www-form-urlencoded
    
    
    ImmutableMultiDict([('name', 'letian'), ('password', '123')])
    letian
    letian
    ['letian']
    little apple
    

    request.form会自动解析数据。

    request.form['name']request.form.get('name')都可以获取name对应的值。对于request.form.get()可以为参数default指定值以作为默认值。所以:

    print(request.form.get('nickname', default='little apple'))
    

    输出的是默认值

    little apple
    

    如果name有多个值,可以使用request.form.getlist('name'),该方法将返回一个列表。我们将client.py改一下:

    import requests
    
    user_info = {'name': ['letian', 'letian2'], 'password': '123'}
    r = requests.post("http://127.0.0.1:5000/register", data=user_info)
    
    print(r.text)
    

    此时运行client.pyprint(request.form.getlist('name'))将输出:

    [u'letian', u'letian2']
    

    5.4 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-003

    6. 处理和响应JSON数据

    使用 HTTP POST 方法传到网站服务器的数据格式可以有很多种,比如「5. 获取POST方法传送的数据」讲到的name=letian&password=123这种用过&符号分割的key-value键值对格式。我们也可以用JSON格式、XML格式。相比XML的重量、规范繁琐,JSON显得非常小巧和易用。

    6.1 建立Flask项目

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    6.2 处理JSON格式的请求数据

    如果POST的数据是JSON格式,request.json会自动将json数据转换成Python类型(字典或者列表)。

    编写server.py:

    from flask import Flask, request
    
    app = Flask("my-app")
    
    
    @app.route('/')
    def hello_world():
        return 'Hello World!'
    
    
    @app.route('/add', methods=['POST'])
    def add():
        print(request.headers)
        print(type(request.json))
        print(request.json)
        result = request.json['a'] + request.json['b']
        return str(result)
    
    
    if __name__ == '__main__':
        app.run(host='127.0.0.1', port=5000, debug=True)
    

    编写client.py模拟浏览器请求:

    import requests
    
    json_data = {'a': 1, 'b': 2}
    
    r = requests.post("http://127.0.0.1:5000/add", json=json_data)
    
    print(r.text)
    

    运行server.py,然后运行client.pyclient.py 会在终端输出:

    3
    

    server.py 会在终端输出:

    Host: 127.0.0.1:5000
    User-Agent: python-requests/2.19.1
    Accept-Encoding: gzip, deflate
    Accept: */*
    Connection: keep-alive
    Content-Length: 16
    Content-Type: application/json
    
    
    <class 'dict'>
    {'a': 1, 'b': 2}
    

    注意,请求头中Content-Type的值是application/json

    6.3 响应JSON-方案1

    响应JSON时,除了要把响应体改成JSON格式,响应头的Content-Type也要设置为application/json

    编写server2.py

    from flask import Flask, request, Response
    import json
    
    app = Flask("my-app")
    
    
    @app.route('/')
    def hello_world():
        return 'Hello World!'
    
    
    @app.route('/add', methods=['POST'])
    def add():
        result = {'sum': request.json['a'] + request.json['b']}
        return Response(json.dumps(result),  mimetype='application/json')
    
    
    if __name__ == '__main__':
        app.run(host='127.0.0.1', port=5000, debug=True)
    

    修改后运行。

    编写client2.py

    import requests
    
    json_data = {'a': 1, 'b': 2}
    
    r = requests.post("http://127.0.0.1:5000/add", json=json_data)
    
    print(r.headers)
    print(r.text)
    

    运行client.py,将显示:

    {'Content-Type': 'application/json', 'Content-Length': '10', 'Server': 'Werkzeug/0.14.1 Python/3.6.4', 'Date': 'Sat, 07 Jul 2018 05:23:00 GMT'}
    {"sum": 3}
    

    上面第一段内容是服务器的响应头,第二段内容是响应体,也就是服务器返回的JSON格式数据。

    另外,如果需要服务器的HTTP响应头具有更好的可定制性,比如自定义Server,可以如下修改add()函数:

    @app.route('/add', methods=['POST'])
    def add():
        result = {'sum': request.json['a'] + request.json['b']}
        resp = Response(json.dumps(result),  mimetype='application/json')
        resp.headers.add('Server', 'python flask')
        return resp
    

    client2.py运行后会输出:

    {'Content-Type': 'application/json', 'Content-Length': '10', 'Server': 'python flask', 'Date': 'Sat, 07 Jul 2018 05:26:40 GMT'}
    {"sum": 3}
    

    6.4 响应JSON-方案2

    使用 jsonify 工具函数即可。

    from flask import Flask, request, jsonify
    
    app = Flask("my-app")
    
    
    @app.route('/')
    def hello_world():
        return 'Hello World!'
    
    
    @app.route('/add', methods=['POST'])
    def add():
        result = {'sum': request.json['a'] + request.json['b']}
        return jsonify(result)
    
    
    if __name__ == '__main__':
        app.run(host='127.0.0.1', port=5000, debug=True)
    

    6.5 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-004

    7. 上传文件

    上传文件,一般也是用POST方法。

    7.1 建立Flask项目

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    7.2 上传文件

    这一部分的代码参考自How to upload a file to the server in Flask

    我们以上传图片为例:
    假设将上传的图片只允许’png’、’jpg’、’jpeg’、’gif’这四种格式,通过url/upload使用POST上传,上传的图片存放在服务器端的static/uploads目录下。

    首先在项目HelloWorld中创建目录static/uploads

    mkdir HelloWorld/static/uploads
    

    werkzeug库可以判断文件名是否安全,例如防止文件名是../../../a.png,安装这个库:

    $ sudo pip3 install werkzeug
    

    server.py代码:

    from flask import Flask, request
    
    from werkzeug.utils import secure_filename
    import os
    
    app = Flask(__name__)
    
    # 文件上传目录
    app.config['UPLOAD_FOLDER'] = 'static/uploads/'
    # 支持的文件格式
    app.config['ALLOWED_EXTENSIONS'] = {'png', 'jpg', 'jpeg', 'gif'}  # 集合类型
    
    
    # 判断文件名是否是我们支持的格式
    def allowed_file(filename):
        return '.' in filename and \
               filename.rsplit('.', 1)[1] in app.config['ALLOWED_EXTENSIONS']
    
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    
    @app.route('/upload', methods=['POST'])
    def upload():
        upload_file = request.files['image']
        if upload_file and allowed_file(upload_file.filename):
            filename = secure_filename(upload_file.filename)
            # 将文件保存到 static/uploads 目录,文件名同上传时使用的文件名
            upload_file.save(os.path.join(app.root_path, app.config['UPLOAD_FOLDER'], filename))
            return 'info is '+request.form.get('info', '')+'. success'
        else:
            return 'failed'
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    app.config中的config是字典的子类,可以用来设置自有的配置信息,也可以设置自己的配置信息。函数allowed_file(filename)用来判断filename是否有后缀以及后缀是否在app.config['ALLOWED_EXTENSIONS']中。

    客户端上传的图片必须以image01标识。upload_file是上传文件对应的对象。app.root_path获取server.py所在目录在文件系统中的绝对路径。upload_file.save(path)用来将upload_file保存在服务器的文件系统中,参数最好是绝对路径,否则会报错(网上很多代码都是使用相对路径,但是笔者在使用相对路径时总是报错,说找不到路径)。函数os.path.join()用来将使用合适的路径分隔符将路径组合起来。

    好了,定制客户端client.py

    import requests
    
    file_data = {'image': open('Lenna.jpg', 'rb')}
    
    user_info = {'info': 'Lenna'}
    
    r = requests.post("http://127.0.0.1:5000/upload", data=user_info, files=file_data)
    
    print(r.text)
    

    运行client.py,当前目录下的Lenna.jpg将上传到服务器。

    然后,我们可以在static/uploads中看到文件Lenna.jpg

    要控制上产文件的大小,可以设置请求实体的大小,例如:

    app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 #16MB
    

    不过,在处理上传文件时候,需要使用try:...except:...

    如果要获取上传文件的内容可以:

    file_content = request.files['image'].stream.read()
    

    7.3 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-005

    8. Restful URL

    简单来说,Restful URL可以看做是对 URL 参数的替代。

    8.1 建立Flask项目

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    8.2 编写代码

    编辑server.py:

    from flask import Flask
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    
    @app.route('/user/<username>')
    def user(username):
        print(username)
        print(type(username))
        return 'hello ' + username
    
    
    @app.route('/user/<username>/friends')
    def user_friends(username):
        print(username)
        print(type(username))
        return 'hello ' + username
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    运行HelloWorld/server.py。使用浏览器访问http://127.0.0.1:5000/user/letian,HelloWorld/server.py将输出:

    letian
    <class 'str'>
    

    而访问http://127.0.0.1:5000/user/letian/,响应为404 Not Found。

    浏览器访问http://127.0.0.1:5000/user/letian/friends,可以看到:

    Hello letian. They are your friends.
    

    HelloWorld/server.py输出:

    letian
    <class 'str'>
    

    8.3 转换类型

    由上面的示例可以看出,使用 Restful URL 得到的变量默认为str对象。如果我们需要通过分页显示查询结果,那么需要在url中有数字来指定页数。按照上面方法,可以在获取str类型页数变量后,将其转换为int类型。不过,还有更方便的方法,就是用flask内置的转换机制,即在route中指定该如何转换。

    新的服务器代码:

    from flask import Flask
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    
    @app.route('/page/<int:num>')
    def page(num):
        print(num)
        print(type(num))
        return 'hello world'
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    `@app.route(‘/page/int:num‘)`会将num变量自动转换成int类型。

    运行上面的程序,在浏览器中访问http://127.0.0.1:5000/page/1,HelloWorld/server.py将输出如下内容:

    1
    <class 'int'>
    

    如果访问的是http://127.0.0.1:5000/page/asd,我们会得到404响应。

    在官方资料中,说是有3个默认的转换器:

    int     accepts integers
    float     like int but for floating point values
    path     like the default but also accepts slashes
    

    看起来够用了。

    8.4 一个有趣的用法

    如下编写服务器代码:

    from flask import Flask
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    
    @app.route('/page/<int:num1>-<int:num2>')
    def page(num1, num2):
        print(num1)
        print(num2)
        return 'hello world'
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    在浏览器中访问http://127.0.0.1:5000/page/11-22HelloWorld/server.py会输出:

    11
    22
    

    8.5 编写转换器

    自定义的转换器是一个继承werkzeug.routing.BaseConverter的类,修改to_pythonto_url方法即可。to_python方法用于将url中的变量转换后供被`@app.route包装的函数使用,to_url方法用于flask.url_for`中的参数转换。

    下面是一个示例,将HelloWorld/server.py修改如下:

    from flask import Flask, url_for
    
    from werkzeug.routing import BaseConverter
    
    
    class MyIntConverter(BaseConverter):
    
        def __init__(self, url_map):
            super(MyIntConverter, self).__init__(url_map)
    
        def to_python(self, value):
            return int(value)
    
        def to_url(self, value):
            return value * 2
    
    
    app = Flask(__name__)
    app.url_map.converters['my_int'] = MyIntConverter
    
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    
    @app.route('/page/<my_int:num>')
    def page(num):
        print(num)
        print(url_for('page', num=123))   # page 对应的是 page函数 ,num 对应对应`/page/<my_int:num>`中的num,必须是str
        return 'hello world'
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    浏览器访问http://127.0.0.1:5000/page/123后,HelloWorld/server.py的输出信息是:

    123
    /page/123123
    

    8.6 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-006

    8.7 值得读

    理解RESTful架构

    9. 使用url_for生成链接

    工具函数url_for可以让你以软编码的形式生成url,提供开发效率。

    9.1 建立Flask项目

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    9.2 编写代码

    编辑HelloWorld/server.py

    from flask import Flask, url_for
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        pass
    
    @app.route('/user/<name>')
    def user(name):
        pass
    
    @app.route('/page/<int:num>')
    def page(num):
        pass
    
    @app.route('/test')
    def test():
        print(url_for('hello_world'))
        print(url_for('user', name='letian'))
        print(url_for('page', num=1, q='hadoop mapreduce 10%3'))
        print(url_for('static', filename='uploads/01.jpg'))
        return 'Hello'
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    运行HelloWorld/server.py。然后在浏览器中访问http://127.0.0.1:5000/testHelloWorld/server.py将输出以下信息:

    /
    /user/letian
    /page/1?q=hadoop+mapreduce+10%253
    /static/uploads/01.jpg
    

    9.3 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-007

    10. 使用redirect重定向网址

    redirect函数用于重定向,实现机制很简单,就是向客户端(浏览器)发送一个重定向的HTTP报文,浏览器会去访问报文中指定的url。

    10.1 建立Flask项目

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    10.2 编写代码

    使用redirect时,给它一个字符串类型的参数就行了。

    编辑HelloWorld/server.py

    from flask import Flask, url_for, redirect
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    @app.route('/test1')
    def test1():
        print('this is test1')
        return redirect(url_for('test2'))
    
    @app.route('/test2')
    def test2():
        print('this is test2')
        return 'this is test2'
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    运行HelloWorld/server.py,在浏览器中访问http://127.0.0.1:5000/test1,浏览器的url会变成http://127.0.0.1:5000/test2,并显示:

    this is test2
    

    10.3 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-008

    11. 使用Jinja2模板引擎

    模板引擎负责MVC中的V(view,视图)这一部分。Flask默认使用Jinja2模板引擎。

    Flask与模板相关的函数有:

    • flask.render_template(template_name_or_list, **context)
      Renders a template from the template folder with the given context.
    • flask.render_template_string(source, **context)
      Renders a template from the given template source string with the given context.
    • flask.get_template_attribute(template_name, attribute)
      Loads a macro (or variable) a template exports. This can be used to invoke a macro from within Python code.

    这其中常用的就是前两个函数。

    这个实例中使用了模板继承、if判断、for循环。

    11.1 建立Flask项目

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    11.2 创建并编辑HelloWorld/templates/default.html

    内容如下:

    <html>
    <head>
        <title>
            {% if page_title %}
                {{ page_title }}
            {% endif %}
        </title>
    </head>
    
    <body>
        {% block body %}{% endblock %}
    
    
    ```
    
    可以看到,在``标签中使用了if判断,如果给模板传递了`page_title`变量,显示之,否则,不显示。
    
    ``标签中定义了一个名为`body`的block,用来被其他模板文件继承。
    
    ### 11.3 创建并编辑HelloWorld/templates/user_info.html
    内容如下:
    
    ```
    {% extends "default.html" %}
    
    {% block body %}
        {% for key in user_info %}
    
            {{ key }}: {{ user_info[key] }} 
    
    
        {% endfor %}
    {% endblock %}
    

    变量user_info应该是一个字典,for循环用来循环输出键值对。

    11.4 编辑HelloWorld/server.py

    内容如下:

    from flask import Flask, render_template
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    
    @app.route('/user')
    def user():
        user_info = {
            'name': 'letian',
            'email': '123@aa.com',
            'age':0,
            'github': 'https://github.com/letiantian'
        }
        return render_template('user_info.html', page_title='letian\'s info', user_info=user_info)
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    render_template()函数的第一个参数指定模板文件,后面的参数是要传递的数据。

    11.5 运行与测试

    运行HelloWorld/server.py:

    $ python3 HelloWorld/server.py
    

    在浏览器中访问http://127.0.0.1:5000/user,效果图如下:

    查看网页源码:

    <html>
    <head>
        <title>
                letian&#39;s info
        </title>
    </head>
    <body>
            name: letian <br/>
            email: 123@aa.com <br/>
            age: 0 <br/>
            github: https://github.com/letiantian <br/>
    </body>
    </html>
    

    11.6 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-009

    12. 自定义404等错误的响应

    要处理HTTP错误,可以使用flask.abort函数。

    12.1 示例1:简单入门

    建立Flask项目

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    代码

    编辑HelloWorld/server.py

    from flask import Flask, render_template_string, abort
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    
    @app.route('/user')
    def user():
        abort(401)  # Unauthorized 未授权
        print('Unauthorized, 请先登录')
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    效果

    运行HelloWorld/server.py,浏览器访问http://127.0.0.1:5000/user,效果如下:

    要注意的是,HelloWorld/server.pyabort(401)后的print并没有执行。

    12.2 示例2:自定义错误页面

    代码

    将服务器代码改为:

    from flask import Flask, render_template_string, abort
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    
    @app.route('/user')
    def user():
        abort(401)  # Unauthorized
    
    
    @app.errorhandler(401)
    def page_unauthorized(error):
        return render_template_string('<h1> Unauthorized </h1><h2>{{ error_info }}</h2>', error_info=error), 401
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    page_unauthorized函数返回的是一个元组,401 代表HTTP 响应状态码。如果省略401,则响应状态码会变成默认的 200。

    效果

    运行HelloWorld/server.py,浏览器访问http://127.0.0.1:5000/user,效果如下:

    12.3 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-010

    13. 用户会话

    session用来记录用户的登录状态,一般基于cookie实现。

    下面是一个简单的示例。

    13.1 建立Flask项目

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    13.2 编辑HelloWorld/server.py

    内容如下:

    from flask import Flask, render_template_string, \
        session, request, redirect, url_for
    
    app = Flask(__name__)
    
    app.secret_key = 'F12Zr47j\3yX R~X@H!jLwf/T'
    
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    
    @app.route('/login')
    def login():
        page = '''
        <form action="{{ url_for('do_login') }}" method="post">
            <p>name: <input type="text" name="user_name" /></p>
            <input type="submit" value="Submit" />
        </form>
        '''
        return render_template_string(page)
    
    
    @app.route('/do_login', methods=['POST'])
    def do_login():
        name = request.form.get('user_name')
        session['user_name'] = name
        return 'success'
    
    
    @app.route('/show')
    def show():
        return session['user_name']
    
    
    @app.route('/logout')
    def logout():
        session.pop('user_name', None)
        return redirect(url_for('login'))
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    13.3 代码的含义

    app.secret_key用于给session加密。

    /login中将向用户展示一个表单,要求输入一个名字,submit后将数据以post的方式传递给/do_login/do_login将名字存放在session中。

    如果用户成功登录,访问/show时会显示用户的名字。此时,打开firebug等调试工具,选择session面板,会看到有一个cookie的名称为session

    /logout用于登出,通过将session中的user_name字段pop即可。Flask中的session基于字典类型实现,调用pop方法时会返回pop的键对应的值;如果要pop的键并不存在,那么返回值是pop()的第二个参数。

    另外,使用redirect()重定向时,一定要在前面加上return

    13.4 效果

    进入http://127.0.0.1:5000/login,输入name,点击submit:

    进入http://127.0.0.1:5000/show查看session中存储的name:

    13.5 设置sessin的有效时间

    下面这段代码来自Is there an easy way to make sessions timeout in flask?

    from datetime import timedelta
    from flask import session, app
    
    session.permanent = True
    app.permanent_session_lifetime = timedelta(minutes=5)
    

    这段代码将session的有效时间设置为5分钟。

    13.6 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-011

    14. 使用Cookie

    Cookie是存储在客户端的记录访问者状态的数据。具体原理,请见 http://zh.wikipedia.org/wiki/Cookie 。 常用的用于记录用户登录状态的session大多是基于cookie实现的。

    cookie可以借助flask.Response来实现。下面是一个示例。

    14.1 建立Flask项目

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    14.2 代码

    修改HelloWorld/server.py

    from flask import Flask, request, Response, make_response
    import time
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_world():
        return 'hello world'
    
    
    @app.route('/add')
    def login():
        res = Response('add cookies')
        res.set_cookie(key='name', value='letian', expires=time.time()+6*60)
        return res
    
    
    @app.route('/show')
    def show():
        return request.cookies.__str__()
    
    
    @app.route('/del')
    def del_cookie():
        res = Response('delete cookies')
        res.set_cookie('name', '', expires=0)
        return res
    
    
    if __name__ == '__main__':
        app.run(port=5000, debug=True)
    

    由上可以看到,可以使用Response.set_cookie添加和删除cookie。expires参数用来设置cookie有效时间,它的值可以是datetime对象或者unix时间戳,笔者使用的是unix时间戳。

    res.set_cookie(key='name', value='letian', expires=time.time()+6*60)
    

    上面的expire参数的值表示cookie在从现在开始的6分钟内都是有效的。

    要删除cookie,将expire参数的值设为0即可:

    res.set_cookie('name', '', expires=0)
    

    set_cookie()函数的原型如下:

    set_cookie(key, value=’’, max_age=None, expires=None, path=’/‘, domain=None, secure=None, httponly=False)

    Sets a cookie. The parameters are the same as in the cookie Morsel object in the Python standard library but it accepts unicode data, too.
    Parameters:

         key – the key (name) of the cookie to be set.
         value – the value of the cookie.
         max_age – should be a number of seconds, or None (default) if the cookie should last only as long as the client’s browser session.

         expires – should be a datetime object or UNIX timestamp.

         domain – if you want to set a cross-domain cookie. For example, domain=”.example.com” will set a cookie that is readable by the domain www.example.com, foo.example.com etc. Otherwise, a cookie will only be readable by the domain that set it.

         path – limits the cookie to a given path, per default it will span the whole domain.

    14.3 运行与测试

    运行HelloWorld/server.py

    $ python3 HelloWorld/server.py
    

    使用浏览器打开http://127.0.0.1:5000/add,浏览器界面会显示

    add cookies
    

    下面查看一下cookie,如果使用firefox浏览器,可以用firebug插件查看。打开firebug,选择Cookies选项,刷新页面,可以看到名为name的cookie,其值为letian

    在“网络”选项中,可以查看响应头中类似下面内容的设置cookie的HTTP「指令」:

    Set-Cookie: name=letian; Expires=Sun, 29-Jun-2014 05:16:27 GMT; Path=/
    

    在cookie有效期间,使用浏览器访问http://127.0.0.1:5000/show,可以看到:

    {'name': 'letian'}
    

    14.4 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-012

    15. 闪存系统 flashing system

    Flask的闪存系统(flashing system)用于向用户提供反馈信息,这些反馈信息一般是对用户上一次操作的反馈。反馈信息是存储在服务器端的,当服务器向客户端返回反馈信息后,这些反馈信息会被服务器端删除。

    下面是一个示例。

    15.1 建立Flask项目

    按照以下命令建立Flask项目HelloWorld:

    mkdir HelloWorld
    mkdir HelloWorld/static
    mkdir HelloWorld/templates
    touch HelloWorld/server.py
    

    15.2 编写HelloWorld/server.py

    内容如下:

    from flask import Flask, flash, get_flashed_messages
    import time
    
    app = Flask(__name__)
    app.secret_key = 'some_secret'
    
    
    @app.route('/')
    def index():
        return 'hi'
    
    
    @app.route('/gen')
    def gen():
        info = 'access at '+ time.time().__str__()
        flash(info)
        return info
    
    
    @app.route('/show1')
    def show1():
        return get_flashed_messages().__str__()
    
    
    @app.route('/show2')
    def show2():
        return get_flashed_messages().__str__()
    
    
    if __name__ == "__main__":
        app.run(port=5000, debug=True)
    

    15.3 效果

    运行服务器:

    $ python3 HelloWorld/server.py
    

    打开浏览器,访问http://127.0.0.1:5000/gen,浏览器界面显示(注意,时间戳是动态生成的,每次都会不一样,除非并行访问):

    access at 1404020982.83
    

    查看浏览器的cookie,可以看到session,其对应的内容是:

    .eJyrVopPy0kszkgtVrKKrlZSKIFQSUpWSknhYVXJRm55UYG2tkq1OlDRyHC_rKgIvypPdzcDTxdXA1-XwHLfLEdTfxfPUn8XX6DKWCAEAJKBGq8.BpE6dg.F1VURZa7VqU9bvbC4XIBO9-3Y4Y
    

    再一次访问http://127.0.0.1:5000/gen,浏览器界面显示:

    access at 1404021130.32
    

    cookie中session发生了变化,新的内容是:

    .eJyrVopPy0kszkgtVrKKrlZSKIFQSUpWSknhYVXJRm55UYG2tkq1OlDRyHC_rKgIvypPdzcDTxdXA1-XwHLfLEdTfxfPUn8XX6DKWLBaMg1yrfCtciz1rfIEGxRbCwAhGjC5.BpE7Cg.Cb_B_k2otqczhknGnpNjQ5u4dqw
    

    然后使用浏览器访问http://127.0.0.1:5000/show1,浏览器界面显示:

    ['access at 1404020982.83', 'access at 1404021130.32']
    

    这个列表中的内容也就是上面的两次访问http://127.0.0.1:5000/gen得到的内容。此时,cookie中已经没有session了。

    如果使用浏览器访问http://127.0.0.1:5000/show1或者http://127.0.0.1:5000/show2,只会得到:

    []
    

    15.4 高级用法

    flash系统也支持对flash的内容进行分类。修改HelloWorld/server.py内容:

    from flask import Flask, flash, get_flashed_messages
    import time
    
    app = Flask(__name__)
    app.secret_key = 'some_secret'
    
    
    @app.route('/')
    def index():
        return 'hi'
    
    
    @app.route('/gen')
    def gen():
        info = 'access at '+ time.time().__str__()
        flash('show1 '+info, category='show1')
        flash('show2 '+info, category='show2')
        return info
    
    
    @app.route('/show1')
    def show1():
        return get_flashed_messages(category_filter='show1').__str__()
    
    @app.route('/show2')
    def show2():
        return get_flashed_messages(category_filter='show2').__str__()
    
    
    if __name__ == "__main__":
        app.run(port=5000, debug=True)
    

    某一时刻,浏览器访问http://127.0.0.1:5000/gen,浏览器界面显示:

    access at 1404022326.39
    

    不过,由上面的代码可以知道,此时生成了两个flash信息,但分类(category)不同。

    使用浏览器访问http://127.0.0.1:5000/show1,得到如下内容:

    ['1 access at 1404022326.39']
    

    而继续访问http://127.0.0.1:5000/show2,得到的内容为空:

    []
    

    15.5 在模板文件中获取flash的内容

    在Flask中,get_flashed_messages()默认已经集成到Jinja2模板引擎中,易用性很强。下面是来自官方的一个示例:

    15.6 本节源码

    https://github.com/letiantian/Learn-Flask/tree/master/flask-demo-013

     

    • 本文作者: letiantian
    • 更多Python视频、源码、资料加群683380553免费获取
    • 本文链接: http://www.letiantian.me/learn-flask/
    • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处,并以可跳转的形式保留/添加原文链接!
    展开全文
  • Python实现简单的Web服务器

    千次阅读 2019-03-29 00:15:28
    Python实现简单的Web服务器项目来源知识储备:HTTP的了解开始项目hello,web——我的第一个web服务器 项目来源 本课程核心部分来自500 lines or less项目,作者是 Mozilla 的 Greg Wilson。项目代码使用 MIT 协议,...

    1 项目来源

    本课程核心部分来自500 lines or less项目,作者是 Mozilla 的 Greg Wilson。项目代码使用 MIT 协议,项目文档使用 http://creativecommons.org/licenses/by/3.0/legalcode 协议。

    2.知识储备:HTTP的了解

    暂不叙述。

    3.开始项目

    3.1 hello,web——我的第一个web服务器

    3.1.1 效果图

    在这里插入图片描述
    通过抓包,在这里插入图片描述

    3.1.2 代码

    from http.server import BaseHTTPRequestHandler, HTTPServer
    
    class RequestHandler(BaseHTTPRequestHandler):
        '''处理请求并返回页面'''
    
        # 页面模板
        Page = '''\
            <html>
            <body>
            <p>Hello, web!</p>
            </body>
            </html>
        '''
    
        # 处理一个GET请求
        def do_GET(self):
            self.send_response(200)
            self.send_header("Content-Type", "text/html")
            self.send_header("Content-Length", str(len(self.Page)))
            self.end_headers()
            self.wfile.write(self.Page.encode('utf-8'))
    
    if __name__ == '__main__':
        serverAddress = ('', 8080)
        server = HTTPServer(serverAddress, RequestHandler)
        server.serve_forever()
    
    

    关闭服务器怎么做呢?

    将运行的程序关闭,即可以将我们的web服务器关闭。
    假设一种情况,我们不确定我们使用的是哪个程序启动的服务器怎么办?
    可以使用win10的powershell控制台来关闭。
    在这里插入图片描述
    然后我们发现:
    在这里插入图片描述
    于是我们能够关闭我们的python文件。

    模块的 BaseHTTPRequestHandler 类会帮我们处理对请求的解析,并通过确定请求的方法来调用其对应的函数,比如方法是 GET ,该类就会调用名为 do_GET 的方法。RequestHandler 继承了 BaseHTTPRequestHandler 并重写了 do_GET 方法,其效果如代码所示是返回 Page 的内容。 Content-Type 告诉了客户端要以处理html文件的方式处理返回的内容。end_headers 方法会插入一个空白行,如之前的request结构图所示。

    重构代码

    from http.server import BaseHTTPRequestHandler, HTTPServer
    
    class RequestHandler(BaseHTTPRequestHandler):
        # ...页面模板...
    	Page = '''\
    	<html>
    	<body>
    	<table>
    	<tr>  <td>Header</td>         <td>Value</td>          </tr>
    	<tr>  <td>Date and time</td>  <td>{date_time}</td>    </tr>
    	<tr>  <td>Client host</td>    <td>{client_host}</td>  </tr>
    	<tr>  <td>Client port</td>    <td>{client_port}</td> </tr>
    	<tr>  <td>Command</td>        <td>{command}</td>      </tr>
    	<tr>  <td>Path</td>           <td>{path}</td>         </tr>
    	</table>
    	</body>
    	</html>
    	'''
    
    	def do_GET(self):
    		page = self.create_page()
    		self.send_content(page)
    
    	def create_page(self):
    	    values = {
    	        'date_time'   : self.date_time_string(),
    	        'client_host' : self.client_address[0],
    	        'client_port' : self.client_address[1],
    	        'command'     : self.command,
    	        'path'        : self.path
    	    }
    	    page = self.Page.format(**values)
    	    return page
    
    	def send_content(self, page):
    	    self.send_response(200)
    	    self.send_header("Content-type", "text/html")
    	    self.send_header("Content-Length", str(len(page)))
    	    self.end_headers()
    	    self.wfile.write(page.encode('utf-8'))
    	    
    if __name__ == '__main__':
        serverAddress = ('', 8080)
        server = HTTPServer(serverAddress, RequestHandler)
        server.serve_forever()
    

    在这里插入图片描述
    客户端端口号随机。

    实现静态网页访问

    import sys, os
    from http.server import BaseHTTPRequestHandler,HTTPServer
    
    # 一个服务器异常,当发生异常抛出这个。
    class ServerException(Exception):
        '''服务器内部错误'''
        pass
    
    class RequestHandler(BaseHTTPRequestHandler):
    
        Error_Page = """\
        <html>
        <body>
        <h1>Error accessing {path}</h1>
        <p>{msg}</p>
        </body>
        </html>
        """
    
        def do_GET(self):
            try:
                # 文件完整路径
                # print(os.getcwd() + self.path)
                #如C:\Users\Administrator\Desktop\我的学习资料\python\web_server /plain.html
                full_path = os.getcwd() + self.path
                # 如果该路径不存在...
                if not os.path.exists(full_path):
                    #抛出异常:文件未找到
                    raise ServerException("'{0}' not found".format(self.path))
                # 如果该路径是一个文件
                elif os.path.isfile(full_path):
                    #调用 handle_file 处理该文件
                    self.handle_file(full_path)
                # 如果该路径不是一个文件
                else:
                    #抛出异常:该路径为不知名对象
                    raise ServerException("Unknown object '{0}'".format(self.path))
            # 处理异常
            except Exception as msg:
                self.handle_error(msg)
    
        def handle_error(self, msg):
            content = self.Error_Page.format(path=self.path, msg=msg)
            self.send_content(content.encode("utf-8"),404)
    
    
        def create_page(self):
            values = {
                'date_time'   : self.date_time_string(),
                'client_host' : self.client_address[0],
                'client_port' : self.client_address[1],
                'command'     : self.command,
                'path'        : self.path
            }
            page = self.Page.format(**values)
            return page
    	
        def send_content(self,content,status=200):
            self.send_response(status)
            self.send_header("Content-type","text/html")
            self.send_header("Content-Length",str(len(content)))
            self.end_headers()
            self.wfile.write(content)
    	# 文件操纵:发送内容
        def handle_file(self,full_path):
            try:
                with open(full_path, 'rb') as reader:
                    content = reader.read()
                self.send_content(content)
            except IOError as msg:
                msg = "'{0}' cannot be read: {1}".format(self.path, msg)
                self.handle_error(msg)
    
    if __name__ == '__main__':
        serverAddress = ('', 8080)
        server = HTTPServer(serverAddress, RequestHandler)
        server.serve_forever()
    
    

    此时,访问了错误的路径:
    在这里插入图片描述
    正确的页面:
    在这里插入图片描述

    访问网址直接链接到首页

    import sys, os
    from http.server import BaseHTTPRequestHandler,HTTPServer
    
    class ServerException(Exception):
        '''服务器内部错误'''
        pass
    
    class case_no_file(object):
        '''该路径不存在'''
    
        def test(self, handler):
            return not os.path.exists(handler.full_path)
    
        def act(self, handler):
            raise ServerException("'{0}' not found".format(handler.path))
    
    
    class case_existing_file(object):
        '''该路径是文件'''
    
        def test(self, handler):
            return os.path.isfile(handler.full_path)
    
        def act(self, handler):
            handler.handle_file(handler.full_path)
    
    
    class case_always_fail(object):
        '''所有情况都不符合时的默认处理类'''
    
        def test(self, handler):
            return True
    
        def act(self, handler):
            raise ServerException("Unknown object '{0}'".format(handler.path))
    
    
    class case_directory_index_file(object):
    
        def index_path(self, handler):
            return os.path.join(handler.full_path, 'index.html')
    
        #判断目标路径是否是目录&&目录下是否有index.html
        def test(self, handler):
            return os.path.isdir(handler.full_path) and \
                   os.path.isfile(self.index_path(handler))
    
        #响应index.html的内容
        def act(self, handler):
            handler.handle_file(self.index_path(handler))
    
    
    class RequestHandler(BaseHTTPRequestHandler):
        '''
        请求路径合法则返回相应处理
        否则返回错误页面
        '''
    
        Cases = [case_no_file(),
                 case_existing_file(),
                 case_directory_index_file(),
                 case_always_fail()]
    
        # 错误页面模板
        Error_Page = """\
            <html>
            <body>
            <h1>Error accessing {path}</h1>
            <p>{msg}</p>
            </body>
            </html>
            """
    
        def do_GET(self):
            try:
    
                # 得到完整的请求路径
                self.full_path = os.getcwd() + self.path
    
                # 遍历所有的情况并处理
                for case in self.Cases:
                    if case.test(self):
                        case.act(self)
                        break
    
            # 处理异常
            except Exception as msg:
                self.handle_error(msg)
    
        def handle_error(self, msg):
            content = self.Error_Page.format(path=self.path, msg=msg)
            self.send_content(content.encode("utf-8"), 404)
    
        # 发送数据到客户端
        def send_content(self, content, status=200):
            self.send_response(status)
            self.send_header("Content-type", "text/html")
            self.send_header("Content-Length", str(len(content)))
            self.end_headers()
            self.wfile.write(content)
    
        def handle_file(self, full_path):
            try:
                with open(full_path, 'rb') as reader:
                    content = reader.read()
                self.send_content(content)
            except IOError as msg:
                msg = "'{0}' cannot be read: {1}".format(self.path, msg)
                self.handle_error(msg)
    
    
    
    if __name__ == '__main__':
        serverAddress = ('', 8080)
        server = HTTPServer(serverAddress, RequestHandler)
        server.serve_forever()
    

    使用CGI协议/并且对源代码进行重写。

    #-*- coding:utf-8 -*-
    import sys, os, subprocess
    from http.server import BaseHTTPRequestHandler,HTTPServer
    #-------------------------------------------------------------------------------
    
    class ServerException(Exception):
        '''服务器内部错误'''
        pass
    
    #-------------------------------------------------------------------------------
    
    class base_case(object):
        '''条件处理基类'''
    
        def handle_file(self, handler, full_path):
            try:
                with open(full_path, 'rb') as reader:
                    content = reader.read()
                handler.send_content(content)
            except IOError as msg:
                msg = "'{0}' cannot be read: {1}".format(full_path, msg)
                handler.handle_error(msg)
    
        def index_path(self, handler):
            return os.path.join(handler.full_path, 'index.html')
    
        def test(self, handler):
            assert False, 'Not implemented.'
    
        def act(self, handler):
            assert False, 'Not implemented.'
    
    #-------------------------------------------------------------------------------
    
    class case_no_file(base_case):
        '''文件或目录不存在'''
    
        def test(self, handler):
            return not os.path.exists(handler.full_path)
    
        def act(self, handler):
            raise ServerException("'{0}' not found".format(handler.path))
    
    #-------------------------------------------------------------------------------
    
    class case_cgi_file(base_case):
        '''可执行脚本'''
    
        def run_cgi(self, handler):
            data = subprocess.check_output(["python3", handler.full_path],shell=False)
            handler.send_content(data)
    
        def test(self, handler):
            return os.path.isfile(handler.full_path) and \
                   handler.full_path.endswith('.py')
    
        def act(self, handler):
            self.run_cgi(handler)
    
    #-------------------------------------------------------------------------------
    
    class case_existing_file(base_case):
        '''文件存在的情况'''
    
        def test(self, handler):
            return os.path.isfile(handler.full_path)
    
        def act(self, handler):
            self.handle_file(handler, handler.full_path)
    
    #-------------------------------------------------------------------------------
    
    class case_directory_index_file(base_case):
        '''在根路径下返回主页文件'''
    
        def test(self, handler):
            return os.path.isdir(handler.full_path) and \
                   os.path.isfile(self.index_path(handler))
    
        def act(self, handler):
            self.handle_file(handler, self.index_path(handler))
    
    #-------------------------------------------------------------------------------
    
    class case_always_fail(base_case):
        '''默认处理'''
    
        def test(self, handler):
            return True
    
        def act(self, handler):
            raise ServerException("Unknown object '{0}'".format(handler.path))
    
    #-------------------------------------------------------------------------------
    
    class RequestHandler(BaseHTTPRequestHandler):
        '''
        请求路径合法则返回相应处理
        否则返回错误页面
        '''
    
        Cases = [case_no_file(),
                 case_cgi_file(),
                 case_existing_file(),
                 case_directory_index_file(),
                 case_always_fail()]
    
        # 错误页面模板
        Error_Page = """\
            <html>
            <body>
            <h1>Error accessing {path}</h1>
            <p>{msg}</p>
            </body>
            </html>
            """
    
        def do_GET(self):
            try:
    
                # 得到完整的请求路径
                self.full_path = os.getcwd() + self.path
    
                # 遍历所有的情况并处理
                for case in self.Cases:
                    if case.test(self):
                        case.act(self)
                        break
    
            # 处理异常
            except Exception as msg:
                self.handle_error(msg)
    
        def handle_error(self, msg):
            content = self.Error_Page.format(path=self.path, msg=msg)
            self.send_content(content.encode("utf-8"), 404)
    
        # 发送数据到客户端
        def send_content(self, content, status=200):
            self.send_response(status)
            self.send_header("Content-type", "text/html")
            self.send_header("Content-Length", str(len(content)))
            self.end_headers()
            self.wfile.write(content)
    
    #-------------------------------------------------------------------------------
    
    if __name__ == '__main__':
        serverAddress = ('', 8080)
        server = HTTPServer(serverAddress, RequestHandler)
        server.serve_forever()
    
    展开全文
  • python webapi

    千次阅读 2019-06-21 15:09:15
    目的:将python代码写的功能模块封装成webapi 我首先用vs2017搭建python flask web项目 在runserver.py文件中 init.py """ The flask application package. """ from flask import Flask app = Flask(__name__) ...

    目的:将python代码写的功能模块封装成webapi
    我首先用vs2017搭建python flask web项目

    在runserver.py文件中
    目录结构
    init.py

    """
    The flask application package.
    """
    
    from flask import Flask
    app = Flask(__name__)
    
    import 自己的模块
    

    runserver.py

    
    
    from os import environ
    from CAD import app
    
    if __name__ == '__main__':
        #HOST = environ.get('SERVER_HOST', 'localhost')
        #try:
           # PORT = int(environ.get('SERVER_PORT', '5555'))
        #except ValueError:
            #PORT = 5555
        #app.run(HOST, PORT)
    	app.run(host='127.0.0.1', port=8080, debug=True, threaded=True) #我这里用的是本地的,可以根据需要自己改
    

    自己的py文件

    """
    Routes and views for the flask application.
    """
    
    from datetime import datetime
    from flask import render_template
    from FlaskWebProject1 import app
    
    
    @app.route('/文件名/方法名',,methods=['GET', 'POST'])
    def 自己的方法():
        """Renders the home page."""
        return render_template(
            'index.html',
            title='Home Page',
            year=datetime.now().year,
        )
    
    
    展开全文
  • python开发本地WEB项目

    千次阅读 2018-10-22 10:26:53
    0. 基础 python版本 python-3.6.4 编辑器 pycharm-2018.2.4 ...虚拟环境是系统的一个位置,在开发web项目时,需要安装的所有python库都必须安装在该环境中。 创建( 通过CMD终端窗口实现 ) 1) ...
  • Python学生成绩管理系统----极简版

    万次阅读 多人点赞 2020-05-27 14:25:28
    Python学生成绩管理系统 全部代码:点击打开链接 说明: 这是一个极其简易的管理系统,这是本人本科阶段的课堂作业,并无任何商业或者实用价值(因上次有人留言说我写的太烂了,特此说明!) 此管理系统实现...
  • 一:创建一个Web Project 1. 打开 Open Visual Studio 2017 软件
  • python 搭建web服务器

    千次阅读 2018-04-30 19:12:19
    使用 httpie 在命令行进行测试1、最基本的:# _*_coding :utf-8 _*_ import httpie from http.server import BaseHTTPRequestHandler,HTTPServer class RequestHandler(BaseHTTPRequestHandler): '''处理请求并...
  • python搭建web全栈

    千次阅读 2017-09-13 11:08:18
    一个Python服务器和一个React前端
  • 在Linux环境下运行 这是错误: Traceback (most recent call last): File "brute.py", line 15, in ... page=the_page else: if page!=the_page: print passw break ```
  • 使用python+oracle 11g开发web应用

    千次阅读 2016-07-22 14:44:31
    Developing a Python Web Application with Oracle Database 11g Purpose This tutorial shows you how to use Python with Oracle Database 11g. Time to Complete Approximately 1 hour Overview Pyth
  • 一、实验介绍 扫描器需要实现功能的思维...多线程的使用 网站爬虫的基本知识 SQL注入的基本原理 SQL检测工具编写,多参数URL的sql注入检测 正则表达式的基本知识 1.3 实验环境 Python 2.7 Win10 PyCha...
  • 使用 python 开发 Web Service

    千次阅读 2008-04-21 23:50:00
    级别: 中级刘 明 (ovis_poly@sina.com), 软件工程师, 上海交通大学电子与通信工程系陈 华泉 (chenhuaquan@21cn.com), 软件工程师, 上海交通大学软件工程学院2008 年 2 月 28 日Python 是一种...使用 python 开发 we
  • 由于目前的Web开发中AJAX、Javascript、CSS的大量使用,一些网站上的重要数据是由Ajax或Javascript动态生成的,并不能直接通过解析html页面内容就能获得(例如采用mechanize、lxml、Beautiful Soup )。要实现对...
  • 小甲鱼零基础入门学习python笔记

    万次阅读 多人点赞 2020-10-05 19:38:17
    小甲鱼老师零基础入门学习Python全套资料百度云(包括小甲鱼零基础入门学习Python全套视频+全套源码+全套PPT课件+全套课后题及Python常用工具包链接、电子书籍等)请往我的资源... 000 愉快的开始 ...
  • Python小项目四:实现简单的web服务器

    万次阅读 多人点赞 2017-07-01 21:09:11
    不同之处在于实验楼使用python2.7,而博主这里使用的是python3.6。在学习中也因为python版本不同遇到了一些坑,这里写成博客一作记录,二来可以帮助像博主这样的入门者少踩一些坑。 要想实现web服务器,首先要明白...
  • Python 3 web开发

    千次阅读 2019-08-07 14:09:38
    文章目录web开发发展历程HTTP协议...Python有上百种web开发框架,有很多成熟的模块技术,用Python进行web开发,开发效率高,运行速度快。 HTTP协议简介 在web应用中,服务器将网页传给服务器,实质上就是将网页的H...
  • Python编写WEB服务器压力测试工具

    万次阅读 2006-03-06 22:13:00
    前言最近在编写一个简单的WEB服务器,一个日常的工作就是测试服务器的性能,试用了MS的Web Application Stress,发现它居然不支持除80以外端口的测试,其他的如Loadrunner 太贵而且太大,试用版只支持10个并发用户,...
  • windows下python常用库的安装

    万次阅读 多人点赞 2019-07-05 10:30:08
    windows下python常用库的安装,前提安装了annaconda 的python开发环境。只要已经安装了anaconda,要安装别的库就很简单了。只要使用pip即可,正常安装好python,都会自带pip安装 工具,在python的scripts安装目录下...
  • python基础:web =html+ python

    千次阅读 2020-09-28 11:30:22
    一般的web应用是js + java(serverlet/controller),python也可以充当服务器后台,代码如下: 过程如下: form表单—&amp;amp;amp;gt;经过服务器解析的【目标文件】 -----&amp;amp;amp;gt;处理提交的数据:...
1 2 3 4 5 ... 20
收藏数 60,625
精华内容 24,250
关键字:

page 使用python做web