Python爬虫学习笔记-第七课(XPath相关知识点)

1. XPath介绍

1.1 基本概念

XPath(XML Path Language)是一种XML的查询语言,它能在XML树状结构中寻找节点。XPath用于在XML文档中通过元素和属性进行导航。
XML是一种标记语法的文本格式,XPath可以方便地定位XML中的元素和其中的属性值。lxml是Python中的一个第三方模块,它包含了将html文本转成xml对象,和对该对象执行xpath的功能。

1.2 举例

首先,正则表达式使用时先由用户指定模板,再根据模板匹配需要的数据。
假设有如下需求:寻找人才,要求是人品好、技术好、颜值高、不要工资。
对于正则表达式,如果给的模板比较严格(不要工资这一项,几乎没有人才能匹配上),或者模板本身很难编写,那么它的使用会受到很大的限制。
对于xpath,就好比有一位资深HR告诉你,xxx区xxx街道xxx楼可以找到所需要的人才。以上述需求为例,xpath是一种可以根据地址找人的技术。

1.3 节点关系

假设有如下XML文本:

xml_content = '''
<bookstore>
<book>
	<title lang='eng'>Harry Potter</title>
	<author>JK.Rowling</author>
	<year>2005</year>
	<price>29</price>
</book>
</bookstore>

上述文档中的节点例子:

<bookstore> (文档节点)
<author>JK.Rowling</author> (元素节点)
lang='eng' (属性节点)

1.4 XPath语法

符号含义
/从根节点选取
//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
.选取当前节点
..选取当前节点的父节点
@选取属性

表格中的语法在后续安装相应的工具给出示例。

2. xpath-helper工具的使用

2.1 安装xpath-helper

  • 点击扩展程序,跳转到chrome://extensions/

在这里插入图片描述

  • 打开开发者模式,点击加载已解压的扩展程序,安装包笔者自己已经准备好
    在这里插入图片描述
  • 安装成功后如图:
    在这里插入图片描述

2.2 使用xpath-helper

按住快捷键Ctrl+Shift+X,插件安装成功后会出现如下界面:
在这里插入图片描述
访问html根节点,整个html页面全部被匹配。
在这里插入图片描述
原本写到title,就能找到“百度一下,你就知道”的数据,但是编程时需要加上text()才能拿到文本数据。
在这里插入图片描述
练习使用//,不考虑具体位置,把符合条件的数据都找出来。
在这里插入图片描述
[] 谓语,用于查找某个特定的节点或者包含某个特定值的节点,谓语被嵌在[]中。
上述写法是有一定问题的,在这个例子中没有很好的体现。如果要找属性title的数据,应该这样写a/@title
在这里插入图片描述
...的使用,类似于dos命令cd ..表示进入上级目录,在XPath里面分别表示当前节点和当前节点的父节点。
在这里插入图片描述
在这里插入图片描述
继续练习[],在[1]填写数字类似于列表查找某个索引的值。
在这里插入图片描述
对应的网页源码如下:
在这里插入图片描述

[last()]查找最后一个元素的值:
在这里插入图片描述

[last()-1]查找倒数第二个元素的值:
在这里插入图片描述

[position()<3]查找前两个元素的值:
在这里插入图片描述

3. lxml模块入门

需求:给出自定义的一段HTML文本,用xpath解析出需要的数据,将其保存到一个csv文件。
示例代码:

from lxml import etree
import csv
# 自定义的HTML文本
wb_data = """
        <div>
            <ul>
                 <li class="item-0"><a href="link1.html">first item</a></li>
                 <li class="item-1"><a href="link2.html">second item</a></li>
                 <li class="item-inactive"><a href="link3.html">third item</a></li>
                 <li class="item-1"><a href="link4.html">fourth item</a></li>
                 <li class="item-0"><a href="link5.html">fifth item</a>
             </ul>
         </div>
        """
# 将HTML数据转化为xml对象
html_element = etree.HTML(wb_data)
print(html_element)
# href所对应的数据
links = html_element.xpath('//li/a/@href')
print('a href:', links)
# a标签所对应的文本数据
items = html_element.xpath('//li/a/text()')
print('a text:', items)
# 需求把打印出来的结果保存到一个字典当中 
# 例如 {'href':'link1.html','text':'first item'}
result_lst = []
for link in links:
    # 每次循环创建新的字典,字典中包含两个key-value
    d = {}
    d['href'] = link
    # links.index(link) 表示获取link在links中的索引
    # 若依次打印其结果为0,1,2,3,4
    d['text'] = items[links.index(link)]
    # 将创建的字典保存到列表中
    result_lst.append(d)
print(result_lst)
# 将上述列表中的数据写入到一个csv文件中
titles = ['href', 'text']
with open('exer.csv', 'w', encoding='utf-8', newline='') as fobj:
    # 创建writer对象, 第二个参数传递表头,对应数据的key
    writer_obj = csv.DictWriter(fobj, titles)
    # 写入表头
    writer_obj.writeheader()
    # 写入内容
    writer_obj.writerows(result_lst)

运行结果:
在这里插入图片描述
在这里插入图片描述

4. 案例演示

需求:爬取豆瓣top250电影的名字、评分、引言、以及详情页的地址,爬取10页,并将数据保存到csv文件中。

4.1 思路分析

  • 编写代码获取要爬取网页的URL:
# 第一页: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 = (page-1)*25
base_url = 'https://movie.douban.com/top250?start={}&filter='
start_page = int(input('请输入爬取网页的起始页:'))
end_page = int(input('请输入爬取网页的终止页:'))
for i in range(start_page, end_page+1):
    tar_url = base_url.format((i-1)*25)
    print(tar_url)

运行结果:
在这里插入图片描述

  • 编写代码获取网页源码文本数据:
import requests
tar_url = 'https://movie.douban.com/top250?start=0&filter='
req_headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 '
}
res_obj = requests.get(tar_url, headers=req_headers)
res_obj.encoding = 'utf-8'
source_text = res_obj.text
print(source_text)

运行结果:
在这里插入图片描述

  • 在网页源码中查找所需要的数据
source_text = '''
        <li>
            <div class="item">
                <div class="pic">
                    <em class="">1</em>
                    <a href="https://movie.douban.com/subject/1292052/">
                        <img width="100" alt="肖申克的救赎" src="https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" class="">
                    </a>
                </div>
                <div class="info">
                    <div class="hd">
                        <a href="https://movie.douban.com/subject/1292052/" class="">
                            <span class="title">肖申克的救赎</span>
                            <span class="title">&nbsp;/&nbsp;The Shawshank Redemption</span>
                            <span class="other">&nbsp;/&nbsp;月黑高飞(港)  /  刺激1995(台)</span>
                        </a>
                        <span class="playable">[可播放]</span>
                    </div>
                    <div class="bd">
                        <p class="">
                            导演: 弗兰克·德拉邦特 Frank Darabont&nbsp;&nbsp;&nbsp;主演: 蒂姆·罗宾斯 Tim Robbins /...<br>
                            1994&nbsp;/&nbsp;美国&nbsp;/&nbsp;犯罪 剧情
                        </p>
                        <div class="star">
                                <span class="rating5-t"></span>
                                <span class="rating_num" property="v:average">9.7</span>
                                <span property="v:best" content="10.0"></span>
                                <span>2220628人评价</span>
                        </div>
                        <p class="quote">
                            <span class="inq">希望让人自由。</span>
                        </p>
                    </div>
                </div>
            </div>
        </li>
'''
# 将HTML数据转化为xml对象
html_element = etree.HTML(source_text)
# 获取电影的名字
movie_name = html_element.xpath('//div[@class="hd"]/a/span[1]/text()')[0]
print(movie_name)
# 获取电影的详情URL
movie_url = html_element.xpath('//div[@class="hd"]/a/@href')[0]
print(movie_url)
# 获取电影的评分
movie_star = html_element.xpath('//div[@class="star"]/span[2]/text()')[0]
print(movie_star)
# 获取电影的引言
movie_quote = html_element.xpath('//p[@class="quote"]/span/text()')
if movie_quote:
    movie_quote = movie_quote[0]
else:
    movie_quote = ''
print(movie_quote)

最后获取电影引言的时候,加上了if语句,目的是判断xpath返回的列表是否为空。如果为空,则手动将变量movie_quote赋值为空字符串。xpath语句后面加上[0]表示取返回列表的第一个值,上述操作都是为后续的写入数据到csv文件做准备。
运行结果:
在这里插入图片描述

4.2 完整代码

class Spider(object):
    def __init__(self, base_url):
        self.req_headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, '
                          'like Gecko) Chrome/87.0.4280.88 Safari/537.36 '}
        self.base_url = base_url
        self.titles = ['name', 'url', 'star', 'quote']

    # 获取网页源码文本数据
    def GetSourceText(self, tar_url):
        res_obj = requests.get(tar_url, headers=self.req_headers)
        res_obj.encoding = 'utf-8'
        source_text = res_obj.text
        return source_text

    # 获取每个电影的数据,每个电影以字典的形式写到列表中
    def GetEveryItem(self, source_text):
        html_element = etree.HTML(source_text)
        # 提取每个电影的总标签内容
        movieItemList = html_element.xpath('//div[@class="info"]')
        movie_list = []
        for eachmovie in movieItemList:
            movie_dict = {}
            movie_name = eachmovie.xpath('div[@class="hd"]/a/span[1]/text()')[0]
            movie_url = eachmovie.xpath('div[@class="hd"]/a/@href')[0]
            movie_star = eachmovie.xpath('div[@class="bd"]/div[@class="star"]/span[2]/text()')[0]
            movie_quote = eachmovie.xpath('div[@class="bd"]/p[@class="quote"]/span/text()')
            if movie_quote:
                movie_quote = movie_quote[0]
            else:
                movie_quote = ''
            movie_dict[self.titles[0]] = movie_name
            movie_dict[self.titles[1]] = movie_url
            movie_dict[self.titles[2]] = movie_star
            movie_dict[self.titles[3]] = movie_quote
            movie_list.append(movie_dict)
        return movie_list

    # 将爬取的数据写入到csv文件中
    def WirteData(self, movie_list, filename):
        with open(filename, 'w', encoding='utf-8', newline='') as fobj:
            writer_obj = csv.DictWriter(fobj, self.titles)
            writer_obj.writeheader()
            writer_obj.writerows(movie_list)
	
	# 控制数据爬取、保存的流程
    def main(self):
        start_page = int(input('请输入爬取网页的起始页:'))
        end_page = int(input('请输入爬取网页的终止页:'))
        movie_list = []
        for i in range(start_page, end_page+1):
            tar_url = self.base_url.format((i-1)*25)
            source_text = self.GetSourceText(tar_url)
            movie_list += self.GetEveryItem(source_text)
        self.WirteData(movie_list, 'movie_data.csv')

if __name__ == '__main__':
    douban = Spider('https://movie.douban.com/top250?start={}&filter=')
    douban.main()

运行结果:
爬取前两页的电影数据,csv文件的内容如下:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值