• Python练习之使用XPath获取豆瓣电影排行榜


      之前我们学习了XPath的简单使用,参考:https://www.cnblogs.com/minseo/p/15502584.html

      今天我们来练习XPath的使用,使用XPath分析豆瓣电影排行榜,本次我们练习获取电影排行榜的新片榜信息,练习获取的内容是新片的url,影片名称,导演名

      为了便于查看XPath分析html的整个过程我们把网页的源码下载下来,使用文本编辑器Notepad++打开,该文本编辑器可以清楚的查看标签的对应关系。

      首先我们来查找10部新片的url

      查看源码发现豆瓣新片榜包含在一个标签<div>内该标签有一个唯一识别的id=“conetent”

       使用XPath查找这个标签

    # 爬取豆瓣电影排行榜的新片帮,使用同步方法
    # 导入模块
    import requests
    from lxml import etree
    # 设置访问客户端头部信息,不设置可能无法使用requests访问
    headers = {'User-Agent': 'M'}
    movice_url = 'https://movie.douban.com/chart'
    resp = requests.get(movice_url,headers=headers)
    # 获取响应的所有源码信息
    movice_resp_text = resp.text
    # 使用etree.HTML转换成可以使用xpath分析的lxml.etree._Element对象
    movice_etree_element = etree.HTML(movice_resp_text)
    movice_url = movice_etree_element.xpath('//*[@id="content"]')
    print(movice_url)
    

      XPath代码解析

    xpath('//*[@id="content"]')
    // # 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
    * # 通配符匹配所有
    [@id="content"] # 匹配标签属性,本次这个id属性是唯一的所以可以匹配到一个唯一的标签
    

      注意:匹配代码如果有多个引号则内部和外部不能使用相同的引号符号,即外部使用单引号则内部需要使用双引号,反之亦然

      本次查找到一个对象输出如下

    [<Element div at 0x134e93395c8>]
    

      如果不确定是否查到的是这个标签,可以打印标签的关键属性查看

      打印id属性可以看到确实是对应的标签

    movice_url = movice_etree_element.xpath('//*[@id="content"]/@id')
    print(movice_url)
    # ['content']
    

      下面缩小范围继续查找,在上一步查找到的标签下继续查找<div>标签

    movice_url = movice_etree_element.xpath('//*[@id="content"]/div')
    print(movice_url)
    # [<Element div at 0x1f2b3248688>]
    

      又找到唯一一个,打印标签的class属性看一下找到的是哪个标签

    movice_url = movice_etree_element.xpath('//*[@id="content"]/div/@class')
    print(movice_url)
    # ['grid-16-8 clearfix']
    

      可以看到找到的是源码里面对应的下面这个标签

       很明显还没有找到对应的电影url

      下面缩小范围继续查找

    movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div')
    print(movice_url)
    # [<Element div at 0x288c4f18508>, <Element div at 0x288c4f18548>, <Element div at 0x288c4f18488>]
    

      在找到的上一个标签<div>下找到3个<div>标签,下面我们还是通过属性来确定新片在这三个标签中的哪一个标签

    movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div')
    print(movice_url[0].xpath('@class'),movice_url[1].xpath('@class'),movice_url[2].xpath('@class'))
    # ['article'] ['aside'] ['extra']
    

      通过取列表的元素再使用xpath方法去查找属性class的值来确定3个标签的位置

      关键关键字在源码中查找这三个标签的位置

     

     

       很明显我们要找的电影url在第一个标签内

      缩小范围继续查找,查找第一个标签

    movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div[1]')
    print(movice_url)
    # print(movice_url)
    [<Element div at 0x23daef97788>]

      注意:这里第一个标签的下标是1而不是像python其他对象比如list的第一个标签是0

      这次又返回一个对象

      下面继续查找下一个div标签打印属性class

    movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div[1]/div/@class')
    print(movice_url)
    # ['indent']
    

      又找到唯一一个<div>标签,在源码里如下位置

       缩小范围继续查找

    movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div[1]/div/div')
    print(movice_url)
    # [<Element div at 0x2d9b21186c8>]
    

      又只有一个,新片还在这个标签范围内

      缩小范围继续查,因为这个标签下面是table标签使用我们使用table标签查找

    movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div[1]/div/div/table')
    print(movice_url)
    # [<Element table at 0x1bedccf8608>, <Element table at 0x1bedccf8588>, <Element table at 0x1bedccf85c8>, <Element table at 0x1bedccf8508>, <Element table at 0x1bedccf8188>, <Element table at 0x1bedccf8148>, <Element table at 0x1bedccf8108>, <Element table at 0x1bedccf8048>, <Element table at 0x1bedccf8088>, <Element table at 0x1bedccf8208>]
    

      在这个<div>标签下包含了10个table标签,很明显新片10部电影的信息在这10个table内

      缩小范围继续查找这10部电影对应的url下面查找tr标签

    movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div[1]/div/div/table/tr')
    print(movice_url)
    # [<Element tr at 0x2135c038648>, <Element tr at 0x2135c0385c8>, <Element tr at 0x2135c038608>, <Element tr at 0x2135c038548>, <Element tr at 0x2135c0381c8>, <Element tr at 0x2135c038188>, <Element tr at 0x2135c038148>, <Element tr at 0x2135c038088>, <Element tr at 0x2135c0380c8>, <Element tr at 0x2135c038248>]
    

      还是10个对象,代表10部电影的内容都在这10行内

      缩小范围继续查找

    movice_etree_element = etree.HTML(movice_resp_text)
    movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div[1]/div/div/table/tr/td')
    print(movice_url)
    

      这次返回了20个对象即20个td即每行有2列,我们取需要的列即第一列

    movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div[1]/div/div/table/tr/td[1]')
    print(movice_url)
    

      又返回10个列标签,我们需要是url信息就在这10个列内  

      是以下源码对应的列,一共10个只截取出一个展示

       缩小范围继续查找这次我们找<a>标签

    movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div[1]/div/div/table/tr/td[1]/a')
    print(movice_url)
    

      没有问题还是返回10个对应的<a>标签,即源码对应的

       下面去这个标签是href属性值就把10部电影的url取出来了

    movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div[1]/div/div/table/tr/td[1]/a/@href')
    print(movice_url)
    # ['https://movie.douban.com/subject/3001114/', 'https://movie.douban.com/subject/33457594/', 'https://movie.douban.com/subject/34820925/', 'https://movie.douban.com/subject/35235502/', 'https://movie.douban.com/subject/1428581/', 'https://movie.douban.com/subject/34626280/', 'https://movie.douban.com/subject/35158124/', 'https://movie.douban.com/subject/34874432/', 'https://movie.douban.com/subject/35115642/', 'https://movie.douban.com/subject/32568661/']
    

      根据取得的url取其中一个url分析取得这部电影的电影名和导演名

      原理和上述是一样的,关键是从源码中找出对应的信息

    # 设置访问客户端头部信息,不设置可能无法使用requests访问
    headers = {'User-Agent': 'M'}
    movice_url = 'https://movie.douban.com/subject/3001114/'
    resp = requests.get(movice_url,headers=headers)
    # 获取响应的所有源码信息
    movice_resp_text = resp.text
    # 使用etree.HTML转换成可以使用xpath分析的lxml.etree._Element对象
    movice_etree_element = etree.HTML(movice_resp_text)
    movice_name = movice_etree_element.xpath('//*[@id="content"]/h1/span[1]/text()')
    movice_author = movice_etree_element.xpath('//*[@id="info"]/span[1]/span[2]/a/text()')
    print(movice_name,movice_author)
    # ['沙丘 Dune'] ['丹尼斯·维伦纽瓦']
    

      下面把以上代码修改成函数然后获取10部新片的信息,并查看执行的时间

      d:/learn-python3/学习脚本/aiohttp/get_movice_use_sync.py

    # 爬取豆瓣电影排行榜的新片帮,使用同步方法
    # 导入模块
    import requests
    from lxml import etree
    import time
    def get_movice_url():
        # 设置访问客户端头部信息,不设置可能无法使用requests访问
        headers = {'User-Agent': 'M'}
        movice_url = 'https://movie.douban.com/chart'
        resp = requests.get(movice_url,headers=headers)
        # 获取响应的所有源码信息
        movice_resp_text = resp.text
        # 使用etree.HTML转换成可以使用xpath分析的lxml.etree._Element对象
        movice_etree_element = etree.HTML(movice_resp_text)
        # 获取10部电影的url返回一个list元素为10部电影url
        movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div[1]/div/div/table/tr/td[1]/a/@href')
        
        return movice_url
    
    def get_movice_info():
        movice_url = get_movice_url()
        # print(movice_url)
        # 设置访问客户端头部信息,不设置可能无法使用requests访问
        headers = {'User-Agent': 'M'}
        # 定义空字典用于接收影片信息
        movice_info = {}
        # 把获取到的电影url遍历出影片名称和导演
        for url in movice_url:    
            resp = requests.get(url,headers=headers)
            # 获取响应的所有源码信息
            movice_resp_text = resp.text
            # 使用etree.HTML转换成可以使用xpath分析的lxml.etree._Element对象
            movice_etree_element = etree.HTML(movice_resp_text)
            # 获取影片的名称和导演
            movice_name = movice_etree_element.xpath('//*[@id="content"]/h1/span[1]/text()')
            movice_author = movice_etree_element.xpath('//*[@id="info"]/span[1]/span[2]/a/text()')
            # 把获取到的影片名称和导演作为一个value赋值给字典,字典key为影片url
            movice_info[url] = {'name':movice_name,'author':movice_author}
        return movice_info
    
    if __name__ == '__main__':
        start_time = time.time()
        movice_info = get_movice_info()
        print(movice_info)
        end_time = time.time()
        print(end_time-start_time)
    

      输出如下,返回字典包含了影片的url,影片名称和导演名,执行时间为8秒多

    {'https://movie.douban.com/subject/3001114/': {'name': ['沙丘 Dune'], 'author': ['丹尼斯·维伦纽瓦']}, 'https://movie.douban.com/subject/33457594/': {'name': ['摩加迪
    沙 모가디슈'], 'author': ['柳昇完']}, 'https://movie.douban.com/subject/34820925/': {'name': ['钛 Titane'], 'author': ['朱利亚·迪库诺']}, 'https://movie.douban.com/subject/35235502/': {'name': ['驾驶我的车 ドライブ・マイ・カー'], 'author': ['滨口龙介']}, 'https://movie.douban.com/subject/1428581/': {'name': ['天书奇谭'], 'author': ['王树忱', '钱运达']}, 'https://movie.douban.com/subject/34626280/': {'name': ['月光光心慌慌:杀戮 Halloween Kills'], 'author': ['大卫·戈登·格林']}, 'https://movie.douban.com/subject/35158124/': {'name': ['盛夏未来'], 'author': ['陈正道']}, 'https://movie.douban.com/subject/34874432/': {'name': ['花束般的恋爱 花束みたいな恋をした
    '], 'author': ['土井裕泰']}, 'https://movie.douban.com/subject/35115642/': {'name': ['平行森林'], 'author': ['郑雷']}, 'https://movie.douban.com/subject/32568661/': {'name': ['妈妈的神奇小子 媽媽的神奇小子'], 'author': ['尹志文']}}
    8.593812465667725
    

      下面结合aiohttp和asyncio使用异步方法执行同样的操作

      get_movice_use_async.py

    # 爬取豆瓣电影排行榜的新片帮,使用异步方法
    # 导入模块
    import requests
    from lxml import etree
    import time
    import asyncio
    import aiohttp
    async def get_movice_url():
        # 设置访问客户端头部信息,不设置可能无法使用requests访问
        headers = {'User-Agent': 'M'}
        movice_url = 'https://movie.douban.com/chart'
        async with aiohttp.ClientSession() as session:
            async with session.get(movice_url,headers=headers) as resp:
                # print(resp.status)
                # 获取响应的所有源码信息
                movice_resp_text = await resp.text()
                # 使用etree.HTML转换成可以使用xpath分析的lxml.etree._Element对象
                movice_etree_element = etree.HTML(movice_resp_text)
                # 获取10部电影的url返回一个list元素为10部电影url
                movice_url = movice_etree_element.xpath('//*[@id="content"]/div/div[1]/div/div/table/tr/td[1]/a/@href')
                return movice_url
    
    
    async def get_movice_info(url):
        # 设置访问客户端头部信息,不设置可能无法使用requests访问
        headers = {'User-Agent': 'M'}
        # 把获取到的电影url遍历出影片名称和导演
        async with aiohttp.ClientSession() as session:
            async with session.get(url,headers=headers) as resp:        
                # 获取响应的所有源码信息
                movice_resp_text = await resp.text()
                # 使用etree.HTML转换成可以使用xpath分析的lxml.etree._Element对象
                movice_etree_element = etree.HTML(movice_resp_text)
                # 取影片的名称和导演
                movice_name = movice_etree_element.xpath('//*[@id="content"]/h1/span[1]/text()')
                movice_author = movice_etree_element.xpath('//*[@id="info"]/span[1]/span[2]/a/text()')
        # 把获取到的影片名称和导演作为一个value赋值给字典,字典key为影片url
        return {url:{'name':movice_name,'author':movice_author}}
    
    # 定义主执行协程函数main
    async def main():
        # 首先调用协程函数获取影片url,返回一个list 元素为影片url
        movice_url = await get_movice_url()
        # 创建tasks把10部影片url作为参数传递给协程函数get_movice_info来获取影片名称和导演信息
        tasks = [get_movice_info(url) for url in movice_url]
        # 使用asyncio.gather方法运行,10个请求是同时运行的,按顺序返回结果
        movice_info = await asyncio.gather(*tasks)
        print(movice_info)
    
    # 执行并计算执行耗时
    if __name__ == '__main__':
        start_time = time.time()
        asyncio.run(main())
        end_time = time.time()
        print(end_time-start_time)
    

      输出如下

    [{'https://movie.douban.com/subject/3001114/': {'name': ['沙丘 Dune'], 'author': ['丹尼斯·维伦纽瓦']}}, {'https://movie.douban.com/subject/33457594/': {'name': ['摩加
    迪沙 모가디슈'], 'author': ['柳昇完']}}, {'https://movie.douban.com/subject/34820925/': {'name': ['钛 Titane'], 'author': ['朱利亚·迪库诺']}}, {'https://movie.douban.com/subject/35235502/': {'name': ['驾驶我的车 ドライブ・マイ・カー'], 'author': ['滨口龙介']}}, {'https://movie.douban.com/subject/1428581/': {'name': ['天书奇谭'], 'author': ['王树忱', '钱运达']}}, {'https://movie.douban.com/subject/34626280/': {'name': ['月光光心慌慌:杀戮 Halloween Kills'], 'author': ['大卫·戈登·格林']}}, {'https://movie.douban.com/subject/35158124/': {'name': ['盛夏未来'], 'author': ['陈正道']}}, {'https://movie.douban.com/subject/34874432/': {'name': ['花束般的恋爱 花束み
    たいな恋をした'], 'author': ['土井裕泰']}}, {'https://movie.douban.com/subject/35115642/': {'name': ['平行森林'], 'author': ['郑雷']}}, {'https://movie.douban.com/subject/32568661/': {'name': ['妈妈的神奇小子 媽媽的神奇小子'], 'author': ['尹志文']}}]
    1.7407007217407227
    

      可以看到执行相同的任务异步耗时比同步耗时省很多

      

      

  • 相关阅读:
    Arrays工具类、二维数组
    Idea软件的使用
    循环语句
    方法
    objective-C 2.0
    Unix系统常用命令
    文献管理工具Zotero
    如何降低论文重复率
    SQL易忽视的细节
    数据库系统原理学习资源
  • 原文地址:https://www.cnblogs.com/minseo/p/15508529.html
Copyright © 2020-2023  润新知