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 = '''
导演: 弗兰克·德拉邦特 Frank Darabont 主演: 蒂姆·罗宾斯 Tim Robbins /...
1994 / 美国 / 犯罪 剧情
2833257人评价
希望让人自由。
'''
# 创建对象,参数是指网页源码
tree = etree.HTML(html)
从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
# //:不需要考虑标签位置,直接定位
# 获取 span 标签
span = tree.xpath('//span') # 返回的是列表,查找所有的 span 标签,并存放到列表当中
print(span)
# 返回值
# [, , , , , , , , ]
# 获取 img 标签
img = tree.xpath('//img')
print(img)
# 返回值
# []
从根节点选取,选择当前元素的下一级。
# /:从根节点选取,选择当前元素的下一级
# 获取 p 标签下的 span 标签
span = tree.xpath('//p/span')
print(span)
# 返回值
# []
选取属性。
# @:选取属性
# 获取 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)
# 返回值
# ['肖申克的救赎']
当前元素的文本内容。
# 获取标签里面的文本内容
rank = tree.xpath('//em/text()')
print(rank)
# 返回值
# ['1']
# 获取 class 为 rating_num 标签的内容
span = tree.xpath('//span[@class="rating_num"]/text()')
print(span)
# 返回值
# ['9.7']
指定元素的索引或者属性特性。
title = tree.xpath('//div[@class="hd"]/a/span[3]/text()')
print(title)
# 返回值
# ['\xa0/\xa0月黑高飞(港) / 刺激1995(台)']
# 导入模块
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)
# 导入模块
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)
记录学习过程,欢迎讨论交流,尊重原创,转载请注明出处~