python接口自动化之python

一、python入门

1. python介绍

1.1 python可运用范围

1.1.1 脚本、小工具

import random
import win32api
import time
import win32con

names = ['张三', '李四', '王五', '小六']
name = random.choice(names)
print("抽到谁谁是大帅比!")
print("倒计时开始~")
for num in range(3):
     time.sleep(1)
     print(3-num)
time.sleep(1)
win32api.MessageBox(0, name, "提示", win32con.MB_ICONASTERISK)

1.1.2 单个接口测试

import requests
import json


def config():
    # 拉取配置,获取配置列表
    # url
    url = "http://17620533205.wicp.vip:46685/logout"
    # 请求头
    # headers = {
    #     'Content-Type': 'application/x-www-form-urlencoded'
    # }
    # 请求参数
    data = {
        'account': '111000',
        'password': '123456'
    }
    r1 = requests.post(url, json=data)
    # 以json数据类型接收,传给r2,r2即整个接口测试返回的数据
    r2 = r1.json()
    print(json.dumps(r2, sort_keys=True, indent=4, separators=(',', ':'), ensure_ascii=False))


config()

1.1.3 selenium

from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
url = 'https://dev.umaicloud.com/login'
# 访问网页登录页
driver.get(url)
# 点击账号输入框和输入账号
driver.find_element_by_xpath('//*[@id="app"]/div/div[3]/div[1]/div[2]/div[1]/form/div[1]/div/div/input').send_keys(
    'xxxxx')
# 点击密码输入框输入密码
driver.find_element_by_xpath('//*[@id="app"]/div/div[3]/div[1]/div[2]/div[1]/form/div[2]/div/div/input').send_keys(
    'xxxxx')
# 点击登录按钮
driver.find_element_by_xpath('//*[@id="app"]/div/div[3]/div[1]/div[2]/div[1]/form/div[4]/div/button').click()
time.sleep(10)
print("登录成功")
# 关闭浏览器
driver.quit()

# 八大定位元素方法
# find_element_by_name
# find_element_by_id
# find_element_by_xpath
# find_element_by_link_text
# find_element_by_partial_link_text
# find_element_by_tag_name
# find_element_by_class_name
# find_element_by_css_selector

1.1.4 appium

# -*- encoding=utf8 -*-
__author__ = "Administrator"
from airtest.core.api import *
auto_setup(__file__)
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)

def open_app(start_time):
 stop_app('com.tencent.mm')
 start_app('com.tencent.mm')
 sleep(2)
 items_elements = poco(name='com.tencent.mm:id/b2p').offspring('com.tencent.mm:id/e0n')
 names = list(map(lambda x: x.get_text(), items_elements))
 target = "调试"
 index = names.index(target)
 print([index])
 print(items_elements[index])
 items_elements[index].click()
 while True:
     times = time.strftime("%H:%M:%S")
     sleep(1)
     if times >= start_time:
         while True:
             try:
                 msg_list = poco("com.tencent.mm:id/alz").child("android.widget.RelativeLayout").offspring("com.tencent.mm:id/ak4")
             except Exception:
                 print("暂无红包,继续等待!")
             else:
                 while True:
                     for msg in msg_list:
                         red_package = msg.offspring("com.tencent.mm:id/r6")
                         invalid = msg.offspring("com.tencent.mm:id/aa5").offspring("com.tencent.mm:id/qv")
                         if red_package:
                             print("发现红包")
                             if invalid.exists() and (invalid.get_text() == '已领取' or invalid.get_text() == '已被领完'):
                                 print("无效红包")
                                 continue
                             else:
                                 print("有效红包,正在抢~")
                                 red_package.click()
                                 open_btn = poco("com.tencent.mm:id/dbr")
                                 if open_btn.exists():
                                     open_btn.click()
                                 else:
                                     print("来晚一步,已被抢完~")
                                 keyevent('BACK')

     else:
         print(times)


open_app("10:29:00")

1.1.5 爬虫

import requests
import re
from urllib import parse
from win32com.client import Dispatch
import time
import win32api
import pyperclip
from DownloadMovie import download


class dytt(object):
 def __init__(self):
     pass

 @staticmethod
 def get_id():
     name = parse.quote(input("请输入你要下载的电影名称:"), encoding='gbk')
     url = "http://s.ygdy8.com/plus/so1.php?typeid=1&keyword=" + name
     headers = {
         "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
         "Accept-Encoding": "gzip, deflate",
         "Accept-Language": "zh-CN,zh;q=0.9",
         "Connection": "keep-alive",
         "Cookie": "UM_distinctid=16f9ecd77256b4-07ee71ccac26da-376b4502-1fa400-16f9ecd77262a1",
         "Host": "s.ygdy8.com",
         "Upgrade-Insecure-Requests": "1",
         "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36",
     }
     r = requests.get(url, headers=headers, verify=False)
     r.encoding = 'gbk'
     # print(r.text)
     result1 = re.findall("<a href='/html/gndy/.+?</a>", r.text, re.S)
     # print(result1)
     if len(result1) == 0:
         print("未获取到资源~正在切换路线寻找资源···")
         names = parse.unquote(name, encoding='gbk')
         # print(names)
         download(names)
         time.sleep(3)
         quit()
     elif len(result1) == 1:
         result2 = str(re.findall("html/gndy/.+?.html", str(result1), re.S)).strip('[""]').strip("'")
         # print(result2)
         return result2
     else:
         for i in range(len(result1)):
             print(f"{i + 1}、", result1[i].strip("<a href=</a>"))
             i += 1
         num = int(input("请输入你要下载的电影序号:"))
         result2 = str(re.findall("html/gndy/.+?.html", result1[num - 1], re.S)).strip('[""]').strip("'")
         # print(result2)
         return result2

 @staticmethod
 def get_download_url():
     movie_id = dytt.get_id()
     requests.packages.urllib3.disable_warnings()
     url = "https://www.ygdy8.com/" + movie_id
     # print(url)
     r = requests.get(url, verify=False)
     r.encoding = 'gbk'
     # print(r.text)
     result = re.findall('>magnet:.+?<', r.text, re.S)
     # print(len(result))
     if len(result) == 0:
         result1 = re.findall('<a href="ftp:.+?">', r.text, re.S)
         if len(result1) == 0:
             result3 = re.findall('thunder.+?<', r.text, re.S)
             if len(result3) == 0:
                 print("暂未找到下载链接或下载链接失效!")
             elif len(result3) == 1:
                 print("正在打开迅雷,可能需要几秒钟~")
                 win32api.ShellExecute(0, 'open', 'C:\\Program Files\\Thunder\\Program\\ThunderStart.exe', '', '', 3)
                 time.sleep(5)
                 pyperclip.copy(result3)
             else:
                 for j in range(len(result3)):
                     print(f"{j + 1}、", result3[j])
                     j += 1
                 num = int(input("请选择:"))
                 pyperclip.copy(result3[num - 1])
         else:
             if len(result1) == 1:
                 result2 = str(result1).strip("['<a href=>']").strip('"')
                 # print(result2)
                 dytt.open_thunder(result2)
             else:
                 for m in range(len(result1)):
                     print(f"{m + 1}、", result1[m])
                     m += 1
                 num = int(input("请选择:"))
                 result2 = str(result1[num - 1]).strip("['<a href=>']").strip('"')
                 # print(result2)
                 dytt.open_thunder(result2)
     else:
         for n in range(len(result)):
             print(f"{n + 1}、", result[n].strip('><'))
             n += 1
         num = int(input("请输入你要下载的电影序号:"))
         result3 = result[num - 1].strip('><')
         dytt.open_thunder(result3)

 def open_thunder(downloadurl):
     print("正在打开迅雷,可能需要几秒钟~")
     win32api.ShellExecute(0, 'open', 'C:\\Program Files\\Thunder\\Program\\ThunderStart.exe', '', '', 3)
     time.sleep(5)
     thunder = Dispatch('ThunderAgent.Agent64.1')
     thunder.AddTask(downloadurl)
     thunder.CommitTasks()


dytt.get_download_url()

1.1.6 面向对象与面向过程

  • 区别

面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
举个栗子:用面向过程的方法写出来的程序是一份蛋炒饭,而用面向对象写出来的程序是一份盖浇饭。盖浇饭,就是菜饭分离,在一碗白米饭上面浇上一份盖菜,喜欢什么菜,你就浇上什么菜。

  • 面向过程

优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、易扩展。

  • 面向对象

优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护。
缺点:性能比面向过程低。

1.2 环境搭建(python+pycharm)

1.2.1 python下载

Python官网:https://www.python.org/

Python文档下载地址:https://www.python.org/doc/

\172.18.1.125\download添加到映射,长期共享学习软件。

1.2.2 python安装

https://www.runoob.com/python3/python3-install.html

1.2.3 python安装路径添加至path

如:D:\python;复制到系统变量中的path中。

1.2.4 检验安装

cmd中输入python,能进入python则安装成功,不能则环境有误或者安装不成功。

1.2.5 修改pip下载路径为国内源

在C:\Users\Administrator路径下新建pip文件夹,再进入pip文件夹中新建pip.ini文件,将下面三行复制保存即可。

[global]
trusted-host =  mirrors.aliyun.com
index-url = https://mirrors.aliyun.com/pypi/simple

1.2.6 升级pip版本到20版本+

python -m pip install --upgrade pip

1.2.7 查看安装的所有模块

pip list

1.2.8 设置pycharm运行Python的路径

打开pycharm——点击左上角文件-设置——搜索框中输入project——点击project interpreter右侧的下拉箭头——确认是否是你的Python的安装路径——如果找不到或路径不对,点击show all——再点击+添加——进入到new environment中——设置location(py文件的路径)——设置base interpreter(Python安装路径)——勾选下面inherit global···和make available

1.2.9 修改字体大小及主题

设置——搜索框搜索font——修改font、color scheme font、console font中的字体(推荐source code pro)、大小(16)、行距(1.0)

1.3 解释器及编码

1.3.1 解释器

未指定解释器时,在linux中运行代码可能会报错,需将下面一行复制在代码第一行

#!/usr/bin/python

1.3.2 编码

Python 文件中如果未指定编码,在执行过程可能会出现报错,Python3正常

#!/usr/bin/python

print ("你好,世界")

解决方法为只要在文件开头加入 # -*- coding: UTF-8 -*- 或者 # coding=utf-8 就行了,# coding=utf-8的=号两边不要空格

2.python基础(针对性讲解)

2.1 语法要求

  • python标识符

    在 Python 中,所有标识符可以包括英文、数字以及下划线,但不能以数字开头。

    包含:项目名称、包名、模块名、变量名、函数名、类名。

    最好见名知意,如test_goods,不建议test01等模糊命名方式,也尽量不要中文。

    Python标识符(除类名)命名规范建议都使用_隔开,如test_goods,不建议testgoods,testGoods。

    Python类名按照规范应该使用驼峰式命名法,如TestGoods,即首字母、后面每个单词的首字母大写。

    Python 可以同一行显示多条语句,方法是用分号 ; 分开,也可以使用\将一行语句分为多行,如:

    为了阅读舒适性,Python每行尽量不要超过80个字符,Pycharm也会有辅助线。

    print ('hello');print ('world');
    hello
    world
    print('hello \
          world')
    Hello,      World!
    
  • python保留字符

    下面的列表显示了在Python中的保留字。这些保留字不能用作常数或变数,或任何其他标识符名称。

    所有 Python 的关键字只包含小写字母

    and exec not
    assert finally or
    break for pass
    class from print
    continue global raise
    def if return
    del import try
    elif in while
    else is with
    except lambda yield
  • 行和缩进

    学习 Python 与其他语言最大的区别就是,Python 的代码块不使用大括号 {} 来控制类,函数以及其他逻辑判断。python 最具特色的就是用缩进来写模块。

    缩进的空白数量是可变的,但是所有代码块语句必须包含相同的缩进空白数量,这个必须严格执行。

    正确的缩进:

    if True:
        print ("True")
    else:
        print ("False")
    

    错误的缩进:

    if True:
        print ("Answer")
        print ("True")
    else:
        print ("Answer")
        # 没有严格缩进,在执行时会报错
      print ("False")
    

    执行以上代码,会出现如下错误提醒:

    File "test.py", line 11
        print ("False")
                      ^
    IndentationError: unindent does not match any outer indentation level
    

    因此,在 Python 的代码块中必须使用相同数目的行首缩进空格数。

    建议你在每个缩进层次使用单个制表符或两个空格或四个空格

  • 注释

    python中单行注释采用 # 开头,多行注释也可以全选要注释的内容,按住ctrl+/

    # 第一个注释
    print ("Hello, Python!")  # 第二个注释
    

    python 中多行注释使用三个单引号(''')或三个双引号(""")

    '''
    这是多行注释,使用单引号。
    这是多行注释,使用单引号。
    这是多行注释,使用单引号。
    '''
    """
    这是多行注释,使用双引号。
    这是多行注释,使用双引号。
    这是多行注释,使用双引号。
    """
    
  • 输入和输出

    print("我叫王智景")

    input("请输入内容:"),input是读取用户输入在控制台的内容,类型为str,可使用type()查看输入或输出类型。

2.2 常用运算符

  • 算数运算符

    a = 1
    b = 2
    w = a + b
    x = b - a
    y = a * b
    z = int(b / a)
    print(w, x, y, z)
    
  • 比较(关系)运算符

    运算符 描述 实例
    == 等于 - 比较对象是否相等 (a == b) 返回 False
    != 不等于 - 比较两个对象是否不相等 (a != b) 返回 true
    <> 不等于 - 比较两个对象是否不相等 (a <> b) 返回 true。这个运算符类似 !=
    > 大于 - 返回x是否大于y (a > b) 返回 False
    < 小于 - 返回x是否小于y (a < b) 返回 true
    >= 大于等于 - 返回x是否大于等于y (a >= b) 返回 False
    <= 小于等于 - 返回x是否小于等于y (a <= b) 返回 true
  • 赋值运算符

    运算符 描述 实例
    = 简单的赋值运算符 c = a + b 将 a + b 的运算结果赋值为 c
    += 加法赋值运算符 c += a 等效于 c = c + a
    -= 减法赋值运算符 c -= a 等效于 c = c - a
    *= 乘法赋值运算符 c *= a 等效于 c = c * a
    /= 除法赋值运算符 c /= a 等效于 c = c / a
    %= 取模赋值运算符 c %= a 等效于 c = c % a
    **= 幂赋值运算符 c **= a 等效于 c = c ** a
    //= 取整除赋值运算符 c //= a 等效于 c = c // a
  • 逻辑运算符

    运算符 逻辑表达式 描述
    and x and y "与"
    or x or y "或"
    not not x "非"
  • 成员运算符

    运算符 描述 实例
    in 找到返回True,否则False x 在 y 序列中 , 如果 x 在 y 序列中返回 True
    not in 没有找到返回True,否则False x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True

2.3 条件语句

常规语句表达:

if 判断条件:
    执行语句……
else:
    执行语句……

多个条件判断表达:

if 判断条件1:
    执行语句1……
elif 判断条件2:
    执行语句2……
elif 判断条件3:
    执行语句3……
else:
    执行语句4……

2.4 循环语句

2.4.1 for

for num in range(10):
    print(num) # num会从0开始遍历,至10结束(不包含10),打印出来
0
1
2
3
4
5
6
7
8
9
for num in range(1, 10):
    print(num) # num从1开始遍历,至10结束(不包含10),打印出来
1
2
3
4
5
6
7
8
9
names = ['张三', '李四', '王五', '小六']
for name in names:
    print(name) # 遍历列表names,打印names所有元素
张三
李四
王五
小六
names = ['张三', '李四', '王五', '小六']
print(len(names))  # 获取列表长度 结果为4
for num in range(len(names)):  # 将长度作为一个范围,num会从0遍历,再把num作为序号加入到列表索引中
    print(names[num])
4
张三
李四
王五
小六

2.4.2 while

执行语句可以是单个语句或语句块。判断条件可以是任何表达式,任何非零、或非空(null)的值均为true。

当判断条件假 false 时,循环结束。

while 判断条件:
    执行语句……
age = 0
while age > 0:  # 条件不成立,所以不会执行该while语句
    print("条件不成立")
while age == 0:  # 因为age永远是0,所以陷入无限循环
    print("条件为真")

2.4.3 循环控制语句

age = 0
while True:  # 判断该条件是否为真,真就会一直循环往下执行代码,也可以表示为while age >= 0:
    age += 1  # 每过一年,我大一岁
    if age > 18:  # 如果我长大到了18岁,则跳出循环
        print("我超过18岁了")
        break  # 开始跳出
    elif age == 18:  # 当age=18岁时,会走到这,因为加了pass语句,执行了空语句,所以不会报错
        # print("我刚好18岁了")
        pass
    else:
        print("我还没到18岁呢")  # 判断我还没到18岁,会一直循环下去,知道18岁才跳出循环
        continue
        print("加了continue就不会走到这条语句,没加的话会执行完else里的语句再进行下一次循环")
  • break

    Python break语句,就像在C语言中,打破了最小封闭for或while循环。

    break语句用来终止循环语句,即循环条件没有False条件或者序列还没被完全递归完,也会停止执行循环语句。

    break语句用在while和for循环中。如果您使用嵌套循环,break语句将停止执行最深层的循环,并开始执行下一行代码。

  • continue

    Python continue 语句跳出本次循环,continue后的语句不执行,未加continue会执行该次循环中所有符合条件的语句,执行完毕后再进入循环,而break跳出整个循环。

    continue 语句用来告诉Python跳过当前循环的剩余语句,然后继续进行下一轮循环。

    continue语句用在while和for循环中。

  • pass

    Python pass 是空语句,是为了保持程序结构的完整性。

    pass不做任何事情,一般用做占位语句。

2.5 变量类型

  • 整型

    a = 10

  • 浮点型

    a = 10.0

  • 字符串

    a = "name" or a = 'name'

  • 字典

    字典的每个键值 key=>value对用冒号 : 分割,每个键值对之间用逗号 , 分割整个字典包括在花括号 {} 中 。

    键一般是唯一的,如果重复最后的一个键值对会替换前面的,值不需要唯一。

    dict = {'a': 1, 'b': 2, 'b': '3'}

  • 列表

    list1 = ['physics', 'chemistry', 1997, 2000]

    list2 = [1, 2, 3, 4, 5 ]

    list3 = ["a", "b", "c", "d"]

  • 元组

    Python的元组与列表类似,不同之处在于元组的元素不能修改。

    元组使用小括号,列表使用方括号。

    tup1 = ('physics', 'chemistry', 1997, 2000)

    tup2 = (1, 2, 3, 4, 5 )

    tup3 = "a", "b", "c", "d"

2.6 字符串

  • 索引

    strings = 'hello world' # 空格也属于一个字符
    print(strings[0]) # 取第一个字符
    print(strings[1:5]) # 截取第二个字符到第五个(不包含5即第6个字符)
    
    h
    ello
    
  • 运算

    操作符 描述 实例
    + 字符串连接 >>>a + b 'HelloPython'
    * 重复输出字符串 >>>a * 2 'HelloHello'
    [] 通过索引获取字符串中字符 >>>a[1] 'e'
    [ : ] 截取字符串中的一部分 >>>a[1:4] 'ell'
    in 成员运算符 - 如果字符串中包含给定的字符返回 True >>>"H" in a True
    not in 成员运算符 - 如果字符串中不包含给定的字符返回 True >>>"M" not in a True
    % 格式字符串 请看下一章节
    var = 'Hello World!'
    
    print("输出:", var[:6] + 'Python!')
    
    输出: Hello Python!
    
  • 格式化

    符 号 描述
    %c 格式化字符及其ASCII码
    %s 格式化字符串
    %d 格式化整数
    %u 格式化无符号整型
    %o 格式化无符号八进制数
    %x 格式化无符号十六进制数
    %X 格式化无符号十六进制数(大写)
    %f 格式化浮点数字,可指定小数点后的精度
    %e 用科学计数法格式化浮点数
    %E 作用同%e,用科学计数法格式化浮点数
    %g %f和%e的简写
    %G %F 和 %E 的简写
    %p 用十六进制数格式化变量的地址

    Python 支持格式化字符串的输出 。尽管这样可能会用到非常复杂的表达式,但最基本的用法是将一个值插入到一个有字符串格式符 %s 的字符串中。

    #!/usr/bin/python
    
    print("My name is %s and I am %d years old!" % ('python', 29))
    
    My name is python and I am 29 years old!
    

2.7 列表

  • 访问列表中的值及截取

    Python 表达式 结果 描述
    L[2] 'Taobao' 读取列表中第三个元素
    L[-2] 'Runoob' 读取列表中倒数第二个元素
    L[1:] ['Runoob', 'Taobao'] 从第二个元素开始截取列表
    list1 = ['physics', 'chemistry', 1997, 2000]
    list2 = [1, 2, 3, 4, 5, 6, 7]
    
    print(list1[0])
    print(list2[1:5])
    
    physics
    [2, 3, 4, 5]
    
  • 增加值

    list = []  # 空列表
    list.append('hello')  # 使用 append() 添加元素
    list.append('python')
    print(list)
    
    ['hello', 'python']
    
  • 删除值

    list = []  # 空列表
    list.append('hello')  # 使用 append() 添加元素
    list.append('python')
    print(list)
    
    del list[1]  # 删除list中第二个元素,即python
    print(list)
    
  • 列表函数&方法

    序号 函数
    1 cmp(list1, list2) 比较两个列表的元素
    2 len(list) 列表元素个数
    3 max(list) 返回列表元素最大值
    4 min(list) 返回列表元素最小值
    5 list(seq) 将元组转换为列表
    序号 方法
    1 list.append(obj) 在列表末尾添加新的对象
    2 list.count(obj) 统计某个元素在列表中出现的次数
    3 list.extend(seq) 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
    4 list.index(obj) 从列表中找出某个值第一个匹配项的索引位置
    5 list.insert(index, obj) 将对象插入列表
    6 [list.pop(index=-1]) 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
    7 list.remove(obj) 移除列表中某个值的第一个匹配项
    8 list.reverse() 反向列表中元素
    9 list.sort(cmp=None, key=None, reverse=False) 对原列表进行排序

2.8 字典

  • 查(访问字典的值,同json取值)

    dicts = {'Name': 'python', 'Age': 29, 'sex': 'other'}
    
    print(dicts['Name'])
    print(dicts['Age'])
    
    python
    29
    

    如果字典中没有的键访问数据,会报KeyError: 'xxx'错误,解析json时遇到这种情况也会报错

    dicts = {'Name': 'python', 'Age': 29, 'Sex': 'other'}
    
    print(dicts['email'])
    
  • 增/改(增加/修改字典)

    dicts = {'Name': 'python', 'Age': 29, 'Sex': 'other'}
    dicts['Sex'] = '男'
    dicts['Age'] = 30
    print(dicts)
    
    {'Name': 'python', 'Age': 30, 'Sex': '男'}
    

    如果修改字典时取键时不在字典中,会在字典中新增键与值

    dicts = {'Name': 'python', 'Age': 29, 'Sex': 'other'}
    dicts['name'] = 'java'
    dicts['age'] = 30
    dicts['sex'] = '男'
    print(dicts)
    
    {'Name': 'python', 'Age': 29, 'Sex': 'other', 'name': 'java', 'age': 30, 'sex': '男'}
    
  • 删(删除字典元素)

    dicts = {'Name': 'python', 'Age': 29, 'Sex': 'other'}
    del dicts['Sex']
    print(dicts)  # 删除了Sex及值,打印时就不会被打印出来
    dicts.clear()  # 清空了字典元素,打印时会打印空的字典
    print(dicts)
    del dicts  # 删除了整个字典,所以打印时会提示未定义dicts
    print(dicts)
    
    {'Name': 'python', 'Age': 29}
    {}
    NameError: name 'dicts' is not defined
    

2.9 类型转换

2.9.1 各数据类型转换

有时候,我们需要对数据内置的类型进行转换,数据类型的转换,你只需要将数据类型作为函数名即可。

函数 描述
[int(x ,base]) 将x转换为一个整数
[long(x ,base] ) 将x转换为一个长整数
float(x) 将x转换到一个浮点数
[complex(real ,imag]) 创建一个复数
str(x) 将对象 x 转换为字符串
repr(x) 将对象 x 转换为表达式字符串
eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s) 将序列 s 转换为一个元组
list(s) 将序列 s 转换为一个列表
set(s) 转换为可变集合
dict(d) 创建一个字典。d 必须是一个序列 (key,value)元组。
frozenset(s) 转换为不可变集合
chr(x) 将一个整数转换为一个字符
unichr(x) 将一个整数转换为Unicode字符
ord(x) 将一个字符转换为它的整数值
hex(x) 将一个整数转换为一个十六进制字符串
oct(x) 将一个整数转换为一个八进制字符串

2.9.2 字符串与字典

json.dumps()和json.loads()是json格式处理函数(可以这么理解,json是字符串)
(1)json.dumps()函数是将一个Python数据类型列表进行json格式的编码(可以这么理解,json.dumps()函数是将json丢掉,不要json,那就是将字典转化为字符串)
(2)json.loads()函数是将json格式数据转换为字典(可以这么理解,json.loads()函数是加载json,意味着要json,那就是将字符串转化为字典)

  • json.dumps()

    data参数支持字典格式也支持字符串格式,如果是字典格式,requests方法会将其按照默认表单urlencoded格式转换为字符串,如果是字符串则不转化
    如果data以字符串格式传输需要遵循以下几点:

    • 必须是严格的JSON格式字符串,里面必须用双引号,k-v之间必须有逗号,布尔值必须是小写的true/false等等
    • 不能有中文,直接传字符串不会自动编码

    一般来说,建议将data声明为字典格式(方便数据添加修改),然后再用json.dumps()方法把data转换为合法的JSON字符串格式

    import json  # 需要导入JSON包
    
    data = {'name': '张三', 'password': '123456', "male": True, "money": None}  # 字典格式
    str_data = json.dumps(data)  # 序列化,转化为合法的JSON文本(方便HTTP传输)
    print(str_data)
    
    {"name": "\u5f20\u4e09", "password": "123456", "male": true, "money": null}
    

    indent: 缩进空格数,indent=0输出为一行

    sork_keys=True: 将json结果的key按ascii码排序

    ensure_ascii=Fasle: 不确保ascii码,如果返回格式为utf-8包含中文,不转化为\u...

    import json  # 需要导入JSON包
    
    data = {'name': '张三', 'password': '123456', "male": True, "money": None}  # 字典格式
    str_data = json.dumps(data, indent=4, sort_keys=True, ensure_ascii=False)  # 序列化,转化为合法的JSON文本(方便HTTP传输)
    print(str_data)
    
    {
        "male": true,
        "money": null,
        "name": "张三",
        "password": "123456"
    }
    
  • json.loads()

    将合法的JSON字符串转换字典

    import json  # 需要导入JSON包
    
    data = {'name': '张三', 'password': '123456', "male": True, "money": None}  # 字典格式
    str_data1 = json.dumps(data, indent=4, sort_keys=True, ensure_ascii=False)  # 序列化,转化为合法的JSON文本(方便HTTP传输)
    print(str_data1)
    print(type(str_data1))
    str_data2 = json.loads(str_data1)
    print(str_data2)
    print(type(str_data2))
    
    {
        "male": true,
        "money": null,
        "name": "张三",
        "password": "123456"
    }
    <class 'str'>
    {'male': True, 'money': None, 'name': '张三', 'password': '123456'}
    <class 'dict'>
    

3. 脚本实例编写

  • 打印1~100中所有奇数/偶数
  • 计算1~100之间所有奇数的和
  • 计算1~100之间所有偶数的和

二、接口测试

1. 内置模块

1.1 time

序号 函数及描述
1 time.altzone 返回格林威治西部的夏令时地区的偏移秒数。如果该地区在格林威治东部会返回负值(如西欧,包括英国)。对夏令时启用地区才能使用。
2 [time.asctime(tupletime]) 接受时间元组并返回一个可读的形式为"Tue Dec 11 18:07:14 2008"(2008年12月11日 周二18时07分14秒)的24个字符的字符串。
3 time.clock( ) 用以浮点数计算的秒数返回当前的CPU时间。用来衡量不同程序的耗时,比time.time()更有用。
4 [time.ctime(secs]) 作用相当于asctime(localtime(secs)),未给参数相当于asctime()
5 [time.gmtime(secs]) 接收时间戳(1970纪元后经过的浮点秒数)并返回格林威治天文时间下的时间元组t。注:t.tm_isdst始终为0
6 [time.localtime(secs]) 接收时间戳(1970纪元后经过的浮点秒数)并返回当地时间下的时间元组t(t.tm_isdst可取0或1,取决于当地当时是不是夏令时)。
7 time.mktime(tupletime) 接受时间元组并返回时间戳(1970纪元后经过的浮点秒数)。
8 time.sleep(secs) 推迟调用线程的运行,secs指秒数。
9 [time.strftime(fmt,tupletime]) 接收以时间元组,并返回以可读字符串表示的当地时间,格式由fmt决定。
10 time.strptime(str,fmt='%a %b %d %H:%M:%S %Y') 根据fmt的格式把一个时间字符串解析为时间元组。
11 time.time( ) 返回当前时间的时间戳(1970纪元后经过的浮点秒数)。
12 time.tzset() 根据环境变量TZ重新初始化时间相关设置。
  • time.time()——获取时间戳

    import time
    
    print(time.time())
    
    1588929714.3305402
    
  • 获取当前时间(格式化时间)

    python中时间日期格式化符号

    • y 两位数的年份表示(00-99)
    • %Y 四位数的年份表示(000-9999)
    • %m 月份(01-12)
    • %d 月内中的一天(0-31)
    • %H 24小时制小时数(0-23)
    • %I 12小时制小时数(01-12)
    • %M 分钟数(00=59)
    • %S 秒(00-59)
    • %a 本地简化星期名称
    • %A 本地完整星期名称
    • %b 本地简化的月份名称
    • %B 本地完整的月份名称
    • %c 本地相应的日期表示和时间表示
    • %j 年内的一天(001-366)
    • %p 本地A.M.或P.M.的等价符
    • %U 一年中的星期数(00-53)星期天为星期的开始
    • %w 星期(0-6),星期天为星期的开始
    • %W 一年中的星期数(00-53)星期一为星期的开始
    • %x 本地相应的日期表示
    • %X 本地相应的时间表示
    • %Z 当前时区的名称
    • %% %号本身
    import time
    
    localtime = time.strftime('%Y-%m-%d %H:%M:%S')
    print(localtime)
    
    20-05-08 17:26:05
    
  • round()

    语法

    round(number,digits)

    参数

    number

    要四舍五入的数,digits是要小数点后保留的位数。

    如果 digits 大于 0,则四舍五入到指定的小数位。

    如果 digits 等于 0,则四舍五入到最接近的整数。

    如果 digits 小于 0,则在小数点左侧进行四舍五入。

    如果round函数只有参数number,等同于digits 等于 0。

    返回值

    四舍五入后的值

print(round(3.1415926, 2))


```python
3.14
import time

print(time.time())  # 打印当前时间戳
print(round(time.time()))  # 打印无小数点的时间戳
print(round(time.time()*100))  # 等于1588932416.278496四舍五入后的值*100,即12位时间戳
1588932416.278496
1588932416
158893241628

1.2 calendar

序号 函数及描述
1 calendar.calendar(year,w=2,l=1,c=6) 返回一个多行字符串格式的year年年历,3个月一行,间隔距离为c。 每日宽度间隔为w字符。每行长度为21* W+18+2* C。l是每星期行数。
2 calendar.firstweekday( ) 返回当前每周起始日期的设置。默认情况下,首次载入 calendar 模块时返回 0,即星期一。
3 calendar.isleap(year) 是闰年返回 True,否则为 False。>>> import calendar >>> print(calendar.isleap(2000)) True >>> print(calendar.isleap(1900)) False
4 calendar.leapdays(y1,y2) 返回在Y1,Y2两年之间的闰年总数。
5 calendar.month(year,month,w=2,l=1) 返回一个多行字符串格式的year年month月日历,两行标题,一周一行。每日宽度间隔为w字符。每行的长度为7* w+6。l是每星期的行数。
6 calendar.monthcalendar(year,month) 返回一个整数的单层嵌套列表。每个子列表装载代表一个星期的整数。Year年month月外的日期都设为0;范围内的日子都由该月第几日表示,从1开始。
7 calendar.monthrange(year,month) 返回两个整数。第一个是该月的星期几的日期码,第二个是该月的日期码。日从0(星期一)到6(星期日);月从1到12。
8 calendar.prcal(year,w=2,l=1,c=6) 相当于 print calendar.calendar(year,w=2,l=1,c=6)
9 calendar.prmonth(year,month,w=2,l=1) 相当于 print calendar.month(year,month,w=2,l=1)
10 calendar.setfirstweekday(weekday) 设置每周的起始日期码。0(星期一)到6(星期日)。
11 calendar.timegm(tupletime) 和time.gmtime相反:接受一个时间元组形式,返回该时刻的时间戳(1970纪元后经过的浮点秒数)。
12 calendar.weekday(year,month,day) 返回给定日期的日期码。0(星期一)到6(星期日)。月份为 1(一月) 到 12(12月)。
  • 获取某月日历

    import calendar
    
    cal = calendar.month(2020, 5)
    print(cal)
    
          May 2020
    Mo Tu We Th Fr Sa Su
                 1  2  3
     4  5  6  7  8  9 10
    11 12 13 14 15 16 17
    18 19 20 21 22 23 24
    25 26 27 28 29 30 31
    
  • 格式化日期

    import time
    
    # 格式化成2016-03-20 11:45:39形式
    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
    
    # 格式化成Sat Mar 28 22:24:24 2016形式
    print(time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()))
    
    # 将格式字符串转换为时间戳
    a = "Sat Mar 28 22:24:24 2016"
    print(time.mktime(time.strptime(a, "%a %b %d %H:%M:%S %Y")))
    
    2020-05-08 17:32:39
    Fri May 08 17:32:39 2020
    1459175064.0
    

1.3 json

类型转换已经提到过,可以翻阅类型转换查看,下面也截取了一部分关键内容,可以多了解一点

函数 描述
json.dumps 将 Python 对象编码成 JSON 字符串
json.loads 将已编码的 JSON 字符串解码为 Python 对象
  • python 原始类型向 json 类型的转化对照表
Python JSON
dict object
list, tuple array
str, unicode string
int, long, float number
True true
False false
None null
  • json 类型转换到 python 的类型对照表
JSON Python
object dict
array list
string unicode
number (int) int, long
number (real) float
true True
false False
null None

1.4 random

  • 返回值

    返回随机生成的一个实数,它在[0,1)范围内。

    import random
    
    # 生成第一个随机数
    print(random.random())
    
    # 生成第二个随机数
    print(random.random())
    
    0.9516361757935445
    0.3494738700183079
    
  • 常用方法

    import random
    
    list = [1, 2, 3, 4, 5]
    print(random.randint(1, 10))  # 产生 1 到 10 的一个整数型随机数
    print(random.random())  # 产生 0 到 1 之间的随机浮点数
    print(random.uniform(1.1, 5.4))  # 产生  1.1 到 5.4 之间的随机浮点数,区间可以不是整数
    print(random.choice(list))  # 从序列中随机选取一个元素
    print(random.randrange(1, 100, 2))  # 生成从1到100的间隔为2的随机整数
    random.shuffle(list)  # 将序列list中的元素顺序打乱
    print(list)
    
    7
    0.04950387613677654
    3.5018207607321745
    5
    65
    [3, 4, 5, 1, 2]
    

1.5 os常用方法

  • os.open()

    import os
    
    # 打开文件
    fd = os.open("foo.txt", os.O_RDWR | os.O_CREAT)
    
    # 关闭文件
    os.close(fd)
    
    print("关闭文件成功!!")
    

    os.open(files, flags[, mode])打开一个文件,并且设置需要的打开选项,mode参数是可选的。

    • file -- 要打开的文件
    • flags -- 该参数可以是以下选项,多个使用 "|" 隔开:
      • os.O_RDONLY: 以只读的方式打开
      • os.O_WRONLY: 以只写的方式打开
      • os.O_RDWR : 以读写的方式打开
      • os.O_NONBLOCK: 打开时不阻塞
      • os.O_APPEND: 以追加的方式打开
      • os.O_CREAT: 创建并打开一个新文件
      • os.O_TRUNC: 打开一个文件并截断它的长度为零(必须有写权限)
      • os.O_EXCL: 如果指定的文件存在,返回错误
      • os.O_SHLOCK: 自动获取共享锁
      • os.O_EXLOCK: 自动获取独立锁
      • os.O_DIRECT: 消除或减少缓存效果
      • os.O_FSYNC : 同步写入
      • os.O_NOFOLLOW: 不追踪软链接
    • mode -- 类似 chmod()
  • os.system()

    system函数可以将字符串转化成命令在服务器上运行。

    import os
    
    os.system('shutdown /s /t 300 /c "5分钟后自动关机"')
    

1.6 hashlib

hashlib是一个提供字符加密功能的模块,包含MD5和SHA的加密算法,具体支持md5,sha1, sha224, sha256, sha384, sha512等算法。 该模块在用户登录认证方面应用广泛,对文本加密也很常见。

简单来说。就是三步:

1,建立加密对象。2,对字符串进行算法加密。3,获得16进制显示。

import hashlib

md5 = hashlib.md5()  # 创建hashlib的md5对象
md5.update('字符串'.encode('utf-8'))  # 将字符串载入到md5对象中,获得md5算法加密
new_md5 = md5.hexdigest()  # 通过hexdigest()方法,获得new_md5对象的16进制md5显示
print(new_md5)
cc4dd1da7e1a754534215f02fb9ba85d

注意:向对象中传入字符串时,在python3中需要对字符串进行 encode 操作必须为编码类型。使用.encode('UTF-8')的方法,使字符串变为bytes类型。

可以创建的加密算法有:md5,sha1, sha224, sha256, sha384, sha512。

import hashlib
new_md5 = hashlib.md5()
new_sha1 = hashlib.sha1()
new_sha256 = hashlib.sha256()

2. 第三方模块

2.1 requests

  • 安装库

    pip install requests
    
  • 导入库

    import requests
    

3. 组成

3.1 url

3.2 params的用法

  • 参数类型

    字典,字典中键值对作为查询参数。

  • 特点

    url为基准的url地址,不包含查询参数。

    该方法会自动对params字典编码,然后和url拼接。

    import requests
    
    url = 'http://httpbin.org/get'
    data = {
        "name": "张三",
        "age": 22
    }
    response = requests.get(url, params=data)  # 自动对params中的内容进行编码,然后和url进行拼接,再发出请求,查看打印的name已经被编码了,如需解码可以用urllib.parse.unquote
    print(response.url)
    
    http://httpbin.org/get?name=%E5%BC%A0%E4%B8%89&age=22
    
  • 参数包含在url中

    import requests
    response = requests.get("http://httpbin.org/get?name=zhangsan&age=22")
    print(response.text)
    
  • 通过get方法传送参数

    import requests
    
    url = 'http://httpbin.org/get?name=zhangsan&age=22'
    data = {
        "name": "zhangsan",
        "age": 22
    }
    response = requests.get("http://httpbin.org/get", params=data)
    # print(response.text)
    print(response.url)
    if url == response.url:
        print("两个url是一致的")
    else:
        print("两个url不一致")
    

3.3 data

  • 用于post请求

    通常,想要发送一些编码为表单形式的数据(像HTML表单),只需传递一个字典给data参数,然后数据字典在发出请求时会自动编码为表单形式。

    response = requests.post(url, data = data, headers=headers)
    

3.4 headers

  • 模拟发送请求头(传送headers参数)

    有些网站为了避免被爬虫攻击,会用请求头中的User-Agent来判断是否是浏览器请求,提交数据类型也可以在请求头中声明。

    import requests
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36",
        "Content-Type": "application/x-www-form-urlencoded"
    }
    response = requests.get("http://httpbin.org/get", headers=headers)
    print(response.text)
    

3.5 cookies和session

  • cookies和session的用处

    使用的cookie和session好处:很多网站必须登录后(或者获取某种权限后)才能够请求到相关数据。

    使用的cookie和session的弊端:一套cookie和session往往和一个用户对应.请求太快,请求次数太多,容易被服务器识别为爬虫,从而使账号收到损害。

    • 不需要cookie的时候尽量不去使用cookie。
    • 为了获取登录之后的页面,我们必须发送带有cookies的请求,此时为了确保账号安全应该尽量降低数据采集速度。
  • 获取cookies信息

    response.cookies
    
  • cookies在首次登录后获取到,后面可以放在requests提交时用

    import requests
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36",
        "Content-Type": "application/x-www-form-urlencoded"
    }
    response = requests.get("http://httpbin.org/get", headers=headers, cookies=response.cookies)
    print(response.text)
    
  • 构造session回话对象

    requests库的session会话对象可以跨请求保持某些参数,说白了,就是比如你使用session成功的登录了某个网站,则在再次使用该session对象求求该网站的其他网页都会默认使用该session之前使用的cookie等参数。

    session = requests.session()
    

4. get请求

  • 无参数

    常用于访问网址或无参数的请求url

    import requests
    response = requests.get("www.baidu.com")
    print(response.headers)  # 可查看响应头headers中Content-Type中的类型,从而决定以什么方法接收
    print(response.text)  
    
  • 有参数

    import requests
    
    url = 'http://httpbin.org/get'
    data = {
        "name": "张三",
        "age": 22
    }
    response = requests.get(url, params=data)  # 自动对params中的内容进行编码,然后和url进行拼接,再发出请求,查看打印的name已经被编码了,如需解码可以用urllib.parse.unquote
    print(response.url)
    print(response.headers)  # 返回的是application/json,尽量用response.json()
    print(response.text)  # 可能也不会报错,但是数据类型不是字典,是字符串
    print(type(response.text))
    print(response.json())  # 返回的是json,以json去接收,数据类型是字典,方便后续字典取值
    print(type(response.json()))
    
    {'Date': 'Sat, 09 May 2020 03:39:03 GMT', 'Content-Type': 'application/json', 'Content-Length': '378', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true'}
    {
      "args": {
        "age": "22", 
        "name": "\u5f20\u4e09"
      }, 
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Host": "httpbin.org", 
        "User-Agent": "python-requests/2.22.0", 
        "X-Amzn-Trace-Id": "Root=1-5eb625d7-7528eeb39efb718f94feac7e"
      }, 
      "origin": "183.15.91.21", 
      "url": "http://httpbin.org/get?name=\u5f20\u4e09&age=22"
    }
    
    <class 'str'>
    {'args': {'age': '22', 'name': '张三'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.22.0', 'X-Amzn-Trace-Id': 'Root=1-5eb625d7-7528eeb39efb718f94feac7e'}, 'origin': '183.15.91.21', 'url': 'http://httpbin.org/get?name=张三&age=22'}
    <class 'dict'>
    
  • urllib.parse.quote编码(需要导入urllib.parse)

    此处name=张三已经被编码了,用这个urllib.parse.quote可实现一样的效果。

    from urllib import parse  # 或者import urllib.parse
    name = '张三'
    age = '22'
    url1 = 'http://httpbin.org/get?name=%E5%BC%A0%E4%B8%89&age=22'
    new_name = urllib.parse.quote(name)
    print(new_name)
    url2 = "http://httpbin.org/get?name=" + new_name + '&age=' + age
    print(url2)
    if url1 == url2:
        print("两个url是一致的")
    else:
        print("两个url不一致")
    
    %E5%BC%A0%E4%B8%89
    http://httpbin.org/get?name=%E5%BC%A0%E4%B8%89&age=22
    两个url是一致的
    
  • urllib.parse.unquote解码

    from urllib import parse  # 或者import urllib.parse
    name = '%E5%BC%A0%E4%B8%89'  # %E5%BC%A0%E4%B8%89即张三
    print(urllib.parse.unquote(name))
    
    张三
    

5. post请求

  • x-www-form-urlencoded

    浏览器原生form表单默认的数据格式。

    name=value&name2=value2=name3=value3
    
  • application/json

    具体表述请求数据为json格式,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据( enctype 的 POST 默认方式)。

    {"name1":"value1","name2":"value2"}
    
  • text/html

    以xml的形式进行传参。

    <!--?xml version="1.0"?-->
    <methodcall>
    <methodname>examples.getStateName</methodname>
    <params>
    <param>
    <value><i4>41</i4></value>
    </params>
    </methodcall>
    

6. 代理

  • 代理的用法

    proxies = {
        "http": "https://175.44.148.176:9000",
        "https": "https://183.129.207.86:14002"
    }
    response = requests.get("https://www.baidu.com/", proxies=proxies)
    

7. response属性

属性 描述
response.text 获取str类型(Unicode编码)的响应,即:url对应的页面内容
response.content 获取bytes类型的响应
response.status_code 获取响应状态码
response.headers 获取响应头
response.request 获取响应对应的请求
response.url 获取请求url
response.encoding 从HTTP header中猜测的响应内容编码方式
  • response.encoding

    当用response.text获取了html内容出现unicode码时,可以通过设置字符编码response.encoding 来匹配指定的编码,这样就不会乱码了。

    import requests
    r = requests.get("http://www.baidu.com")
    print(r.text)  # 未指定编码,打印中文时出现乱码
    
    <!DOCTYPE html>
    <!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>ç�¾åº¦ä¸�ä¸�ï¼�ä½ å°±ç�¥é��</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=ç�¾åº¦ä¸�ä¸� class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>æ�°é�»</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>å�°å�¾</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>è§�é¢�</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>è´´å�§</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>ç�»å½�</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">ç�»å½�</a>');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">æ�´å¤�产å��</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>å
    

³äº�ç�¾åº¦</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使ç�¨ç�¾åº¦å��å¿
读</a>  <a href=http://jianyi.baidu.com/ class=cp-feedback>æ��è§�å��é¦�</a> äº¬ICPè¯�030173å�·  <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>


> 指定encoding后可以解决乱码,utf-8是通用编码,如遇到中文乱码问题,也可以使用gbk2312

```python
import requests
r = requests.get("http://www.baidu.com")
r.encoding = 'utf-8'
# r.encoding = 'gbk2312'
print(r.text)
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>

三、python进阶

1. 函数

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。

1.1 规则

函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()

任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。

函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。

函数内容以冒号起始,并且缩进。

return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

1.2 调用

# 定义函数
def printme1():
    print("无参数,随便打印")


def printme2(strings):
    "打印任何传入的字符串"
    print(strings)
    return  # 未带表达式,不返回内容则不用写return,两者相同,所以返回的是None


def printme3(a):
    "打印任何传入的字符串"
    print(f"传进来的a的值为:{a}")
    b = 2
    c = a + b
    return c  # 带表达式,会返回a给调用方,经常这样表达:返回值=函数名(参数)


# 调用函数
printme1()  # 无参数,不用填写参数,直接函数名()调用即可
printme2("调用函数!")  # 有参数,需要提交参数,不然会报错
num = printme3(1)
print("返回的c的值为:{num}")

1.3 参数

1.3.1 必备参数

必备参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。

调用printme()函数,你必须传入一个参数,不然会出现语法错误:

def printme(strings):
    "打印任何传入的字符串"
    print(strings)
printme()
TypeError: printme() missing 1 required positional argument: 'strings'

1.3.2 关键字参数

关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。

使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。

def printme(string1, string2):
    "打印任何传入的字符串"
    print(string1)
    print(string2)
printme(string2="打赢我Java你就是第一", string1="php是世界上最好的语言!")  # 会按照关键字传值,所以顺序不重要
php是世界上最好的语言!
打赢我Java你就是第一

1.3.3 默认参数

调用函数时,默认参数的值如果没有传入,则被认为是默认值。下例会打印默认的age。

# 可写函数说明
def printinfo(name, age=35):
    "打印任何传入的字符串"
    print("Name: ", name)
    print("Age ", age)
    return
# 调用printinfo函数
printinfo(age=50, name="miki")  # 传递了age,所以age取最后一次传递的值
printinfo(name="miki")  # 没有传递age,但是age有默认值,所以不会报错
Name:  miki
Age  50
Name:  miki
Age  35

1.3.4 不定长参数

你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述2种参数不同,声明时不会命名。基本语法如下:

def printinfo(arg1, *arg2):
    "打印任何传入的参数"
    print(arg1)
    for var in arg2:
        print(var)
    return
# 调用printinfo 函数
printinfo(10)
printinfo(70, 60, 50, 40)  # 70传递给了arg1,剩下的60 50 40···全部传给了arg2

1.4 return

函数中return后,需要在调用方接收值表达如下:

def test():
    a = 1
    return a
b = test()  # 右侧调用test函数,因为函数返回了a的值,所以在左侧设置一个变量b接收函数返回的a,为了避免看起来混乱,所以尽量改个名来接收返回的值
print(b)  # 此时b的值就是a,也就是1

1.5 全局变量和局部变量

定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。如下实例:

total = 0  # 这是一个全局变量


# 可写函数说明
def sum(arg1, arg2):
    # 返回2个参数的和."
    total = arg1 + arg2  # total在这里是局部变量.
    print("函数内是局部变量 : ", total)

    return total


# 调用sum函数
sum(10, 20)
print("函数外是全局变量 : ", total)
函数内是局部变量 :  30
函数外是全局变量 :  0

2. file读写

open()方法,用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出 OSError。

注意:使用 open() 方法一定要保证关闭文件对象,即调用 close() 方法。

open() 函数常用形式是接收两个参数:文件名(file)和模式(mode)。

open(file, mode='r')
完整的语法格式为:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
  • mode参数:

    模式 描述
    t 文本模式 (默认)。
    x 写模式,新建一个文件,如果该文件已存在则会报错。
    b 二进制模式。
    + 打开一个文件进行更新(可读可写)。
    U 通用换行模式(不推荐)。
    r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
    rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
    r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
    rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。
    w 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
    wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
    w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
    wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
    a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
    ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
    a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
    ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。
  • file对象

    file 对象使用 open 函数来创建,下表列出了 file 对象常用的函数:

    序号 方法及描述
    1 file.close()关闭文件。关闭后文件不能再进行读写操作。
    2 file.flush()刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。
    3 file.fileno()返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上。
    4 file.isatty()如果文件连接到一个终端设备返回 True,否则返回 False。
    5 file.next()返回文件下一行。
    6 [file.read(size])从文件读取指定的字节数,如果未给定或为负则读取所有。
    7 [file.readline(size])读取整行,包括 "\n" 字符。
    8 [file.readlines(sizeint])读取所有行并返回列表,若给定sizeint>0,则是设置一次读多少字节,这是为了减轻读取压力。
    9 [file.seek(offset, whence])设置文件当前位置
    10 file.tell()返回文件当前位置。
    11 [file.truncate(size])截取文件,截取的字节通过size指定,默认为当前文件位置。
    12 file.write(str)将字符串写入文件,返回的是写入的字符长度。
    13 file.writelines(sequence)向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。

3. 异常处理

异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行。

当Python脚本发生异常时我们需要捕获处理它,否则程序会终止执行。

3.1 try except else finally

try:
<语句>        #运行别的代码
except BaseException:  # BaseException为所有异常的基类,还有很多异常,RuntimeError、ValueError··
<语句>        #如果引发了异常,执行这,不执行else
else:
<语句>        #如果没有异常发生,就执行else,不会执行except
finally:
<语句>        #不管有无报错,都会执行这条语句
a = 1
try:
    print(b)  # 尝试打印b,但是b不存在,所以会报错
except Exception as e:  # 在这捕获了异常,且打印出异常,代码还会往下执行,不捕获的话走到print(b)就会终止运行
    print(e)
else:  #
    print(a)
finally:
    print("不管有无报错,都会执行这条语句")
<class 'Exception'>
不管有无报错,都会执行这条语句

3.2 try except else

try:
    正常的操作
except:
    发生异常,执行这块代码
else:
    如果没有异常执行这块代码

3.3 try finally

try:
<语句>
finally:
<语句>    #退出try时总会执行

3.4 触发异常

我们可以使用raise语句自己触发异常。

# 定义函数
def mye(level):
    if level < 1:
        raise(Exception, "Invalid level!")
        # 触发异常后,后面的代码就不会再执行


try:
    mye(0)  # 触发异常
except Exception:
    print(Exception, "Invalid level!")  # 这里捕获异常且打印异常
else:
    print(2)
<class 'Exception'> Invalid level!

3.5 用户自定义异常

通过创建一个新的异常类,程序可以命名它们自己的异常。异常应该是典型的继承自Exception类,通过直接或间接的方式。

class Networkerror(RuntimeError):
    def __init__(self, arg):
        self.args = arg
try:
    raise Networkerror("Bad hostname")
except Networkerror as e:
    print(e)

4. 面向对象

4.1 类

用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

  • 创建类

    class ClassName:
       '类的帮助信息'   #类文档字符串
       class_suite  #类体
    

    类的帮助信息可以通过ClassName.doc查看。

    class_suite 由类成员,方法,数据属性组成。

    class Employee:
        '所有员工的基类'
        empCount = 0
    
        def __init__(self, name, salary):
            self.name = name
            self.salary = salary
            Employee.empCount += 1
    
        def displayCount(self):
            print("Total Employee %d" % Employee.empCount)
            
        def displayEmployee(self):
            print("Name : ", self.name, ", Salary: ", self.salary)
    

    empCount 变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 Employee.empCount 访问。

    第一种方法init()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法。

    self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。

  • self代表类的实例,而非类

    类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。

    class Test:
        def prt(self):
            print(self)
            print(self.__class__)
            print("我是打印")
    t = Test()  # 实例化对象,无参数传递,函数如设置了参数,则需要在此传递
    t.prt()  # 通过类Test()调用类里的方法,等于Test().prt(),只是把Test()传给了t
    
    <__main__.Test object at 0x000001DC4B453648>
    <class '__main__.Test'>
    我是打印
    

4.2 实例化对象与访问属性

  • 创建实例对象

    类的实例化类似函数调用方式,并通过 init 方法接收参数。

    t1 = man('zhangsan', 24)
    t2 = man('lisi', 25)
    
  • 初始化方法

    init用作初始化方法,类需要的变量可以放在这,语法格式为self.名称=初始值,当使用类名()创建对象时,Python便会自动调用初始化方法为对象的属性且设置初始值。

    def __init__(self, name, age):  # 实例化对象时传递name和age给self.name和self.age,后续类中的任何方法需要调用name时,输入self.name或self.age即可访问,直接类.类变量和这有一定的区别,见下文4.5章节中解释
            self.name = name
            self.age = age
    
  • 调用方法和变量

    使用.来访问方法。

    使用.访问类变量。

    t1 = man('zhangsan', 24)
    t.print1()  # 调用print1方法,即类名+类中的方法名
    t1.age  # 调用类中的age变量
    
    class man:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def print1(self):
            print("我是负责打印的~")
            print(self.name)
        def print2(self):
            print("我也是负责打印的~")
            print(self.age)
    t = man('zhangsan', 24)  # 实例化对象给t,后续t就是类,只用用t调用方法或变量
    t.print1()  # 通过类调用类里面定义的方法(函数和方法的区别见下面4.3章节中描述)
    t.print2()
    pring(t.name)  # 通过类调用类变量name和age
    pring(t.age)
    

4.3 类方法和Python函数的区别

  • 所处位置不同

    类方法是class类中的,函数不是类中的。

  • 定义的方式不同

    函数定义的方式是def关键字,然后接函数名,再是括号,括号里面写形参也可以省略不写。

    def test():
        pringt("我是打印")
    test()  # 函数调用,无参数时不用传递参数,有参数时必须传递参数
    

    方法定义的方式是定义在类中的,其他大体和函数定义差不多,这里需要注意的一点就是方法必须带一个默认参数(如self),静态方法除外(见静态方法介绍)。

    class Test(object):
        def test(self):
            pringt("我是打印")
    t = Test()  # 实例化对象
    t.test()  # 方法调用是通过对象.方法调用
    
  • 调用的方式不一致

    函数的调用:函数的调用是直接写,函数名(参数1,参数2,......)

    方法的调用:对象.方法

    t = Test()  # 实例化对象
    t.test()  # 方法调用是通过对象.方法调用
    

4.4 深入理解实例化对象

class 人(object):
    def __init__(self,性别,年龄,姓名等等):
        self.性别=性别
        self.年龄=年龄
        self.姓名=姓名
    def 吃饭(self,要吃的菜品):
        print(要吃的菜品)
    def 喝水(self,要喝的水)
        print(要喝的水)
    def 睡觉(self)
        pass
小明=人(男,20岁,小明)
小明.吃饭('青椒土豆丝')
小明.喝水('快乐肥宅水')
小明.睡觉()

在上面例子中,人要吃饭,人要喝水,所以吃饭和喝水都是人这一类中,因为类是具有相同属性(吃饭、喝水、睡觉)的集合,但是人类是个集合,是个名称,是个名词,是个抽象的东西,不是具体对象,“人类”不能实现吃饭,但人类中的小明可以实现吃饭和喝水,所以类需要一个具体对象去实现类中的方法,这就是实例化对象,然后用实例化的对象去执行类中的方法。

4.5 深入理解类方法、静态方法、类变量和实例变量

  • 类方法

    @classmethod修饰符对应的方法不需要实例化,也不需要self参数,需要传递一个cls参数,可以通过类名直接调用。

    类中def定义的方法必须要实例化对象调用,且需要self参数。

    class Test(object):
        @classmethod  # 使用@classmethod修饰符
        def test(cls):  
            pass
    Test.test()  # 直接使用类名调用test方法
    
    class Test(object):
        def test(self):  
            pass
    t = Test()  # 需要实例化,通过实例化对象调用test方法
    t.test()
    
  • 静态方法

    加了@staticmethod修饰符的方法,参数可以为空,支持类名和实例对象调用,等同于放在外部的函数,为了代码的整一性和美观,所以放在类中。

    class Test(object):
        @classmethod  # 使用@classmethod修饰符
        def test1(cls):
            print("我是类方法")
        def test2(self):
            print("我也是类方法")
        @staticmethod
        def test3():
            print("我是静态方法")
    # Test是叫类名,Test()是叫类,要区分开来
    Test.test1()  # 直接使用类名调用类方法test1()
    t = Test()  # 实例化对象,用t和Test()是一样的,只是为了书写和方便会把类名传给一个值
    t.test2()  # 通过类的实例对象调用类的方法test2()
    t.test3()  # 通过类的实例对象调用类中静态方法test3()
    Test.test3()  # 支持通过类名直接调用静态方法
    
  • 类变量

    类名和实例对象都可以访问,实例只能访问,不能修改。类名可以访问和修改。

    # Test()是表达类,Test是类名,
    # 在常规的类中,只需记住类名调用类变量,类(实例对象)调用类方法
    class Test(object):
        a = 10  # 类变量
        def test(self):
            print(Test.a)  # 通过类名调用类变量
            t.a = 20    # 实例只能访问类变量,不能修改类变量a的值
            print(t.a)  # 通过实例调用类变量
            print(Test.a)  # 这里再次打印的还是a = 10
    t = Test()  # 需要实例化,通过实例对象调用test方法
    t.test()
    
    10
    20
    10
    
    class Test(object):
        a = 10  # 类变量
        def test(self):
            print(Test.a)  # 通过类名调用类变量
            print(t.a)     # 通过实例调用类变量
            Test.a = 20    # 实例调用类变量,且重新赋值20
            print(Test.a)  # 实例再次调用类变量查看a的值
            print(t.a)     # 因为a已经被修改成了20,所以调用的时候都会打印20
    t = Test()  # 需要实例化,通过实例对象调用test方法
    t.test()
    
    10
    10
    20
    20
    
  • 实例变量

    实例变量,即实例对象时传递的参数,实例对象可调用。

    class man(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def print1(self):
            print("我是负责打印的~")
            print(self.name)
        def print2(self):
            print("我也是负责打印的~")
            print(self.age)
    t = man("zhangsan", 24)  # 实例化对象,且传递变量到了init方法中,self.name接收了name的值,self.name='zhangsan'即实例变量,后面类中调用self.name即可
    

5. mysql

5.1 数据库连接与查询

Python查询Mysql使用 fetchone() 方法获取单条数据, 使用fetchall() 方法获取多条数据。

  • fetchone(): 该方法获取下一个查询结果集。结果集是一个对象

  • fetchall():接收全部的返回结果行.

  • rowcount: 这是一个只读属性,并返回执行execute()方法后影响的行数。

import MySQLdb

# 打开数据库连接
db = MySQLdb.connect("localhost", "testuser", "test123", "TESTDB", charset='utf8')

# 使用cursor()方法获取操作游标
cursor = db.cursor()

# 使用execute方法执行SQL语句
cursor.execute("SELECT VERSION()")

# 使用 fetchone() 方法获取一条数据
data = cursor.fetchone()

# 关闭数据库连接
db.close()

5.2 数据库更新操作

import MySQLdb

# 打开数据库连接
db = MySQLdb.connect("localhost", "testuser", "test123", "TESTDB", charset='utf8')

# 使用cursor()方法获取操作游标 
cursor = db.cursor()

# SQL 更新语句
sql = "UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE SEX = '%c'" % ('M')
try:
    # 执行SQL语句
    cursor.execute(sql)
    # 提交到数据库执行
    db.commit()
except:
    # 发生错误时回滚
    db.rollback()

# 关闭数据库连接
db.close()

5.3 删除操作

import MySQLdb

# 打开数据库连接
db = MySQLdb.connect("localhost", "testuser", "test123", "TESTDB", charset='utf8')

# 使用cursor()方法获取操作游标 
cursor = db.cursor()

# SQL 删除语句
sql = "DELETE FROM EMPLOYEE WHERE AGE > %s" % (20)
try:
    # 执行SQL语句
    cursor.execute(sql)
    # 提交修改
    db.commit()
except:
    # 发生错误时回滚
    db.rollback()

# 关闭连接
db.close()

6. 多线程

6.1 线程模块

Python3 通过两个标准库 thread 和 threading 提供对线程的支持。

thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。

threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:

  • threading.currentThread(): 返回当前的线程变量。
  • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:

  • run(): 用以表示线程活动的方法。
  • start():启动线程活动。
  • join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
  • isAlive(): 返回线程是否活动的。
  • getName(): 返回线程名。
  • setName(): 设置线程名。

6.2 创建多线程

  • 方式一:函数式,调用thread模块中的_start_new_thread()函数来产生新线程。

    _thread.start_new_thread ( function, args[, kwargs] )
    # function - 线程函数
    # args - 传递给线程函数的参数,他必须是个tuple类型
    # kwargs - 可选参数
    
    import _thread
    import time
    
    
    # 为线程定义一个函数
    def print_time(threadName, delay):
        count = 0
        while count < 5:
            time.sleep(delay)
            count += 1
            print("%s: %s" % (threadName, time.ctime(time.time())))
    
    
    # 创建两个线程
    try:
        _thread.start_new_thread(print_time, ("Thread-1", 2,))
        _thread.start_new_thread(print_time, ("Thread-2", 4,))
    except:
        print("Error: 无法启动线程")
    
    while 1:
        pass
    
    Thread-1: Sun May 10 18:37:08 2020
    Thread-2: Sun May 10 18:37:10 2020
    Thread-1: Sun May 10 18:37:10 2020
    Thread-1: Sun May 10 18:37:12 2020
    Thread-2: Sun May 10 18:37:14 2020
    Thread-1: Sun May 10 18:37:14 2020
    Thread-1: Sun May 10 18:37:16 2020
    Thread-2: Sun May 10 18:37:18 2020
    Thread-2: Sun May 10 18:37:22 2020
    Thread-2: Sun May 10 18:37:26 2020
    
  • 方式二:使用Threading模块创建线程,直接从threading.Thread继承创建一个新的子类,并实例化后调用 start() 方法启动新线程,即它调用了线程的 run() 方法:

    import threading
    import time
    
    exitFlag = 0
    
    
    class myThread(threading.Thread):
        def __init__(self, threadID, name, counter):
            threading.Thread.__init__(self)
            self.threadID = threadID
            self.name = name
            self.counter = counter
    
        def run(self):
            print("开始线程:" + self.name)
            print_time(self.name, self.counter, 5)
            print("退出线程:" + self.name)
    
    
    def print_time(threadName, delay, counter):
        while counter:
            if exitFlag:
                threadName.exit()
            time.sleep(delay)
            print("%s: %s" % (threadName, time.ctime(time.time())))
            counter -= 1
    
    
    # 创建新线程
    thread1 = myThread(1, "Thread-1", 1)
    thread2 = myThread(2, "Thread-2", 2)
    
    # 开启新线程
    thread1.start()
    thread2.start()
    thread1.join()
    thread2.join()
    print("退出主线程")
    
    开始线程:Thread-1
    开始线程:Thread-2
    Thread-1: Sun May 10 18:43:46 2020
    Thread-2: Sun May 10 18:43:47 2020
    Thread-1: Sun May 10 18:43:47 2020
    Thread-1: Sun May 10 18:43:48 2020
    Thread-2: Sun May 10 18:43:49 2020
    Thread-1: Sun May 10 18:43:49 2020
    Thread-1: Sun May 10 18:43:50 2020
    退出线程:Thread-1
    Thread-2: Sun May 10 18:43:51 2020
    Thread-2: Sun May 10 18:43:53 2020
    Thread-2: Sun May 10 18:43:55 2020
    退出线程:Thread-2
    退出主线程
    

6.3 线程锁

当线程需要共享数据时,可能存在数据不同步的问题。

考虑这样一种情况:一个列表里所有元素都是0,线程"set"从后向前把所有元素改成1,而线程"print"负责从前往后读取列表并打印。可能线程"set"开始改的时候,线程"print"便来打印列表了,输出就成了一半0一半1,这就是数据的不同步。为了避免这种情况,引入了锁的概念。

锁有两种状态——锁定和未锁定。每当一个线程比如"set"要访问共享数据时,必须先获得锁定;如果已经有别的线程比如"print"获得锁定了,那么就让线程"set"暂停,也就是同步阻塞;等到线程"print"访问完毕,释放锁以后,再让线程"set"继续。

经过这样的处理,打印列表时要么全部输出0,要么全部输出1,不会再出现一半0一半1的尴尬场面。

import threading
import time

class myThread (threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
    def run(self):
        print ("开启线程: " + self.name)
        # 获取锁,用于线程同步
        threadLock.acquire()
        print_time(self.name, self.counter, 3)
        # 释放锁,开启下一个线程
        threadLock.release()

def print_time(threadName, delay, counter):
    while counter:
        time.sleep(delay)
        print ("%s: %s" % (threadName, time.ctime(time.time())))
        counter -= 1

threadLock = threading.Lock()
threads = []

# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# 开启新线程
thread1.start()
thread2.start()

# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)

# 等待所有线程完成
for t in threads:
    t.join()
print ("退出主线程")
开启线程: Thread-1
开启线程: Thread-2
Thread-1: Sun May 10 18:47:12 2020
Thread-1: Sun May 10 18:47:13 2020
Thread-1: Sun May 10 18:47:14 2020
Thread-2: Sun May 10 18:47:16 2020
Thread-2: Sun May 10 18:47:18 2020
Thread-2: Sun May 10 18:47:20 2020
退出主线程

7. 正则

7.1 re.match()和re.search()

re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。

re.match(pattern, string, flags=0)
# pattern 匹配的正则表达式
# string 要匹配的字符串
# flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。

匹配对象方法 描述
group(num=0) 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
import re

line = "Cats are smarter than dogs"
# .* 表示任意匹配除换行符(\n、\r)之外的任何单个或多个字符
matchObj = re.match(r'(.*) are (.*?) .*', line, re.M | re.I)

if matchObj:
    print("matchObj.group() : ", matchObj.group())
    print("matchObj.group(1) : ", matchObj.group(1))
    print("matchObj.group(2) : ", matchObj.group(2))
else:
    print("No match!!")
matchObj.group() :  Cats are smarter than dogs
matchObj.group(1) :  Cats
matchObj.group(2) :  smarter

re.match()和re.search()的区别:

re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None。

re.search 匹配整个字符串,直到找到一个匹配。

import re
 
line = "Cats are smarter than dogs"
 
matchObj = re.match( r'dogs', line, re.M|re.I)
if matchObj:
   print ("match --> matchObj.group() : ", matchObj.group())
else:
   print ("No match!!")
 
matchObj = re.search( r'dogs', line, re.M|re.I)
if matchObj:
   print ("search --> matchObj.group() : ", matchObj.group())
else:
   print ("No match!!")
No match!!
search --> matchObj.group() :  dogs

7.2 re.sub()

Python 的re模块提供了re.sub用于替换字符串中的匹配项。

re.sub(pattern, repl, string, count=0, flags=0)
# pattern : 正则中的模式字符串
# repl : 替换的字符串,也可为一个函数
# string : 要被查找替换的原始字符串
# count : 可选参数,模式匹配后替换的最大次数,默认 0 表示替换所有的匹配
# flags : 可选参数,编译时用的匹配模式,数字形式
phone = "2004-959-559 # 这是一个电话号码"

# 删除注释
num = re.sub(r'#.*$', "", phone)
print("电话号码 : ", num)

# 移除非数字的内容
num = re.sub(r'\D', "", phone)
print("电话号码 : ", num)
电话号码 :  2004-959-559 
电话号码 :  2004959559

7.3 re.compile()

compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。

re.compile(pattern[, flags])
# pattern : 一个字符串形式的正则表达式
# flags 可选,表示匹配模式,比如忽略大小写,多行模式等
# re.I 忽略大小写:
# re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
# re.M 多行模式
# re.S 即为' . '并且包括换行符在内的任意字符(' . '不包括换行符)
# re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
# re.X 为了增加可读性,忽略空格和' # '后面的注释

7.4 re.findall()

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

注意: match 和 search 是匹配一次 findall 匹配所有。

re.findall(string[, pos[, endpos]])
# string 待匹配的字符串
# pos 可选参数,指定字符串的起始位置,默认为0
# endpos 可选参数,指定字符串的结束位置,默认为字符串的长度
import re
 
pattern = re.compile(r'\d+')   # 查找数字
result1 = pattern.findall('runoob 123 google 456')
result2 = pattern.findall('run88oob123google456', 0, 10)
 
print(result1)
print(result2)
['123', '456']
['88', '12']

7.5 正则表达式模式

模式 描述
^ 匹配字符串的开头
$ 匹配字符串的末尾。
. 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
[...] 用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k'
[^...] 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
re* 匹配0个或多个的表达式。
re+ 匹配1个或多个的表达式。
re? 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
re{ n} 匹配n个前面表达式。例如,"o{2}"不能匹配"Bob"中的"o",但是能匹配"food"中的两个o。
re{ n,} 精确匹配n个前面表达式。例如,"o{2,}"不能匹配"Bob"中的"o",但能匹配"foooood"中的所有o。"o{1,}"等价于"o+"。"o{0,}"则等价于"o*"。
re{ n, m} 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
a| b 匹配a或b
(re) 匹配括号内的表达式,也表示一个组
(?imx) 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
(?-imx) 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
(?: re) 类似 (...), 但是不表示一个组
(?imx: re) 在括号中使用i, m, 或 x 可选标志
(?-imx: re) 在括号中不使用i, m, 或 x 可选标志
(?#...) 注释.
(?= re) 前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。
(?! re) 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功。
(?> re) 匹配的独立模式,省去回溯。
\w 匹配数字字母下划线
\W 匹配非数字字母下划线
\s 匹配任意空白字符,等价于 [\t\n\r\f]。
\S 匹配任意非空字符
\d 匹配任意数字,等价于 [0-9]。
\D 匹配任意非数字
\A 匹配字符串开始
\Z 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。
\z 匹配字符串结束
\G 匹配最后匹配完成的位置。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\n, \t, 等。 匹配一个换行符。匹配一个制表符, 等
\1...\9 匹配第n个分组的内容。
\10 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。

7.6 正则表达式修饰符

修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

7.7 正则表达式实例

字符匹配

实例 描述
python 匹配 "python".

字符类

实例 描述
[Pp]ython 匹配 "Python" 或 "python"
rub[ye] 匹配 "ruby" 或 "rube"
[aeiou] 匹配中括号内的任意一个字母
[0-9] 匹配任何数字。类似于 [0123456789]
[a-z] 匹配任何小写字母
[A-Z] 匹配任何大写字母
[a-zA-Z0-9] 匹配任何字母及数字
[^aeiou] 除了aeiou字母以外的所有字符
[^0-9] 匹配除了数字外的字符

特殊字符类

实例 描述
. 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式
\d 匹配一个数字字符。等价于 [0-9]
\D 匹配一个非数字字符。等价于 [^0-9]
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]
\w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'
\W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容