第六周

python学习笔记和做的一些习题 (python编程快速上手——让繁琐工作自动化)

第十章

断言

它是要确保代码没有什么明显错误的地方,由assert语句执行,如果检查失败,就会抛出异常。assert语句包含一下部分:

• assert 关键字;

• 条件(即求值为 True 或 False 的表达式);

• 逗号;

• 当条件为 False 时显示的字符串。

python控制红绿灯案例 python红绿灯编程_Go


断言针对的是程序员的错误,而不是用户的错误。对于那些可以恢复的(诸如文件没有找到,或用户输入了无效的数据),请抛出异常,而不是用assert 语句检测它。

在交通灯模拟中使用断言:
假定你在编写一个交通信号灯的模拟程序。

# 编写路口字典
market_2nd = {'ns': 'green', 'ew': 'red'}
mission_16th = {'ns': 'red', 'ew': 'green'}
#编写一个 switchLights() 函数,它接受一个路口字典作为参数,并切换红绿灯。
def switchLights(stoplight):
     #添加断言 确保至少一个交通灯是红色
     assert 'red' in stoplight.values(), 'Neither light is red! ' + str(stoplight)
     for key in stoplight.keys():
         #如果信号灯为绿色,则切换为黄色
          if stoplight[key] == 'green':
              stoplight[key] = 'yellow'
          #黄色切换红色
          elif stoplight[key] == 'yellow':
              stoplight[key] = 'red'
          #红色切换绿色
          elif stoplight[key] == 'red':
              stoplight[key] = 'green'
      
switchLights(market_2nd)

禁用断言:在运行 Python 时传入-O 选项,可以禁用断言。

日志

我们经常在代码中加入 print() 语句,在程序运行时输出某些变量的值,这时候我们就使用了记日志的方式来调试代码。通过它,我们可以理解程序中
发生的事,以及事情发生的顺序。
Python 的 logging 模块使得你很容易创建自定义的消息记录。这些日志消息将描述程序执行何时到达日志函数调用,并列出你指定的任何变量当时的值。另一方面,缺失日志信息表明有一部分代码被跳过,从未执行。

使用日志模块:

import logging
#启用 logging 模块,在程序运行时将日志信息显示在屏幕上
logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s - %(message)s')
logging.debug('Start of program')
#编写一个函数,计算一个数的阶乘
def factorial(n):
    logging.debug('Start of factorial(%s)' % (n))
    total = 1
    for i in range(n + 1):
        total *= i
        logging.debug('i is ' + str(i) + ', total is ' + str(total))
    logging.debug('End of factorial(%s)' % (n))
    return total

print(factorial(5))
logging.debug('End of program')

结果为:

python控制红绿灯案例 python红绿灯编程_函数调用_02


可以看出,阶乘是从0开始的,应将for i in range(n + 1),改为for i in range(1,n + 1),结果为:

python控制红绿灯案例 python红绿灯编程_函数调用_03


日志级别:“日志级别”提供了一种方式,按重要性对日志消息进行分类。5 个日志级别下表所示,从最不重要到最重要。利用不同的日志函数,消息可以按某个级别记入日志。

级别

日志函数

描述

DEBUG

logging.debug()

最低级别。用于小细节。通常只有在诊断问题时,你才会关心这些消息。

INFO

logging.info()

用于记录程序中一般事件的信息,或确认一切工作正常。

WARNING

logging.warning()

用于表示可能的问题,他不会阻止程序的工作,但将来可能会。

ERROR

loggong.error()

用于记录错误,他导致程序做某事失败。

CRITICAL

logging.critical()

最高级别。用于表示知名的错误,他导致或将要导致程序完全停止。

禁用日志:在调试完程序后,你可能不希望所有这些日志消息出现在屏幕上。logging.disable() 函数禁用了这些消息。

将日志记录到文件:除了将日志消息显示在屏幕上,还可以将它们写入文本文件。logging.basicConfig() 函数接受 filename 关键字参数,

IDLE的调试器

“调试器”是 IDLE 的一项功能,让你每次执行一行程序。调试器将运行一行代

码,然后等待你告诉它继续。

要启用 IDLE 的调试器,就在交互式环境窗口中点击 Debug>>Debugger。这将打开调试控制(Debug Control)窗口:

python控制红绿灯案例 python红绿灯编程_python控制红绿灯案例_04


当调试控制窗口出现后,勾选全部 4 个复选框:Stack、Locals、Source 和 Globals。这样窗口将显示全部的调试信息。调试控制窗口显示时,只要你从文件编辑器运行程序,调试器就会在第一条指令之前暂停执行,并显示下面的信息:

• 将要执行的代码行;

• 所有局部变量及其值的列表;

• 所有全局变量及其值的列表。你会发现旁边还有这些键:

python控制红绿灯案例 python红绿灯编程_函数调用_05


Go:点击 Go 按钮将导致程序正常执行至终止,或到达一个“断点”。如果你完成了调试,希望程序正常继续,就点击 Go 按钮。

Step:点击 Step 按钮将导致调试器执行下一行代码,然后再次暂停。如果变量的值发生了变化,调试控制窗口的全局变量和局部变量列表就会更新。如果下一行代码是一个函数调用,调试器就会“步入”那个函数,跳到该函数的第一行代码。

Over:点击 Over 按扭将执行下一行代码,与 Step 按钮类似。但是,如果下一行代码是函数调用,Over 按钮将“跨过”该函数的代码。该函数的代码将以全速执行,调试器将在该函数返回后暂停。

Out:点击 Out 按钮将导致调试器全速执行代码行,直到它从当前函数返回。如果你用 Step 按钮进入了一个函数,现在只想继续执行指令,直到该函数返回,那就点击Out 按钮,从当前的函数调用“走出来”。

Quit:如果你希望完全停止调试,不必继续执行剩下的程序,就点击 Quit 按钮。

调试一个数字相加的程序:

print('Enter the first number to add:')
first = input()
print('Enter the second number to add:')
second = input()
print('Enter the third number to add:')
third = input()
print('The sum is ' + first + second + third)

python控制红绿灯案例 python红绿灯编程_Go_06


我们可以很明显的看出这个程序虽然运行出来,但得到的结果并不是我们想要的.

我们在启用调试控制窗口,再次运行上面的程序:

python控制红绿灯案例 python红绿灯编程_函数调用_07


程序启动时将暂停在第一行,点击Over,执行第一个print()调用:

python控制红绿灯案例 python红绿灯编程_函数调用_08


调试控制窗口将更新到第几行,文件编辑窗口的第几行就会高亮显示:

python控制红绿灯案例 python红绿灯编程_Go_09


继续点击Over,输入值,直到调试器运行到最后一行:

python控制红绿灯案例 python红绿灯编程_Go_10


可以看到,在全局变量的部分,第一个、第二个和第三个变量设置为字符串值,而不是整型值。当最后一行执行时,这些字符串连接起来,而不是加起来,导致了这个缺陷。

用调试器单步执行程序很有用,但也可能很慢。你常常希望程序正常运行,直到它到达特定的代码行。你可以使用断点,让调试器做到这一点。

断点:“断点”可以设置在特定的代码行上,当程序执行到达该行时,它迫使调试器暂停。

#模拟投掷1000次硬币
import random
heads = 0
for i in range(1, 1001):
 if random.randint(0, 1) == 1:
    heads = heads + 1
 if i == 500:
    print('Halfway done!')
print('Heads came up ' + str(heads) + ' times.')

运行结果:

python控制红绿灯案例 python红绿灯编程_函数调用_11


设置断点:右键>>set breakpoint

python控制红绿灯案例 python红绿灯编程_python控制红绿灯案例_12


带有断点的代码行会在文件编辑器中以黄色高亮显示。如果在调试器下运行该程序,开始它会暂停在第一行,像平时一样。但如果点击 Go,程序将全速运行,直到设置了断点的代码行。然后可以点击 Go、Over、Step 或 Out,正常继续。

第十章节习题

1.写一条 assert 语句,如果变量 spam 是一个小于 10 的整数,就触发AssertionError。

assert(spam>=10,'The spam is not less than 10')

2.编写一条 assert 语句,如果 eggs 和 bacon 包含的字符串彼此相同,而且不论大小写如何,就触发 AssertionError(也就是说,‘hello’ 和 ‘hello’ 被认为相同,‘goodbye’ 和 ‘GOODbye’ 也被认为相同)。

assert(eggs.lower()!=bacon.lower().'The eggs and bacon variables are the same.')

3.编写一条 assert 语句,总是触发 AssertionError。

assert(False,'This assertion always triggers.')

4.为了能调用 logging.debug(),程序中必须加入哪两行代码?

import logging
logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s - %(message)s')

5.为了让 logging.debug() 将日志消息发送到名为 programLog.txt 的文件中,程序必须加入哪两行代码?

import logging
logging.basicConfig(filename=programLog.txt,level=logging.DEBUG, format=' %(asctime)s - %(levelname)s - %(message)s')

6.5 个日志级别是什么?

级别

日志函数

描述

DEBUG

logging.debug()

最低级别。用于小细节。通常只有在诊断问题时,你才会关心这些消息。

INFO

logging.info()

用于记录程序中一般事件的信息,或确认一切工作正常。

WARNING

logging.warning()

用于表示可能的问题,他不会阻止程序的工作,但将来可能会。

ERROR

loggong.error()

用于记录错误,他导致程序做某事失败。

CRITICAL

logging.critical()

最高级别。用于表示知名的错误,他导致或将要导致程序完全停止。

7.你可以加入哪一行代码,禁用程序中所有的日志消息?

logging.disable(logging.CRITICAL)

8.显示同样的消息,为什么使用日志消息比使用 print() 要好?
可以禁用日志消息,不必删除日志函数调用。可以选择禁用低级别日志消
息。可以创建日志消息。日志消息提供了时间戳。

9.调试控制窗口中的 Step、Over 和 Out 按钮有什么区别?
Step 按扭让调试器进入函数调用。Over 按钮将快速执行函数调用,不会单
步进入其中。Out 按钮将快速执行余下的代码,直到走出当前所处的函数.

10.在点击调试控制窗口中的 Go 按钮后,调试器何时会停下来?
点击 Go,程序将全速运行,直到设置了断点的代码行。

11.什么是断点?
“断点”可以设置在特定的代码行上,当程序执行到达该行时,它迫使调试器暂停。

12.在 IDLE 中,如何在一行代码上设置断点?
右键>>set breakpoint

第十章节 实践项目

下面程序的意图是一个简单的硬币抛掷猜测游戏。玩家有两次猜测机会(这
是一个简单的游戏)。但是,程序中有一些缺陷。让程序运行几次,找出缺陷,使该程序能正确运行,下面是修改过的程序:

import random
guess = ''
while guess not in ('heads', 'tails'):
    print('Guess the coin toss! Enter heads or tails:')
    guess = input()
n = random.randint(0, 1) # 0 is tails, 1 is heads
toss = {0:'heads',1:'tails'}
if toss[n] == guess:
    print('You got it!')
else:
    print('Nope! Guess again!')
    guesss = input()
    if toss[n] == guess:
        print('You got it!')
    else:
        print('Nope. You are really bad at this game.')

python控制红绿灯案例 python红绿灯编程_python控制红绿灯案例_13

第十一章 从Web抓取信息

使用webbrowser模块

python控制红绿灯案例 python红绿灯编程_Go_14


可以在浏览器中打开你想要打开的网址.

用request模块从Web下载文件

requests.get()函数:接受一个要下载的URL字符串。通过在 requests.get()的返回值上调用 type(),你可以看到它返回一个 Response 对象,其中包含了 Web 服务器对你的请求做出的响应。

在Response对象上调用raise_for_status():检查文件是否下载成功。

下载并保存到文件的完整过程如下:
1.调用 requests.get()下载该文件。
2.用’wb’调用 open(),以写二进制的方式打开一个新文件。
3.利用 Respose 对象的 iter_content()方法做循环。iter_content()方法在循环的每次迭代中,返回一段内容。每一段都是 bytes 数据类型,你需要指定一段包含多少字节。
4.在每次迭代中调用 write(),将内容写入该文件。
5.调用 close()关闭该文件。

用BeautifulSoup模块解析网址

从HTML创建一个BeautifulSoup对象:
bs4.BeautifulSoup()函数调用时需要一个字符串,其中包含将要解析的HTML。bs4.BeautifulSoup()函数返回一个 BeautifulSoup 对象。

用select()方法寻找元素:

传递给select()方法的选择器

将匹配

soup.select(‘div’)

所有名为< div >的元素

soup.select(’#author’)

带有id属性为author的元素

soup.select(’.notice’)

所有使用CSS class属性名为notice的元素

soup.select(‘div span’)

所有在< div >元素之内的< span >元素

soup.select(‘div > span’)

所有直接在< div >元素之内的< span >元素,中间没有其他元素

soup.select(‘input[name]’)

所有名为< input >,并有一个name属性,其值无所谓的元素

soup.select(‘input[type=“button”]’)

所有名为< input >,并有一个type属性,其值为button的元素

用selenium模块控制浏览器

导入selenium 的模块需要一点技巧。不是import selenium,而是要运行from selenium import webdrive

在页面中寻找元素:WebDriver 对象有好几种方法,用于在页面中寻找元素。它们被分成find_element_*和find_elements_*方法。
selenium的WebDriver方法,用于寻找元素:

方法名

返回的WebElement对象/列表

browser.find_element_by_class_name(name) browser.find_elements_by_class_name(name)

使用CSS类name的元素

browser.find_element_by_css_selector(selector) browser.find_elements_by_css_selector(selector)

匹配 CSS selector 的元素

browser.find_element_by_id(id) browser.find_elements_by_id(id)

匹配 id 属性值的元素

browser.find_element_by_link_text(text) browser.find_elements_by_link_text(text)

完全匹配提供的 text 的< a >元素

browser.find_element_by_partial_link_text(text) browser.find_elements_by_partial_link_text(text)

包含提供的 text 的< a >元素

browser.find_element_by_name(name) browser.find_elements_by_name(name)

匹配 name 属性值的元素

browser.find_element_by_tag_name(name) browser.find_elements_by_tag_name(name)

匹配标签 name 的元素(大小写无关,< a >元素匹配’a’和’A’)

WebElement的属性和方法:

属性或方法

描述

tag_name

标签名,例如 'a’表示< a >元素

get_attribute(name)

该元素 name 属性的值

text

该元素内的文本,例如< span >hello</ span>中的’hello’

clear()

对于文本字段或文本区域元素,清除其中输入的文本

is_displayed()

如果该元素可见,返回 True,否则返回 False

is_enabled()

对于输入元素,如果该元素启用,返回 True,否则返回 False

is_selected()

对于复选框或单选框元素,如果该元素被选中,选择 True,否则返回 False

location

一个字典,包含键’x’和’y’,表示该元素在页面上的位置

点击页面: find_element_*和 find_elements_*方法返回的 WebElement 对象有一个 click()方法,模拟鼠标在该元素上点击。这个方法可以用于链接跳转,选择单选按钮,点击提交按钮,或者触发该元素被鼠标点击时发生的任何事情。

填写并提交表单:向 Web 页面的文本字段发送击键,只要找到那个文本字段的< input >或< textarea >元素,然后调用 send_keys()方法。

发送特殊键:selenium 有一个模块,针对不能用字符串值输入的键盘击键。它的功能非常类似于转义字符。这些值保存在selenium.webdriver.common.keys 模块的属性中。由于这个模块名非常长,所以在程序顶部运行 from selenium.webdriver. common.keys import Keys 就比较容易。如果这么做,原来需要写 from selenium.webdriver.common.keys 的地方,就只要写 Keys。
selenium.webdriver. common.keys模块中的常用变量:

属性

含义

Keys.DOWN, Keys.UP, Keys.LEFT,Keys.RIGHT

键盘箭头键

Keys.ENTER, Keys.RETURN

回车和换行键

Keys.HOME, Keys.END, Keys.PAGE_DOWN,Keys.PAGE_UP

Home 键、End 键、PageUp 键和 Page Down 键

Keys.ESCAPE, Keys.BACK_SPACE,Keys.DELETE

Esc、Backspace 和字母键

Keys.F1, Keys.F2, . . . , Keys.F12

键盘顶部的 F1到 F12键

Keys.TAB

Tab 键

点击浏览器按钮:

方法

浏览器按钮

browser.back()

点击“返回”按钮。

browser.forward()

点击“前进”按钮。

browser.refresh()

点击“刷新”按钮。

browser.quit()

点击“关闭窗口”按钮。