爬虫 — Xpath 数据解析

目录

  • 一、介绍
  • 二、使用
  • 三、语法
    • 1、//
    • 2、/
    • 3、@
    • 4、/text
    • 5、[]、[@]
  • 四、练习
    • 1、元组写入
    • 2、对象写入
  • 五、豆瓣电影信息爬取

一、介绍

XPath(XML Path Language)是一种 XML 的查询语言,它能在 XML 树状结构中寻找节点。XPath 用于在 XML 文档中通过元素和属性进行导航

XML 是一种标记语法的文本格式,XPath 可以方便的定位 XML 中的元素和其中的属性值。

lxml 是 Python 中的一个第三方模块,包含了将 HTML 文本转换成 XML 对象和对对象执行 XPath 的功能。

二、使用

1、在终端输入命令:pip install lxml

2、导入:from lxml import etree

3、创建对象:tree = etree.HTML(网页源代码)

4、tree.xpath(XPath 语法)

三、语法

表达式 描述
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
/ 从根节点选取,选择当前元素的下一级
@ 选取属性
/text 当前元素的文本内容
[]、[@] 指定元素的索引或者属性特性

网页数据

html = '''
  • 1 肖申克的救赎

    导演: 弗兰克·德拉邦特 Frank Darabont   主演: 蒂姆·罗宾斯 Tim Robbins /...
    1994 / 美国 / 犯罪 剧情

    9.7 2833257人评价

    希望让人自由。

  • '''
    # 创建对象,参数是指网页源码
    tree = etree.HTML(html)
    

    1、//

    从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。

    # //:不需要考虑标签位置,直接定位
    # 获取 span 标签
    span = tree.xpath('//span')  # 返回的是列表,查找所有的 span 标签,并存放到列表当中
    print(span)
    # 返回值
    # [, , , , , , , , ]
    
    # 获取 img 标签
    img = tree.xpath('//img')
    print(img)
    # 返回值
    # []
    

    2、/

    从根节点选取,选择当前元素的下一级。

    # /:从根节点选取,选择当前元素的下一级
    # 获取 p 标签下的 span 标签
    span = tree.xpath('//p/span')
    print(span)
    # 返回值
    # []
    

    3、@

    选取属性。

    # @:选取属性
    # 获取 img 标签的 src 属性值
    img_url = tree.xpath('//img/@src')
    print(img_url)
    # 返回值
    # ['https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp']
    
    # 获取 img 标签的 alt 属性值
    img_title = tree.xpath('//img/@alt')
    print(img_title)
    # 返回值
    # ['肖申克的救赎']
    

    4、/text

    当前元素的文本内容。

    # 获取标签里面的文本内容
    rank = tree.xpath('//em/text()')
    print(rank)
    # 返回值
    # ['1']
    
    # 获取 class 为 rating_num 标签的内容
    span = tree.xpath('//span[@class="rating_num"]/text()')
    print(span)
    # 返回值
    # ['9.7']
    

    5、[]、[@]

    指定元素的索引或者属性特性。

    title = tree.xpath('//div[@class="hd"]/a/span[3]/text()')
    print(title)
    # 返回值
    # ['\xa0/\xa0月黑高飞(港)  /  刺激1995(台)']
    

    四、练习

    1、元组写入

    # 导入模块
    import csv
    from lxml import etree
    
    # 数据
    wb_data = """
            
            """
    
    # 创建对象
    html = etree.HTML(wb_data)
    
    # 找到所有的标签,并且存放在列表当中
    lis = html.xpath('//li')
    
    # 创建列表
    lst = []
    
    # 循环获取 li
    for li in lis:
        # 链接
        href = li.xpath('./a/@href')[0]  # .代表当前节点的下一级
        # 标题
        texts = li.xpath('./a/text()')[0]
        # 创建元组数据
        tu = (href, texts)
        # 在列表里添加元组数据
        lst.append(tu)
    # 打印列表
    print(lst)
    
    # 创建表头
    head = ('链接', '值')
    
    # 创建文件对象
    with open('data1.csv', 'w', encoding='utf-8-sig', newline='') as f:
        # 创建 csv 写入对象
        writer = csv.writer(f)
        # 写入表头
        writer.writerow(head)
        # 写入数据
        writer.writerows(lst)
    

    2、对象写入

    # 导入模块
    import csv
    from lxml import etree
    
    # 数据
    wb_data = """
            
            """
    
    # 创建对象
    html = etree.HTML(wb_data)
    
    # 找到所有的标签,并且存放在列表当中
    lis = html.xpath('//li')
    
    # 创建列表
    lst = []
    
    # 循环获取 li
    for li in lis:
        # 创建字典对象
        dic = {}
        dic['href'] = li.xpath('./a/@href')[0]  # .代表当前节点的下一级
        dic['texts'] = li.xpath('./a/text()')[0]
        lst.append(dic)
    
    # 打印列表
    print(lst)
    
    # 创建表头,key 必须要跟表头保持一致
    head = ('href', 'texts')
    
    # 创建文件对象
    with open('data2.csv', 'w', encoding='utf-8-sig', newline='') as f:
        # 创建 csv 字典写入对象  fieldnames 固定参数,不可修改
        writer = csv.DictWriter(f, fieldnames=head)  # 设置表头
        # 写入表头
        writer.writeheader()
        # 写入数据
        writer.writerows(lst)
    

    元组写入和对象写入区别:

    元组写入:可以自定义表头文字。

    对象写入:表头数据必须与对象 key 值保持一致。

    五、豆瓣电影信息爬取

    目标网站:https://movie.douban.com/top250

    需求:获取该网站所有的电影(包括翻页)标题,副标题,电影类型,评分,引言并将数据保存到 csv 表格当中。

    页面分析

    翻页爬取:先获取第一页数据

    1、确定 url:https://movie.douban.com/top250

    2、发请求,获取响应:返回网页源代码 — XPath 解析

    3、每一组数据

    包含了所需的数据

    4、遍历拿详情的数据

    电影名称:div[@class=“hd”]/a//text() a 标签下的子孙文本都能获取到

    电影类型:div[@class=“bd”]/p/text() 获取到文本内容之后还需要处理

    电影评分:div[@class=“bd”]/div[@class=“star”]/span[2]/text()

    电影引言:div[@class=“bd”]/p[@class=“quote”]/span/text()

    代码实现

    # 导入模块
    import requests
    from lxml import etree
    
    # 第一页目标 url
    url = "https://movie.douban.com/top250"
    
    # 请求头
    head = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36'
    }
    
    # 发请求,获取响应
    res = requests.get(url, headers=head)
    
    # 创建对象
    html = etree.HTML(res.text)
    
    # 数据解析
    divs = html.xpath('//div[@class="info"]')
    
    # 循环遍历拿到每一组数据
    for div in divs:  # 每一组数据的获取
        # 标题
        title = div.xpath('./div[@class="hd"]/a//text()')
        titls = ''.join(title).replace(' ', '').replace('\n', '')
        # 电影类型
        types = div.xpath('./div[@class="bd"]/p/text()')[1].split('/')[-1].strip()
        # 电影评分
        star = div.xpath('./div[@class="bd"]/div[@class="star"]/span[2]/text()')[0]
        # 引言,没有获取到数据,返回是一个空列表
        quote = div.xpath('./div[@class="bd"]/p[@class="quote"]/span/text()')
        # 打印标题,电影类型,电影评分,引言
        print(titls, types, star, quote)
    

    页面分析

    翻页

    第一页:https://movie.douban.com/top250?start=0&filter=

    第二页:https://movie.douban.com/top250?start=25&filter=

    第三页:https://movie.douban.com/top250?start=50&filter=

    start 参数发生变化

    第一页:(1-1)* 25 = 0

    第二页:(2-1)* 25 = 25

    第三页:(3-1)* 25 = 50

    第 n 页:(n-1)* 25

    page:(page-1) * 25

    f’https://movie.douban.com/top250?start={(page-1) * 25}&filter=’

    代码实现

    # 导入模块
    import requests
    from lxml import etree
    
    # 请求头
    head = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36'
    }
    
    # 翻页
    for page in range(1, 11):
        # 目标 url
        url = f'https://movie.douban.com/top250?start={(page-1) * 25}&filter='
    
        # 发请求,获取响应
        res = requests.get(url, headers=head)
    
        # 创建对象
        html = etree.HTML(res.text)
    
        # 数据解析
        divs = html.xpath('//div[@class="info"]')
    
        # 循环遍历拿到每一组数据
        for div in divs:  # 每一组数据的获取
            # 标题
            title = div.xpath('./div[@class="hd"]/a//text()')
            titls = ''.join(title).replace(' ', '').replace('\n', '')
            # 电影类型
            types = div.xpath('./div[@class="bd"]/p/text()')[1].split('/')[-1].strip()
            # 电影评分
            star = div.xpath('./div[@class="bd"]/div[@class="star"]/span[2]/text()')[0]
            # 引言,没有获取到数据,返回是一个空列表
            quote = div.xpath('./div[@class="bd"]/p[@class="quote"]/span/text()')
            # 判断是否为空列表
            if quote: # 如果不是就直接取下标值
                quote = quote[0]
            else: # 如果是的,就赋值为空字符串
                quote = ''
            # 打印标题,电影类型,电影评分,引言
            print(titls, types, star, quote)
    

    页面分析

    数据已经全部取出

    使用 csv 保存数据到表格

    代码实现

    1、元组写入

    # 导入模块
    import requests
    from lxml import etree
    import csv
    
    # 请求头
    head = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36'
    }
    
    # 数据列表
    lst = []
    
    # 翻页
    for page in range(1, 11):
        # 目标 url
        url = f'https://movie.douban.com/top250?start={(page-1) * 25}&filter='
    
        # 发请求,获取响应
        res = requests.get(url, headers=head)
    
        # 创建对象
        html = etree.HTML(res.text)
    
        # 数据解析
        divs = html.xpath('//div[@class="info"]')
    
        # 循环遍历拿到每一组数据
        for div in divs:  # 每一组数据的获取
            # 标题
            title = div.xpath('./div[@class="hd"]/a//text()')
            titls = ''.join(title).replace(' ', '').replace('\n', '')
            # 电影类型
            types = div.xpath('./div[@class="bd"]/p/text()')[1].split('/')[-1].strip()
            # 电影评分
            star = div.xpath('./div[@class="bd"]/div[@class="star"]/span[2]/text()')[0]
            # 引言,没有获取到数据,返回是一个空列表
            quote = div.xpath('./div[@class="bd"]/p[@class="quote"]/span/text()')
            # 判断是否为空列表
            if quote: # 如果不是就直接取下标值
                quote = quote[0]
            else: # 如果是的,就赋值为空字符串
                quote = ''
            # 标题,电影类型,电影评分,引言组成元组数据
            l = (titls, types, star, quote)
            # 在列表数据中增加元组数据
            lst.append(l)
    
    # 设置表头
    head = ('标题', '电影类型', '电影评分', '引言')
    
    # 创建文件对象
    with open('douban.csv','w',encoding='utf-8-sig',newline='') as f:
        # 创建 csv 写入对象
        writer = csv.writer(f)
        # 写入表头
        writer.writerow(head)
        # 写入数据
        writer.writerows(lst)
    

    2、对象写入

    # 导入模块
    import requests
    from lxml import etree
    import csv
    
    # 请求头
    head = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36'
    }
    
    # 数据列表
    lst = []
    
    # 翻页
    for page in range(1, 11):
        # 目标 url
        url = f'https://movie.douban.com/top250?start={(page-1) * 25}&filter='
    
        # 发请求,获取响应
        res = requests.get(url, headers=head)
    
        # 创建对象
        html = etree.HTML(res.text)
    
        # 数据解析
        divs = html.xpath('//div[@class="info"]')
    
        # 循环遍历拿到每一组数据
        for div in divs:  # 每一组数据的获取
            # 创建对象
            dic = {}
            # 标题
            title = div.xpath('./div[@class="hd"]/a//text()')
            dic['titls'] = ''.join(title).replace(' ', '').replace('\n', '')
            # 电影类型
            dic['types'] = div.xpath('./div[@class="bd"]/p/text()')[1].split('/')[-1].strip()
            # 电影评分
            dic['star'] = div.xpath('./div[@class="bd"]/div[@class="star"]/span[2]/text()')[0]
            # 引言,没有获取到数据,返回是一个空列表
            quote = div.xpath('./div[@class="bd"]/p[@class="quote"]/span/text()')
            # 判断是否为空列表
            if quote: # 如果不是就直接取下标值
                dic['quote'] = quote[0]
            else: # 如果是的,就赋值为空字符串
                dic['quote'] = ''
            # 在列表数据中增加对象数据
            lst.append(dic)
    
    # 设置表头,与对象中的 key 值相同
    head = ('titls', 'types', 'star', 'quote')
    
    # 创建文件对象
    with open('douban.csv','w',encoding='utf-8-sig',newline='') as f:
        # 创建 csv 写入对象
        writer = csv.DictWriter(f, fieldnames=head)
        # 写入表头
        writer.writeheader()
        # 写入数据
        writer.writerows(lst)
    

    记录学习过程,欢迎讨论交流,尊重原创,转载请注明出处~

    你可能感兴趣的:(爬虫,爬虫,python)