一、前言                           

  前面讲了环境搭建和常用的元素定位,后续会持续以项目实践的方式去慢慢学习以及整理各方面的知识点,具体不会详细阐述,但会贴上完整代码,想要了解更多的可以直接网上查找资料哈,接下来用企业微信的应用(订单平台)做实践,环境配置:win10+Python 3.7.4+appium 1.16.0+unittest框架+真机andorid 8.0

注:关于移动端的,暂时就只做一个项目,因为移动端的扩展性没这么多,后续应该会以web端项目来实操

二、关于Appium实现中文输入

  1、要实现中文输入的话,在初始化里加入下面的代码就行了

# 实现中文输入,使用unicodeKeyboard的编码方式来发送字符串
'unicodeKeyboard': True,
# 将键盘给隐藏起来
'resetKeyboard': True

  2、如果Appium设置中文输入报错: Attempt to re-install io.appium.android.ime without first

    原因:漏卸载应用

    解决方法:查出所有的第三方安装包:一共3个,然后用adb卸载掉(adb shell pm list package -3或adb shell pm list package -3 | findstr appium),如图1

(图1:卸载应用)

  3、Appium 在 Android7.0 以上版本找不到元素的问题,解决方法:安装Uiautomator2(使用npm安装: npm install appium-uiautomator2-driver)

三、关于隐式等待和显示等待

  1、WebDriverWait():显示等待,是针对于某个特定的元素设置的等待时间,在设置时间内,默认每隔一段时间检测一次当前页面某个元素是否存在,如果在规定的时间内找到了元素,则直接执行,即找到元素就执行相关操作,如果超过设置时间检测不到则抛出异常。默认检测频率为0.5s,默认抛出异常为:NoSuchElementException

  WebDriverWait()一般由unitl()或until_not()方法配合使用,until()调用该方法提供的驱动作为一个参数,直到返回值为True,unitl_not()调用该方法提供的驱动作为一个参数,直到返回值为False 。

  用法示例:

 from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By loc = ("xpath", "//android.view.View[contains(@text,'确定')]")
try:
# 显示等待用法一:EC.presence_of_element_located()直到元素出现
e = WebDriverWait(self.driver, 3, 0.5).until(EC.presence_of_element_located(loc))
# 显示等待用法二:用By
#WebDriverWait(self.driver, 3, 0.5).until(EC.presence_of_element_located(By.XPATH, "//android.view.View[contains(@text,'确定')]"))
# 显示等待用法三:用lambda函数
#e = WebDriverWait(self.driver, 3 ,0.5).until(lambda x: self.driver.find_element_by_xpath("//android.view.View[contains(@text,'确定')]"))
e.click()
print("成功选择非免付啦")
except:
pass

  2、implicitly_wait():隐式等待,是设置的全局等待。设置等待时间,是对页面中的所有元素设置加载时间,如果超出了设置时间的则抛出异常。隐式等待可以理解成在规定的时间范围内,浏览器在不停的刷新页面,直到找到相关元素或者时间结束。

  3、隐式等待和显示等待都存在时,超时时间取二者中较大的。

四、关于unittest框架

  1、简要说明

  unittest是Python中自带的单元测试框架,它里面封装好了一些校验返回的结果方法和一些用例执行前的初始化操作。unittest单元测试框架不仅可以适用于单元测试,还可以适用web自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否通过,最终生成测试结果。

最基础的四个概念:TestCase,TestSuite,TestRunner,TestFixture

  2、运行流程

  先编写好TestCase,然后由TestLoader加载TestCase到TestSuite,其次由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例

  3、unittest模块的各个属性说明

  1)unittest.TestCase:TestCase类,所有测试用例类继承的基本类。class BaiduTest(unittest.TestCase):

  2)unittest.main():使用它可以方便的将一个单元测试模块变为可直接运行的测试脚本,main()方法使用TestLoader类来搜索所有包含在该模块中以“test”命名开头的测试方法,并自动执行他们。执行方法的默认顺序是:根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。所以以A开头的测试用例方法会优先执行,以a开头会后执行。

  3)unittest.TestSuite():unittest框架的TestSuite()类是用来创建测试套件的。

  4)unittest.TextTextRunner():unittest框架的TextTextRunner()类,通过该类下面的run()方法来运行suite所组装的测试用例,入参为suite测试套件。

  5)unittest.defaultTestLoader(): defaultTestLoader()类,通过该类下面的discover()方法可自动更具测试目录start_dir匹配查找测试用例文件(test*.py),并将查找到的测试用例组装到测试套件,因此可以直接通过run()方法执行discover。

  6)unittest.skip():装饰器,当运行用例时,有些用例可能不想执行等,可用装饰器暂时屏蔽该条测试用例。一种常见的用法就是比如说想调试某一个测试用例,想先屏蔽其他用例就可以用装饰器屏蔽。

    @unittest.skip(reason): skip(reason)装饰器:无条件跳过装饰的测试,并说明跳过测试的原因。

    @unittest.skipIf(reason):skipIf(condition,reason)装饰器:条件为真时,跳过装饰的测试,并说明跳过测试的原因。

    @unittest.skipUnless(reason):skipUnless(condition,reason)装饰器:条件为假时,跳过装饰的测试,并说明跳过测试的原因。

    @unittest.expectedFailure():expectedFailure()测试标记为失败。

  7)setUp():setUp()方法用于每个测试用例执行前的初始化工作。如测试用例中需要访问数据库,可以在setUp中建立数据库连接并进行初始化。如测试用例需要登录web,可以先实例化浏览器。

  8)tearDown():tearDown()方法用于每个测试用例执行之后的善后工作。如关闭数据库连接、关闭浏览器。

  9)setUpClass():setUpClass()方法用于所有测试用例前的设置工作。

  10)tearDownClass():tearDownClass()方法用于所有测试用例执行后的清理工作。

  11)addTest():addTest()方法是将测试用例添加到测试套件中。

  12)run():run()方法是运行测试套件的测试用例,入参为suite测试套件。

  13)assert*():在执行测试用例的过程中,最终用例是否执行通过,是通过判断测试得到的实际结果和预期结果是否相等决定的。

  4、添加用例运行方式

  1)用法一:用addTests方法单个添加用例

import unittest

if __name__ == '__main__':
suite = unittest.TestSuite()
# 单个添加测试用例
suite.addTest(TestMathFunc("test_multi"))
suite.addTest(TestMathFunc("test_divide"))
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)

  2)用法二:将用例添加到一个用例集中,再通过suite统一运行

import unittest

if __name__ == '__main__':
suite = unittest.TestSuite()
# 将测试用例添加到一个用例集中
tests = [TestMathFunc("test_add"), TestMathFunc("test_minus")]
suite.addTests(tests) # 将测试用例列表添加到测试组中
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)

  3)用法三:这是最实用的方法,引用discover()方法,匹配指定文件夹下以test开头的测试用例

import unittest

if __name__ == '__main__':
path = './testcase'
all_cases = unittest.defaultTestLoader.discover(path, 'test*.py')
# 找到某个目录下所有的以test开头的Python文件里面的测试用例
runner = unittest.TextTestRunner(verbosity=2)
runner.run(all_cases)

五、BeautifulReport测试报告

  1、如何使用?

  1)pip安装:pip install BeautifulReport

  2)使用示例:

import unittest
from BeautifulReport import BeautifulReport if __name__ == '__main__':
#"."表示当前目录,"*tests.py"匹配当前目录下所有tests.py结尾的用例
test_suite = unittest.defaultTestLoader.discover('./tests', pattern='test*.py')
   result = BeautifulReport(test_suite)
   result.report(filename='测试报告', description='测试deafult报告', report_dir='report', theme='theme_default')

  2、简要说明:

  1)BeautifulReport.report

    report (
        filename -> 测试报告名称, 如果不指定默认文件名为report.html
        description -> 测试报告用例名称展示
        report_dir='.' -> 报告文件写入路径
        theme='theme_default' -> 报告主题样式 theme_default theme_cyan theme_candy theme_memories
        )

  2)BeautifulReport.add_test_img:如果使用报告过程中需要把测试报告的截图放在报告中, 可以使用add_test_img方法

  3)add_test_img ( *pargs ):可以在测试用例上挂载一个装饰器, 实例内容如下:

    默认存放的图片路径是img, 需要在当前测试项目的启动路径下, 创建一个img文件夹

    传递给装饰器的图片,在运行测试前可以不存在, 运行测试之后生成即可.

    当文件在报告中展示后, 想要看到原图, 可以点击报告中的缩略图查看完整的截图

六、完整项目代码示例

  1、项目目录结构,如图2

(图2:项目目录结构示例)

  2、测试用例text_wxwork.py

注:可能会涉及到敏感信息,所以有些case的注释和text会用XXX代替

 1 from appium import webdriver  
 2 import unittest 
 3 import time
 4 import datetime
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from BeautifulReport import BeautifulReport
import os
from selenium.webdriver.common.by import By class wxworkTest(unittest.TestCase):
'''企业微信-XXX移动端'''
@classmethod
def setUpClass(cls):
''' 所有的测试方法运行前运行,使用@classmethod装饰器进行修饰,整个测试过程中只执行一次 '''
wxwork = {
'platformName': 'Android', # android的apk
'deviceName': 'WTKDU16905017501', # 手机设备名称,通过adb devices查看
'platformVersion': '8.0', # android系统的版本号
'appPackage': 'com.tencent.wework', # apk包名
'appActivity': '.launch.LaunchSplashActivity', # apk的启动Activity
#'unicodeKeyboard': True, # 实现中文输入,使用unicodeKeyboard的编码方式来发送字符串
#'resetKeyboard': True # 将键盘给隐藏起来
}
cls.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", wxwork) # 连接appium
cls.driver.implicitly_wait(10) # 隐式等待,最长等待10s
# 切换到工作台
cls.driver.find_element_by_xpath("//*[@text='工作台']").click()
# 调用上滑方法,找到应用并进入
cls.up(4, 500)
time.sleep(1)
cls.driver.find_element_by_xpath("//*[@text='XXX测试']").click()
# 在移动端应用进入主页
cls.driver.find_element_by_xpath("//*[@text='XXX采购']").click()
print("已进入XXX移动端/我的工作台") @classmethod
def tearDownClass(cls):
''' 所有的测试方法运行后运行,使用@classmethod装饰器进行修饰,整个测试过程中只执行一次 '''
cls.driver.quit() # 退出应用
print("已退出企业微信") @classmethod
def getsize(self):
'''定义方法:自动获取手机屏幕'''
x = self.driver.get_window_size()['width']
y = self.driver.get_window_size()['height']
return (x, y) @classmethod
def up(self,n,t):
'''定义方法:上滑手势操作'''
screensize = self.getsize()
x1 = int(screensize[0] * 0.5)
y1 = int(screensize[1] * 0.7)
y2 = int(screensize[1] * 0.3)
for i in range(0, n):
self.driver.swipe(x1, y1, x1, y2, t)
print("第", i + 1, "次上滑成功啦") def save_img1(self):
"""直接指定路径,并用当前时间生成截图"""
# 获取当前时间,用于命名截图
pic_time = datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S")
# 截图保存写入的路径中
self.driver.get_screenshot_as_file("E:\\08PyCharmProject\\Case1\\img\\" + pic_time + ".png") def save_img(self, img_name):
'''用于放在测试报告的截图,os.path.abspath:返回当前目录的绝对路径,传入一个img_name,并存储到指定路径下'''
self.driver.get_screenshot_as_file('{}\{}.png'.format(os.path.abspath('E:\\08PyCharmProject\\Case1\\img'), img_name)) def editClear(self, text):
'''定义清除文本框方法'''
# 123代表光标移动到末尾
self.driver.keyevent(123)
for i in range(0, len(text)):
self.driver.keyevent(67) # 67退格键
# 清空后回车
self.driver.keyevent(66) def main_purchurse(self):
'''定义重新进入主页面的方法'''
'''用text不管用,用xpath的话,每个用例最终停留的界面不同,所以也不行,最后忍痛决定用tap'''
# 坐标点击我的工作台
self.driver.tap([(720, 1644), (1080, 1792)], 500)
# 坐标点击XXX
self.driver.tap([(0, 1644),(360, 1792)],500)
print("已在XXX主页面") def detail_purchurse(self):
'''定义重新进入XXX明细页面的方法'''
# 坐标点击我的工作台
self.driver.tap([(720, 1644), (1080, 1792)], 500)
# 坐标点击XXX
self.driver.tap([(0, 1644), (360, 1792)], 500)
# 通过定位电话图标,点击进入XXX明细页面
self.driver.find_element_by_xpath("//*[@text='ABs3ach']").click()
print("已在XXX明细页面") def test_case1(self):
'''case1:我的工作台:各种类型的订单统计跳转功能测试'''
self.driver.find_element_by_xpath("//*[@text='未发货']").click()
print("case1执行成功:完成了工作台的所有跳转测试") @BeautifulReport.add_test_img('test_case2') # 在测试用例中挂载一个装饰器,报错自动截图
def test_case2(self):
'''case2:我的工作台/XXX/XXX,来回切换(报错自动截图贴报告,不报错时用时间命名的截图,不贴报告)'''
self.main_purchurse() # 调用方法:我的工作台切换到XXX
# XXX切换到XXXX:tap定位
self.driver.tap([(360, 1644), (720, 1792)], 500)
print("成功切换到XXXX模块")
self.save_img1() # 截图断言弹窗提示语,没报错则调用另一个方法截图,没有入参 另一个方法不会附在测试报告上
print("case2执行成功:完成底部大模块的切换测试")
@BeautifulReport.add_test_img('test_case4') #报错自动截图
def test_case4(self):
'''case4:XXX主表:待下单状态的功能校验(报错自动截图贴报告,不报错也截图,不贴报告)'''
self.main_purchurse() # 调用方法:我的工作台切换到XXX
# 搜索功能测试:回车键搜索
self.driver.find_element_by_xpath("//android.widget.EditText[@text='供应商/采购员']").send_keys("M0001")
self.driver.keyevent(66) # 回车键搜索
print("搜索成功")
# 获取文本框的文本,用于传参给editClear函数
get_text = self.driver.find_element_by_xpath("//android.widget.EditText[@text='供应商/采购员']").get_attribute('text')
# 再次点击文本框,用于清空操作
self.driver.find_element_by_xpath("//android.widget.EditText[@text='供应商/采购员']").click()
self.editClear(get_text) # 调用方法:清空文本框的值
# 获取清空后文本框的文本,用于判断是否删除成功
get_text1 = self.driver.find_element_by_xpath("//android.widget.EditText[@text='供应商/采购员']").get_attribute("text")
print((get_text1))
if get_text1 == "供应商/采购员":
print("文本框删除成功")
else:
print("文本框删除失败")
# 点击分享
self.driver.find_element_by_xpath("//*[@text='分享']").click()
print("您想要分享给微信好友,还是企业微信好友呢?")
self.save_img('test_case4') # 不报错也自动截图
self.driver.find_element_by_xpath("//*[@text='取消']").click()
print("取消分享")
print("case4执行成功:完成XXX-待下单状态的功能测试") def test_case5(self):
'''case5:XXX明细页的状态切换测试'''
self.detail_purchurse() # 调用方法:进入XXX明细页
# 点击采购中tab列表,因为text有时不起作用,保险起见这里用了兄弟元素定位
self.driver.find_element_by_xpath("//android.widget.Button[@text='一键操作']/../android.view.View[4]//*[contains(@text,'采购中')]").click()
print("已进入XXX明细页的采购中列表")
'''这里删除了一些不重要的'''
       print("case5执行成功:完成版料明细页的状态切换") def test_case6(self):
'''case6:XXX明细页:待下单功能校验1-搜索区'''
self.detail_purchurse() # 调用方法:进入XXX明细页
# 搜索框输入sku,回车搜索
self.driver.find_element_by_xpath("//*[@class='android.widget.EditText']").send_keys("F00000583")
self.driver.keyevent(66)
print("sku搜索成功")
# 获取文本框的文本,用于传参给editClear函数
get_text = self.driver.find_element_by_xpath("//*[@class='android.widget.EditText']").get_attribute('text')
print(get_text)
# 再次点击文本框,用于清空操作
self.driver.find_element_by_xpath("//*[@class='android.widget.EditText']").click()
self.editClear(get_text) # 调用方法:清空文本框的值
# 获取清空后文本框的文本,用于判断是否删除成功
get_text1 = self.driver.find_element_by_xpath("//*[@class='android.widget.EditText']").get_attribute("text")
print((get_text1))
if get_text1 == "供应商/采购单号/物料名称/sku/设计款号/采购员":
print("文本框删除成功")
else:
print("文本框删除失败")
# 目标交期排序功能测试
self.driver.find_element_by_xpath("//*[@text='目标交期']").click()
print("目标交期筛选成功")
# 筛选功能测试(兄弟元素定位)
self.driver.find_element_by_xpath("//android.widget.Button[@text='一键操作']/../android.widget.Button").click()
self.driver.find_element_by_xpath("//android.widget.Button[@text='超期']").click()
self.driver.find_element_by_xpath("//android.widget.Button[@text='重置']").click()
self.driver.find_element_by_xpath("//android.widget.Button[@text='超期']").click()
self.driver.find_element_by_xpath("//android.widget.Button[@text='确定']").click()
print("成功输入超期筛选条件")
print("搜索成功")
# 一键操作功能测试:确认采购
self.driver.find_element_by_xpath("//android.widget.Button[@text='一键操作']").click()
# 定位复选框,点击确认采购:兄弟元素定位,因为有多个android.view.View兄弟,所以要带上[]
self.driver.find_element_by_xpath("//android.view.View[contains(@text,'地址')]/../android.view.View[1]/android.view.View[1]").click()
print("勾选上啦")
# 确认采购,虽然有text,但没定位成功,所以这里用的是ia+class组合定位
self.driver.find_element_by_xpath("//*[@resource-id='container']/android.widget.Button[3]").click()
print("确认采购成功")
self.driver.find_element_by_xpath("//*[@text='完成']").click()
print("case6执行成功:完成搜索与一键确认采购测试") def test_case7(self):
'''case7:XXX明细页:待下单的功能校验2-卡片区(不报错时也截图)'''
self.detail_purchurse() # 调用方法:进入XXX明细页
# 点击放大图片,方法一:从最父级,一层一层往下找
self.driver.find_element_by_xpath("//*[@resource-id='container']/android.view.View[5]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[4]/android.widget.Image").click()
print("放大图片")
self.save_img('test_case7') # 调用截图方法
time.sleep(2)
self.driver.keyevent(4) # 返回键
# 点击放大图片,方法二:根据兄弟元素(text:地址)定位到自己,再往下找
# 根据兄弟元素定位到自己,再往下找
self.driver.find_element_by_xpath("//android.view.View[contains(@text,'地址')]/../android.view.View/android.widget.Image").click()
self.driver.keyevent(4)
print("再次放大图片")
print("case7执行成功:完成卡片区的图片放大功能测试") def test_case8(self):
'''case8:XXX明细页:采购中状态-通知发货功能测试'''
self.detail_purchurse() # 调用方法:进入XXX明细页
# 点击采购中tab列表,因为text有时不起作用,保险起见这里用了兄弟元素定位
self.driver.find_element_by_xpath("//android.widget.Button[@text='一键操作']/../android.view.View[4]//*[contains(@text,'采购中')]").click()
print("已进入XXX明细页的采购中列表")
# 点击通知发货
self.driver.find_element_by_xpath("//*[@text='通知发货']").click()
print("已进入发货窗口")
# 打印本次采购单价输入框的文本
get_text = self.driver.find_element_by_xpath("//*[contains(@text,'*本次采购单价')]/../android.view.View/android.widget.EditText").get_attribute('text')
print(get_text)
# 定位到本次采购单价,并清除文本框的值,重新输入新的采购单价
self.driver.find_element_by_xpath("//*[contains(@text,'*本次采购单价')]/../android.view.View/android.widget.EditText").click()
self.editClear(get_text)
self.driver.find_element_by_xpath("//*[contains(@text,'*本次采购单价')]/../android.view.View/android.widget.EditText").send_keys(1)
# 打印是否免付选择框的文本
text = self.driver.find_element_by_xpath("//*[contains(@text,'*是否免付')]/../android.view.View/android.view.View").text
print(text)
# 点击是否免付选择框
self.driver.find_element_by_xpath("//*[contains(@text,'*是否免付')]/../android.view.View/android.view.View").click()
print("成功弹窗")
# 方法一:弹窗默认为是免付,直接确定
self.driver.find_element_by_xpath("//android.view.View[contains(@text,'确定')]").click()
# 方法二:再次点击出现免付弹窗,向上滑动,选到否免付后,确定
self.driver.find_element_by_xpath("//*[contains(@text,'*是否免付')]/../android.view.View/android.view.View").click()
self.up(2, 500)
loc = ("xpath", "//android.view.View[contains(@text,'确定')]")
try:
# 显示等待,EC.presence_of_element_located()直到元素出现
e = WebDriverWait(self.driver, 3, 0.5).until(EC.presence_of_element_located(loc))
# 也可以用By
#WebDriverWait(self.driver, 3, 0.5).until(EC.presence_of_element_located(By.XPATH, "//android.view.View[contains(@text,'确定')]"))
# 也可以用lambda函数
#e = WebDriverWait(self.driver, 3 ,0.5).until(lambda x: self.driver.find_element_by_xpath("//android.view.View[contains(@text,'确定')]"))
e.click()
print("成功选择非免付啦")
except:
pass
# 上传图片
self.driver.find_element_by_xpath("//android.view.View[contains(@text,'添加图片')]").click()
self.driver.find_element_by_xpath("//*[@resource-id='com.tencent.wework:id/aqa'][contains(@text,'其他方式')]").click()
self.driver.find_element_by_xpath("//*[@resource-id='com.android.documentsui:id/dir_list']/android.widget.LinearLayout[1]").click()
print("成功上传图片")
# 确定发货
self.driver.find_element_by_xpath("//android.widget.Button[contains(@text,'确定')]").click()
print("发货成功") @unittest.skip("暂时不执行该用例")
def test_case9(self):
'''case9:订单明细页:测试''' @BeautifulReport.add_test_img('test_case90')
def test_case90(self):
'''用于看测试报告的报错截图'''
self.main_purchurse() # 调用方法:进入XXX主表
self.driver.find_element_by_xpath("")
print("case90:故意输入错误的定位,用于报错截图")

  3、执行用例excute_case.py

 import unittest
from BeautifulReport import BeautifulReport
import datetime if __name__ == '__main__':
# 加载测试用例:指定E:\\08PyCharmProject\\Case1\\test_case目录,“test*.py”匹配指定目录下所有test开头的.py文件
test_suite = unittest.defaultTestLoader.discover('E:\\08PyCharmProject\\Case1\\test_case', pattern='test*.py')
# 获取当前时间,用于命名测试报告标题
now = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
# 将用例加到对象中
result = BeautifulReport(test_suite)
# report方法实现了用例的执行、用例执行结束的结果统计、生成测试报告等操作
# :filename -> 测试报告名称, 如果不指定默认文件名为report.html,description -> 测试报告用例名称展示,report_dir-> 报告文件写入路径
result.report(filename='测试报告'+str(now), description='自动化测试', report_dir='E:\\08PyCharmProject\\Case1\\report')

  4、执行结束后的img和report展示

  1)img展示,如图3

(图3:img目录展示截图)

  2)report展示,如图4-6

(图4:report目录展示测试报告)

(图5:html测试报告1)

(图6:html测试报告2-详细数据,报错的用例会有截图)

Appium+Python-项目实践一的更多相关文章

  1. python项目实践一:即时标记

    转自:http://www.code123.cc/1317.html 这是<python基础教程>后面的实践,照着写写,一方面是来熟悉python的代码方式,另一方面是练习使用python ...

  2. Python 项目实践一(外星人入侵)第一篇

    python断断续续的学了一段实践,基础课程终于看完了,现在跟着做三个小项目,第一个是外星人入侵的小游戏: 一 Pygame pygame 是一组功能强大而有趣的模块,可用于管理图形,动画乃至声音,让 ...

  3. Python 项目实践二(生成数据)第二篇之随机漫步

    接着上节继续学习,在本节中,我们将使用Python来生成随机漫步数据,再使用matplotlib以引人瞩目的方式将这些数据呈现出来.随机漫步是这样行走得到的路径:每次行走都完全是随机的,没有明确的方向 ...

  4. Python 项目实践三(Web应用程序)第一篇

    一 Djangao入门 当今的网站实际上都是富应用程序(rich application),就像成熟的桌面应用程序一样.Python提供了一组开发Web应用程序的卓越工具.在本章中,你将学习如何使用D ...

  5. Python 项目实践三(Web应用程序)第二篇

    接着上节的继续学习,使用Django创建网页的过程通常分三个阶段:定义URL.编写视图和编写模板.首先,你必须定义URL模式,每个URL都被映射到特定的视图--视图函数获取并处理网页所需的数据.视图函 ...

  6. Python 项目实践三(Web应用程序)第五篇

    接着上节继续学习,在这一节,我们将建立一个用户注册和身份验证系统,让用户能够注册账户,进而登录和注销.我们将创建一个新的应用程序,其中包含与处理用户账户相关的所有功能.我们还将对模型Topic稍做修改 ...

  7. Python 项目实践二(生成数据)第二篇

    接着上节继续学习,在本节中,我们将使用Python来生成随机漫步数据,再使用matplotlib以引人瞩目的方式将这些数据呈现出来.随机漫步是这样行走得到的路径:每次行走都完全是随机的,没有明确的方向 ...

  8. Python 项目实践一(外星人入侵)第二篇

    接着上次的继续学习. 一 创建一个设置类 每次给游戏添加新功能时,通常也将引入一些新设置.下面来编写一个名为settings的模块,其中包含一个名为Settings的类,用于将所有设置存储在一个地方, ...

  9. Python 项目实践一(外星人入侵小游戏)第二篇

    接着上次的继续学习. 一 创建一个设置类 每次给游戏添加新功能时,通常也将引入一些新设置.下面来编写一个名为settings的模块,其中包含一个名为Settings的类,用于将所有设置存储在一个地方, ...

  10. Python 项目实践一(外星人入侵小游戏)第三篇

    今天是圣诞节,公司放假一天,趁着有空,学习了一下午,多写一篇博客吧! 接着上节的继续学习, 一 重构:模块game_functions 在大型项目中,经常需要在添加新代码前重构既有代码.重构旨在简化既 ...

随机推荐

  1. 计时线程Runnable和Handler的结合

    利用Runnable和Handler,来创建计时线程 private double recodeTime = 0;// 用于计时 private double econdTime = 0;// 用于计 ...

  2. 【Java】手动编写第一个Java程序,HelloWorld!

    第一个Java程序HelloWorld! 环境前提:确保你已经配置好了JDK8的环境变量,和本体安装 打开文本编辑器,这里我使用的是EditPlus 编写代码: public class Hello{ ...

  3. C++关于容器vector的使用方法以及#ifdef #else #endif #if #ifndef 的使用

    //此处根据0还是1来判断具体使用那一段主函数 #if 1 #define WAY #endif #ifdef WAY #include <iostream> #include<st ...

  4. Crossing River POJ过河问题

    A group of N people wishes to go across a river with only one boat, which can at most carry two pers ...

  5. Python算法题:金字塔

    代码如下: #Python金字塔练习 """ 最大层数:max_level 当前层数:current_level 金字塔正序时: 每层的空格=最大层数-当前层数 每层的星 ...

  6. [转载]利用分块传输绕过WAF进行SQL注入

    原理 客户端给服务器发送数据的时候,如果我们利用协议去制作payload,就可以绕过http协议的waf,实现SQL注入 分块传输编码(Chunked transfer encoding)是HTTP中 ...

  7. kafka相关术语名词

    Topic:标签名,一个消息队列的名称 Producer:生产者,发布消息 Consumer:消费者,订阅发布消息,进行处理的存在 Broker:kafka集群,有一个.多个Topic Partiti ...

  8. 痞子衡嵌入式:大话双核i.MXRT1170之Cortex-M7与Cortex-M4互相激活之道

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是恩智浦i.MXRT1170上Cortex-M7与Cortex-M4内核互相激活的方法. 痞子衡最近在深耕i.MXRT1170这颗划时代的 ...

  9. 只会Vue怎么开发小程序?vue和微信小程序的到底有哪些区别?

    写了vue项目和小程序,发现二者有许多相同之处,在此想总结一下二者的共同点和区别. 一.生命周期 先贴两张生命周期图对比下: vue生命周期 小程序生命周期 相比之下,小程序的钩子函数要简单得多. v ...

  10. Scrapy爬虫框架(2)--内置py文件

    Scrapy概念图 这里有很多py文件,分别与Scrapy的各个模块对应 superspider是一个爬虫项目 spider1.py则是一个创建好的爬虫文件,爬取资源返回url和数据 items.py ...