Xpath语法
一、XML简介
1、什么是XML
-
XML 指可扩展标记语言(EXtensible Markup Language)
-
XML 是一种标记语言,很类似 HTML
-
XML 的设计宗旨是传输数据,而非显示数据
-
XML 的标签需要我们自行定义
-
XML 被设计为具有自我描述性
-
XML 是 W3C 的推荐标准
W3School 官方文档:http://www.w3school.com.cn/xml/index.asp
二、XML和HTML的区别
他们两者都是用于操作数据或者结构数据,在结构上大致相同的,但他们在本质上却存在着明显的区别
语法不同: xml的语法比html要求更加严格
- xml属性不能为空,html属性可以只有属性名
- xml的标签是严格闭合的。html是可以省略未标签的
| 数据格式 | 描述 | 设计目标 |
|---|---|---|
| XML | Extensible Markup Language (可扩展标记语言) | 被设计为传输和存储数据,其焦点是数据的内容 |
| HTML | HyperText Markup Language (超文本标记语言) | 显示数据以及如何更好显示数据 |
| HTML DOM | Document Object Model for HTML (文档对象模型) | 通过 HTML DOM,可以访问所有的 HTML 元素,连同它们所包含的文本和属性,可以对其中的内容进行修改和删除,同时也可以创建新的元素 |
XML文档示例:
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
</bookstore>
HTML DOM模型:
HTML DOM 定义了访问和操作 HTML 文档的标准方法,以树结构方式表达 HTML 文档
1、XML的节点关系
1、父(Parent)
每个元素以及属性都有一个父
下面是一个简单的XML例子中,book 元素是 title、author、year 以及 price 元素的父:
<?xml version="1.0" encoding="utf-8"?>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
2、子(Children)
元素节点可有零个、一个或多个子
在下面的例子中,title、author、year 以及 price 元素都是 book 元素的子:
<?xml version="1.0" encoding="utf-8"?>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
3、同胞(Sibling)
拥有相同的父的节点
在下面的例子中,title、author、year 以及 price 元素都是同胞:
<?xml version="1.0" encoding="utf-8"?>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
4、先辈(Ancestor)
某节点的父、父的父,等等
在下面的例子中,title 元素的先辈是 book 元素和 bookstore 元素:
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
5、后代(Descendant)
某个节点的子,子的子,等等
在下面的例子中,bookstore 的后代是 book、title、author、year 以及 price 元素:
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
三、XPath简介
1、什么是XPath?
XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历
W3School官方文档:http://www.w3school.com.cn/xpath/index.asp
2、选取节点
XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。这些路径表达式和我们 在常规的电脑文件系统中看到的表达式非常相似。下面列出了最常用的路径表达式:
| 表达式 | 描述 |
|---|---|
| nodename | 选取此节点的所有子节点 |
| / | 从节点选取 |
| // | 匹配文档所有的节点,而不考虑他们的位置 |
| . | 选取当前节点 |
| … | 选取当前节点的父节点 |
| @ | 选取属性 |
在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:
| 路径 | 路径表达式 |
|---|---|
| bookstore | 选取 bookstore 元素的所有子节点 |
| /bookstore | 选取根元素 bookstore。/代表元素的绝对路径 |
| bookstore/book | 选取属于 bookstore 的子元素的所有 book 元素 |
| //book | 选取所有 book 子元素,而不管它们在文档中的位置 |
| bookstore//book | 选择属于 booksore 元素的后代所有的 book 元素,而不管他们位于 bookstore 之下的什么位置 |
| //@lang | 选取名为 lang 的所有属性 |
| text() | 取标签当中的值 |
3、谓语(Predicates)
谓语用来查找某个特定的节点或者包含某个指定的值的节点,被
嵌在方括号中,在下面的表格中,我们列出了带有谓语的一些路
径表达式,以及表达式的结果:
| 路径表达式 | 结果 |
|---|---|
| /bookstore/book[l] | 选取属于 bookstore 子元素的第一个 book 元素 |
| /bookstore/book[last()] | 选取属于 bookstore 子元素的最后一个 book 元素 |
| /bookstore/book[last()-1] | 选取属于 bookstore 子元素的倒数第二个 book 元素 |
| /bookstore/book[position()❤️] | 选最前面的两个属于 bookstore 元素的子元素的 book 元素 |
| //title[@lang] | 选取所有属性名为 lang 的属性的 title 元素 |
| //titlel@lang=‘eng’] | 选取所有 tltle 元素,且这些元素有属性值为 eng 的 lang 属性 |
| /bookstore/book[price>35.00] | 选取 bookstore 元素的所有 book 元素, 且其中的 price 元素的值须大于 35 |
| /bookstore/book[price>35.00]/title | 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素 |
4、选取未知节点
| 通用符 | 描述 |
|---|---|
| * | 匹配任何元素节点 |
| @* | 匹配任何属性节点 |
| node() | 匹配任何类型节点 |
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
| 路径表达式 | 结果 |
|---|---|
| /bookstore/* | 选取 bookstore 元素的所有子元素 |
| //* | 选取文档中的所有元素 |
| //title[@*] | 选取所有带有属性的 title 元素 |
5、选取若干路径
通过在路径表达式中使用“|”运算符,您可以选取若干个路径。在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
| 路径表达式 | 结果 |
|---|---|
| //book/title//book/price | 选取 book 元素的所有 title 和 price 元素 |
| //title//price | 选取文档中所有 title 和 price 元素 |
| //price | 选取文档中所有的 price 元素 |
四、lxml模块
1、lxml简介与安装
lxml 是一个 HTML/XML 的解析器,主要的功能是如何解析和提取 HTML/XML 数据
我们可以利用之前学习的 XPath 语法,来快速的定位特定元素以及节点信息
安装方法:pip install lxml
2、初步使用
1、解析 HTML 字符串
XML 素材:http://www.cnblogs.com/zhangboblogs/p/10114698.html
小结: lxml 可以自动修正 html 代码,例子里不仅补全了 li 标签,还添加了 body,html 标签
2、lxml 文件读取
XML 素材:http://www.cnblogs.com/zhangboblogs/p/10114698.htm
除了直接读取字符串,lxml 还支持从文件里读取内容。我们新建一个 hello.html 文件,再利用 etree.parse()方法来读取文件
注意:从文件中读取数据,要求文件内容符合 xml 格式,如果标签缺失,则不能正常读取
五、XPath节点信息解析:
from lxml import etree
text = '''
<div>
<ul>
<li class="item-0"><a href="link1.html" class = "a_class1">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive">
<a href="link3.html" class="bold"></a>
<span class="span_item1">span_text1</span>
</li>
<li class="item-1">
test
<a href="link4.html">fourth item<span class="span_item2">span_text2</span></a>
</li>
<li class="item-0">
<a href="link5.html">fifth item</a>
</ul>
</div>
'''
# 1、将html_str---》html(element对象)
tree = etree.HTML(text)
# print(tree)
# 2、将element对象变成字符串
# print(etree.tostring(tree,pretty_print=True).decode('utf-8'))
# 1. 获取所有的 <li> 标签
# result = tree.xpath('//li')
# print(result)
# 2.继续获取<li> 标签的所有 class属性
# result = tree.xpath('//li/@class')
# print(result)
# 3.继续获取<li>标签下href 为 link1.html 的 <a> 标签
# result = tree.xpath('//li/a[@href="link1.html"]')
# print(result)
# 4.获取<li> 标签下的所有 <span> 标签(包括孙子span)
#标签/标签:两个标签是父子关系
#标签//标签:两个标签是先辈和后代关系
# result = tree.xpath('//li/span')
# print(result)
# 5.获取 <li> 标签下的<a>标签里的所有 class
# result = tree.xpath('//li/a/@class')
# print(result)
# 6.获取最后一个 <li> 的 <a> 的 href
# result = tree.xpath('//li[last()]/a/@href')
# print(result)
# 7.获取倒数第二个元素的内容
# result = tree.xpath('//*[last()-1]/text()')
# print(result)
# 8.获取 class 值为 bold 的标签名
# result = tree.xpath('//*[@class="bold"]')
# print(result)
六、爬虫案例
(1)、爬取扇贝单词
import requests
from lxml import etree
from excel_utils.excel_utils import Excel_Utils
def get_content(url):
'''
请求url,获取页面tree对象
:param url:
:return:
'''
headers= {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
}
respone = requests.get(url,headers= headers)
#测试--为了确定header请求头是否正确
# print(respone.text)
return etree.HTML(respone.text)
def pase_word(tree):
'''
解析每页的单词
:param tree: 改页面的element对象
:return:
'''
en_word_list = tree.xpath('//td[@class="span2"]/strong/text()')
zh_word_list = tree.xpath('//td[@class="span10"]/text()')
# print(en_word_list)
# print(zh_word_list)
for i,word in enumerate(en_word_list):
item = {}
item['en_word'] = word
item['zh_word'] = zh_word_list[i]
# print(item)
infos.append(item)
def main():
#1、确定url
base_url = 'https://www.shanbay.com/wordlist/110521/232414/?page=%s'
#2、实现分页
for i in range(1,4):
tree = get_content(base_url %i)
#解析
pase_word(tree)
#4、保存数据
Excel_Utils.write_to_excel(infos,'单词.xls')
if __name__ == '__main__':
infos = []
main()
(2)、网易云歌手爬取
import requests
from lxml import etree
from day04.excel_utils.excel_utils import Excel_Utils
def get_xpath(url):
'''
请求url,返回响应element对象
:param url:
:return:
'''
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
}
response = requests.get(url,headers=headers)
#测试
# print(response.text)
return etree.HTML(response.text)
def get_area_urls(url):
'''
获取区域列表
:param url: 歌手首页
:return: list
'''
#请求url,获取tree
tree = get_xpath(url)
return tree.xpath('//div[@class="blk"]/ul/li/a/@href')
def get_singer_words(url):
'''
获取歌手字母列表
:param url:
:return:
'''
tree = get_xpath(url)
return tree.xpath('//ul[@id="initial-selector"]/li[position()>1]/a/@href')
def parse_singers(url):
'''
从歌手字母页面中解析歌手信息
:param url:
:return:
'''
tree = get_xpath(url)
#歌手的名称
singer_names = tree.xpath('//ul[@id="m-artist-box"]/li/p/a/text()|//ul[@id="m-artist-box"]/li/a/text()')
singer_urls = tree.xpath('//ul[@id="m-artist-box"]/li/p/a/@href|//ul[@id="m-artist-box"]/li/a/@href')
# print(singer_names)
# print(singer_urls)
for i ,name in enumerate(singer_names):
item = {}
item['singer_name'] = name
item['singer_url'] = singer_urls[i]
print(item)
singers.append(item)
#歌手详情页链接
def main():
#1、获取区域列表,urls
#经验:如果url里面有锚点,我们要特别注意了。
base_url = 'https://music.163.com/discover/artist'
area_urls = get_area_urls(base_url)
# print(area_urls)
#2、循环请求区域列表的url,进入各个区域
for area_url in area_urls:
# 3、获取歌手字母列表(urls)
singer_words = get_singer_words('https://music.163.com'+area_url)
# print(singer_words)
#4、分别请求歌手名字字母url进入该页面。
for word in singer_words:
# 5、从页面中获取歌手信息。
parse_singers('https://music.163.com'+word)
#写入excel
Excel_Utils.write_to_excel(infos=singers,filename='网易云歌手信息.xls')
if __name__ == '__main__':
singers = []
main()
(3)、古诗文爬取
import os
import re
from excel_utils.excel_utils import Excel_Utils
import requests
from lxml import etree
def get_xpath(url):
'''
请求url,获取element对象
:param url:
:return:
'''
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
}
response = requests.get(url, headers=headers)
# print(response.text)
return etree.HTML(response.text)
def parse_song(tree, url):
'''
解析诗歌
:param tree: 诗歌详情页的element对象
:return:
'''
print(1)
# 待爬取字段:古诗文名、作者、朝代、内容、译文及注释;
song_title = tree.xpath('//h1/text()')[0]
# print(song_title)
song_author = tree.xpath('//p[@class="source"]/a/text()')[1]
song_dynasty = tree.xpath('//p[@class="source"]/a/text()')[0]
song_id = re.search(r'_(\w+)\.aspx', url).group(1)
# print(song_id)
song_content = tree.xpath('string(//div[@id="contson{}"])'.format(song_id))
# print(song_content)
song_fanyi = tree.xpath('string(//div[@class="contyishang"]/p[1])')
song_zhushi = tree.xpath('string(//div[@class="contyishang"]/p[2])')
item = {}
item['song_title'] = song_title
item['song_author'] = song_author
item['song_dynasty'] = song_dynasty
item['song_id'] = song_id
item['song_content'] = song_content
item['song_zhushi'] = song_zhushi
item['song_fanyi'] = song_fanyi
print(item)
infos.append(item)
def write_to_file():
# print(2)
# 写入excel
filename = '古诗文.xls'
if not os.path.exists(filename):
Excel_Utils.write_to_excel(infos, filename)
infos.clear()
else:
Excel_Utils.append_to_excel(infos, filename)
infos.clear()
def main():
# 1、从首页中获取诗词分类url
base_url = 'https://www.gushiwen.org/'
tree_index = get_xpath(base_url)
song_type_urls = tree_index.xpath('//div[@class="right"]/div[@class="sons"]/div[@class="cont"]/a/@href')
# print(song_type_urls)
# 2、循环氢气分类url,进入分类页面。
for type_url in song_type_urls:
# 请求
tree_type = get_xpath(type_url)
# 3、获取该分类下的所有古诗的url
song_urls = tree_type.xpath('//div[@class="typecont"]/span/a/@href')
# 4、循环请求这些url,从每个古诗详情页中解析古诗信息。
# print(song_urls)
for url in song_urls:
tree_song = get_xpath(url)
parse_song(tree_song, url)
# 写入文件
write_to_file()
if __name__ == '__main__':
infos = []
main()
(4)、小说爬取
import os
import requests
from lxml import etree
from excel_utils.excel_utils import Excel_Utils
def get_xpath(url):
'''
请求url,返回响应element对象
:param url:
:return:
'''
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
}
response = requests.get(url, headers=headers)
# 测试
# print(response.text)
return etree.HTML(response.text)
def get_text(text):
if text:
return text[0]
return ''
def parse_page(tree):
'''
解析每页
:param tree:
:return:
'''
li_list = tree.xpath('//div[@class="ls"]/ul/li')
# print(li_list)
for li in li_list:
book_name = get_text(li.xpath('.//div[@class="sm"]/a/text()'))
book_url = get_text(li.xpath('.//div[@class="sm"]/a/@href'))
book_desc = get_text(li.xpath('.//div[@class="jj"]/a/text()'))
book_word_num = get_text(li.xpath('.//div[@class="zs"]/text()'))
book_author = get_text(li.xpath('.//div[@class="zz"]/text()'))
item = {}
item['book_name'] = book_name
item['book_url'] = book_url
item['book_desc'] = book_desc
item['book_author'] = book_author
item['book_word_num'] = book_word_num
print(item)
infos.append(item)
def main():
# 1、确定url
base_url = 'https://xiaoshuo.2345daohang.com/sort.html'
# 2、获取分类url
tree_index = get_xpath(base_url)
type_urls = tree_index.xpath('//div[@id="left"]/div[position()>2]/a/@href')
# 3、请求分类,点击分类,在右边的显示中取找数据。
for t_url in type_urls:
# 4、确定分类中分页。
# 获取最大也的页码
# result = tree_type.xpath('//div[@class="page"]/text()')[0]
t_url = 'https://xiaoshuo.2345daohang.com' + t_url
for i in range(1, 101):
if i == 1:
tree_type = get_xpath(t_url)
else:
# /list_20.htm
t_url_new = t_url.replace('.htm', '_{}.htm'.format(i))
# print(t_url_new)
# print('=================')
tree_type = get_xpath(t_url_new)
parse_page(tree_type)
# 保存数据
if not os.path.exists(filename):
Excel_Utils.write_to_excel(infos, filename)
infos.clear()
else:
Excel_Utils.append_to_excel(infos, filename)
infos.clear()
if __name__ == '__main__':
filename = '小说.xls'
infos = []
main()
七、将爬取信息写入Excel文件中
import xlwt
class Excel_Utils:
@staticmethod
def write_to_excel(infos,filename,sheetname = 'sheet1'):
'''
写入excel
:param infos: 写入的数据:[{item},{}]
:param filename: 文件名
:param sheetname: sheet名
:return:
'''
#1、创建工作博
work_book = xlwt.Workbook(encoding='utf-8')
#2、创建一个sheet
sheet = work_book.add_sheet(sheetname)
#3、写标头
head = list(infos[0].keys())
print(head)
for i in range(len(head)):
sheet.write(0,i,head[i])
#4|写内容
rows = 1
for item in infos:
for j in range(len(head)):
sheet.write(rows,j,item[head[j]])
rows+=1
#5、保存
work_book.save(filename)
print('写入成功!')
八、将爬取信息追加到Excel中
from xlutils.copy import copy
@staticmethod
def append_to_excel(infos, filename, sheetname='sheet1'):
'''
追加数据到excel
:param infos: 【{item},{item}。。。。】
:param filename:
:param sheetname:
:return:
'''
# 1、打开excel文件
work_book = xlrd.open_workbook(filename=filename)
# 2、获取所有表单的名称
sheet_names = work_book.sheet_names()
# 3、通过名字来获取sheet表单
sheet = work_book.sheet_by_name(sheet_names[0])
# 4、读取行数
old_rows = sheet.nrows
# 5、将xlrd的workbook变成xlwt的workbook
new_work_book = copy(work_book)
new_sheet = new_work_book.get_sheet(0)
# 写入
head = sheet.row_values(0)
for item in infos:
for j in range(len(head)):
new_sheet.write(old_rows, j, item[head[j]])
old_rows += 1
new_work_book.save(filename)
print('追加成功!')
本文介绍了XPath语法,包括XML的基本概念、与HTML的区别,XPath的节点选择、谓语和选取路径。此外,详细讲解了Python的lxml模块,包括安装、基本使用,以及如何利用XPath解析XML和HTML,结合实例展示了XPath在爬虫中的应用。
376

被折叠的 条评论
为什么被折叠?



