• 【Python学习】Day-032 Day-033 xpath;xml数据格式、多线程、线程池、常用命令


    1. xml与xpath

    1.1 xpath基本概念

    1. 树:整个html(xml)代码结构就是一个树结构
    2. 节点:树结构中的每一个元素(标签)就是一个节点
    3. 根节点(根元素): html或者xml最外面的那个标签(元素)
    4. 节点内容:标签内容
    5. 节点属性:标签属性

    1.2 xml数据格式

    1. xml和json一样,是一种通用的数据格式(绝大部分编程语言都支持的数据格式)
    2. xml是通过标签(元素)的标签内容和标签属性来保存数据的。
    <supermarket name="永辉超市" address="肖家河大厦">
        <staffs>
            <staff  id="s001" class="c1">
                <name>小明name>
                <position>收营员position>
                <salary>4000salary>
            staff>
            <staff  id="s002">
                <name>小花name>
                <position>促销员position>
                <salary>3500salary>
            staff>
            <staff  id="s003">
                <name>张三name>
                <position>保洁position>
                <salary>3000salary>
            staff>
            <staff  id="s004" class="c1">
                <name>李四name>
                <position>收营员position>
                <salary>4000salary>
            staff>
            <staff  id="s005">
                <name>王五name>
                <position>售货员position>
                <salary>3800salary>
            staff>
        staffs>
        
        <goodsList>
            <goods discount="0.9">
                <name>泡面name>
                <price>3.5price>
                <count>120count>
            goods>
            <goods class="c1">
                <name>火腿肠name>
                <price>1.5price>
                <count>332count>
            goods>
            <goods>
                <name>矿泉水name>
                <price>2price>
                <count>549count>
            goods>
            <goods discount="8.5">
                <name>面包name>
                <price>5.5price>
                <count>29count>
            goods>
        goodsList>
    supermarket>
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    1.3 xpath基本语法

    1. 创建树结构获取树的根节点
      etree.XML(xml数据)
      etree.HTML(html数据)
    from lxml import etree
    with open('../file/data.xml', encoding='utf-8') as f:
        root = etree.XML(f.read())
    
    • 1
    • 2
    • 3
    1. 根据xpath获取指定标签
      节点对象.xpath(路径) - 返回路径对应的所有的标签,返回值是列表,列表中的元素是标签对象(节点对象)

      路径的写法

      • 绝对路径: 用"/"开头的路径 - /标签在树结构中的路径 (路径必须从根节点开始写)
      • 相对路径: 路径开头用"."标签当前节点(xpath前面是谁,'.'就代表谁), "…"表示当前节点的上层节点
      • 全(任意)路径: 用"//"开头的路径 - 在整个树中获取标签

      注意:绝对路径和全路径的写法以及查找方式和是用谁去点的xpath无关

    # 绝对路径
    result = root.xpath('/supermarket/staffs/staff/name/text()')
    print(result)
    
    # 相对路径
    result = root.xpath('./staffs/staff/name/text()')
    print(result)
    
    staff1 = root.xpath('./staffs/staff')[0]            # 获取第一个员工对应的staff标签
    result = staff1.xpath('./name/text()')
    print(result)
    
    result = staff1.xpath('../staff/name/text()')
    print(result)
    
    # 全(任意)路径
    result = root.xpath('//name/text()')
    print(result)
    
    result = staff1.xpath('//goods/name/text()')
    print(result)
    
    # 运行结果
    '''
    ['小明', '小花', '张三', '李四', '王五']
    ['小明', '小花', '张三', '李四', '王五']
    ['小明']
    ['小明', '小花', '张三', '李四', '王五']
    ['小明', '小花', '张三', '李四', '王五', '泡面', '火腿肠', '矿泉水', '面包']
    ['泡面', '火腿肠', '矿泉水', '面包']
    '''
    
    • 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
    1. 获取标签内容
      节点对象.xpath(获取标签的路径/text()) - 获取指定路径下所有标签的标签内容
    result = root.xpath('//position/text()')
    print(result)
    
    # 运行结果
    '''
    ['收营员', '促销员', '保洁', '收营员', '售货员']
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 获取标签属性
      节点对象.xpath(获取标签的路径/@属性名)
    result = root.xpath('/supermarket/@name')
    print(result)
    
    result = root.xpath('//staff/@id')
    print(result)
    
    # 运行结果
    '''
    ['永辉超市']
    ['s001', 's002', 's003', 's004', 's005']
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 谓语(条件)
    # 1) 位置相关谓语
    # [m] - 第m个
    result = root.xpath('//staff[1]/name/text()')
    print(result)
    # [last()] - 最后第一个
    # [last()-m] - 第n-m个/倒数第m+1个
    # [position()m]、[position()<=m]、[position()>=m]
    # 前m-1个、后n-m个、前m个、后n-m+1个
    
    
    # 2) 属性相关谓语
    # [@属性名=属性值] - 获取指定属性是指定值的标签
    result = root.xpath('//staff[@class="c1"]/name/text()')
    print(result)
    
    # [@属性名]
    result = root.xpath('//goods[@discount]/name/text()')
    print(result)
    
    
    # 3) 子标签内容相关谓语 - 根据子标签的内容来筛选标签
    # [子标签<数据]、[子标签>数据]、[子标签<=数据]、[子标签>=数据]、[子标签=数据]
    result = root.xpath('//goods[price=2]/name/text()')
    print(result)
    
    # 运行结果
    '''
    ['小明']
    ['小明', '李四']
    ['泡面', '面包']
    ['矿泉水']
    '''
    
    • 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
    • 32
    1. 通配符
    # 写路径的时候,用*来表示任意标签或任意属性
    result = root.xpath('//staff[1]/*/text()')
    print(result)
    
    result = root.xpath('//*[@class="c1"]/name/text()')
    print(result)
    
    result = root.xpath('//goods[@*]/name/text()')
    print(result)
    
    # 运行结果
    '''
    ['小明', '收营员', '4000']
    ['小明', '李四', '火腿肠']
    ['泡面', '火腿肠', '面包']
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1. 若干
    # 路径1|路径2|。。。 - 获取所有路径的内容
    result = root.xpath('//goods/name/text()|//staff/position/text()')
    print(result)
    
    # 运行结果
    '''
    ['收营员', '促销员', '保洁', '收营员', '售货员', '泡面', '火腿肠', '矿泉水', '面包']
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2. 多线程

    2.1 基本理论

    1. 进程和线程

      • 进程: 一个正在运行的应用程序就是一个进程,每个进程均运行在其专门且受保护的内存空间中
      • 线程: 线程是进程执行任务的基本单元(一个进程中的任务都是在线程中执行的)

      进程就是车间,线程就是车间里面的工人。
      一个进程中默认有一个线程,这个线程叫主线程。

    2. 线程的特点
      如果在一个线程中执行多个任务,任务是串行执行的。
      (当一个程序中有很多个任务的时候,如果只有一个线程,那么程序的执行效率会很低)

    3. 多线程
      一个进程中有多个线程就是多线程。
      多线程执行任务的时候,多个任务可以同时(并行)执行。

    4. 多线程原理
      一个cpu同一时间只能调度一个线程,多线程其实是cpu快速的在多个线程之间进行切换,造成多个线程同时执行的假象。
      (提高cpu利用率)

    2.2 Python使用多线程的方法

    1. 一般使用方法
      多个线程可以通过循环来创建
    from threading import Thread
    from time import sleep
    from datetime import datetime
    
    def download(name):
        print(f'{name}开始下载:{datetime.now()}')
        sleep(2)
        print(f'{name}下载结束:{datetime.now()}')
    
    
    def main():
        # 1)创建线程对象
        """
        线程对象 = Thread(target=函数, args=元组)
        a.函数  - 可以是普通函数函数名,也可以是匿名函数。这个函数就是需要子线程中执行的任务。
        b.元组  - 元组中的元素就是在子线程中调用target对应的函数的时候需要的参数
        """
        time1 = datetime.now()
        t1 = Thread(target=download, args=('肖生克救赎',))
        t2 = Thread(target=download, args=('霸王别姬',))
        t3 = Thread(target=download, args=('阿甘正传',))
    
        # 2)启动线程 - 让子线程调用对应的函数
        t1.start()
        t2.start()
        t3.start()
        time2 = datetime.now()
        print(time2-time1)
    
    
    if __name__ == '__main__':
        main()
    
    # 运行结果
    '''
    肖生克救赎开始下载:2022-08-20 10:05:23.121123
    霸王别姬开始下载:2022-08-20 10:05:23.125239
    阿甘正传开始下载:2022-08-20 10:05:23.126225
    0:00:00.006098
    肖生克救赎下载结束:2022-08-20 10:05:25.137502阿甘正传下载结束:2022-08-20 10:05:25.137502 霸王别姬下载结束:2022-08-20 10:05:25.137502
    '''
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    1. 线程等待(阻塞)
      上面的程序存在一个明显的问题,那就是主线程提前结束,而子线程还在运行,为避免这种情况一般会加入线程等待(阻塞)
    # 在main()中加入线程阻塞
    def main():
    
        time1 = datetime.now()
        t1 = Thread(target=download, args=('肖生克救赎',))
        t2 = Thread(target=download, args=('霸王别姬',))
        t3 = Thread(target=download, args=('阿甘正传',))
    
        t1.start()
        t2.start()
        t3.start()
    
        # 3) 加入线程阻塞
        t1.join()
        t2.join()
        t3.join()
    
        time2 = datetime.now()
        print(time2-time1)
    
    # 运行结果
    '''
    肖生克救赎开始下载:2022-08-20 10:11:27.210833
    霸王别姬开始下载:2022-08-20 10:11:27.213781
    阿甘正传开始下载:2022-08-20 10:11:27.213781
    霸王别姬下载结束:2022-08-20 10:11:29.214501
    肖生克救赎下载结束:2022-08-20 10:11:29.222479
    阿甘正传下载结束:2022-08-20 10:11:29.229458
    0:00:02.019667
    '''
    
    • 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

    3. 线程池

    • 管理多个线程的工具
    • 线程池工作原理:先创建指定个数的线程,然后添加多个任务(任务数量>线程数量),让线程池中的线程去执行添加的所有任务(线程池中的每个线程可能会执行多个任务)
    1. submit()
      一次添加一个任务:submit(函数, 实参1, , 实参2, 实参3, ...)
      注意:实参的数量由前面的函数在调用的时候需要的实参来决定

    2. map()
      同时添加多个任务: map(函数, 参数对应的序列)
      注意:使用map添加多个任务的时候,任务对应的函数必须是有且只有一个参数的函数

    3. 关闭线程池
      线程池关闭后无法再添加新的任务,并且会阻塞当前线程等待整个线程池的任务都完成
      shutdown()

    from time import sleep
    from datetime import datetime
    from random import randint
    from concurrent.futures import ThreadPoolExecutor
    
    
    def download(name):
        print(f'{name}开始下载:{datetime.now()}')
        sleep(randint(2, 7))
        print(f'{name}下载结束:{datetime.now()}')
    
    
    def main():
        # 使用线程池下载1000个电影
        # ThreadPoolExecutor(线程数最大值)
        pool = ThreadPoolExecutor(3)
    
        pool.submit(download, '肖生克的救赎')
        pool.submit(download, '霸王别姬')
    
        pool.map(download, ['V字仇杀队', '恐怖游轮', '沉默的羔羊'])
    
        pool.shutdown()
        print('==============完成!=============')
    
    
    if __name__ == '__main__':
        main()
    
    # 运行结果
    '''
    肖生克的救赎开始下载:2022-08-20 10:22:28.727568
    霸王别姬开始下载:2022-08-20 10:22:28.735995
    V字仇杀队开始下载:2022-08-20 10:22:28.736993
    肖生克的救赎下载结束:2022-08-20 10:22:30.738571
    恐怖游轮开始下载:2022-08-20 10:22:30.738571
    霸王别姬下载结束:2022-08-20 10:22:32.747770
    沉默的羔羊开始下载:2022-08-20 10:22:32.754632
    V字仇杀队下载结束:2022-08-20 10:22:33.741739
    恐怖游轮下载结束:2022-08-20 10:22:34.747225
    沉默的羔羊下载结束:2022-08-20 10:22:35.759421
    ==============完成!=============
    '''
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    通过with操作来自动关闭多线程

    def main():
        # 使用线程池下载1000个电影
        # ThreadPoolExecutor(线程数最大值)
        movies = ['肖生克的救赎', '霸王别姬', 'V字仇杀队', '恐怖游轮', '沉默的羔羊']
        with ThreadPoolExecutor(max_workers=3) as pool:
            for i in movies:
                pool.submit(download, i)
    
        print('==============完成!=============')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4. 常用的指令

    常见的指令操作

    执行指令的工具: Windows - 命令提示符(cmd) 、Mac - 终端

    1. 运行python程序: - 运算程序的计算机必须先安装python环境
    # win
    python py文件路径
      
    # mac:  
    python3 py文件路径     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 进入文件夹: cd
    # 注意:如果是windows操作系统,cd操作如果要跨盘需要先切盘,然后再cd
    # 切盘方法:
    D:
    cd  文件夹相对路径、文件夹绝对路径
    
    • 1
    • 2
    • 3
    • 4
    1. 查看当前文件夹的内容
    # win:  
    dir
    
    # Mac:
    ls
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 用指令创建虚拟环境

      • 第一步:找到一个用来放虚拟环境的文件夹

      • 第二步:通过cd指令进入到存放虚拟环境的文件夹中

      • 第三步:创建虚拟环境

      python -m venv 虚拟环境名
      python3 -m venv 虚拟环境名
      
      • 1
      • 2
      • 第四步:激活虚拟环境
      (mac) source  虚拟环境目录/bin/activate
      (windows)  虚拟环境目录\Scripts\activate.bat
      cmd要写绝对路径,否则会报错,power shell可以写相对路径
      
      • 1
      • 2
      • 3
      • 第五步:退出虚拟环境
      deactivate
      
      • 1
    2. 常用pip指令(pip - Python包管理工具)

    	pip list		-		查看当前环境已经安装过的所有的第三方库
    	 
        pip install  第三方库名称		-		下载并且安装指定的第三方库
    	pip install  第三方库名称 -i 镜像地址		-		在指定的镜像地址中下载安装
    	pip install  第三方库名称==版本号	-i   镜像地址
    	
    	pip install  第三方库名称1   第三方库名称2  
    
    	pip freeze > 依赖文件名  	-	生成依赖文件	
    	pip install -r 依赖文件路径			-		批量安装	
    
    	pip uninstall 第三方库名称   -  卸载指定的第三方库
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    【飞桨PaddleSpeech语音技术课程】— 语音识别-流式服务
    【藏经阁一起读】(70)__《看见新力量(第七期)》
    Python中的单元测试与代码覆盖率:实践与问题解决
    Python升级之路( Lv13 ) pyinstaller 使用详解
    带符号整数的除法与余数
    scrollIntoView多重校验rules滚动到指定位置
    1990-2022上市公司董监高学历工资特征信息数据/上市公司高管信息数据
    测试人经验谈:需求不明确也能写出测试用例
    17.C++常用的算法_集合算法
    kotlin语法快速入门-接口与接口实现(8)
  • 原文地址:https://blog.csdn.net/ChenAi_140/article/details/126437022