lxml类库的xpath的使用
为什么要学习lxml类库和xpath呢?
-lxml类库是一款高性能的Python HTML/XML解析器,我们可以利用XPath,
来快速地定位特定元素以及获取节点信息。
-XPath是一门在HTML/XML文档中查找信息的语言,可用来在HTML/XML文档中对元素和属性进行遍历。
XML和HTML的区别?
-XML:可扩展标记语言,被设计为传输和存储数据,其焦点是数据的内容。
-HTML:超文本标记语言,显示数据以及如何更好显示数据。
我们可以使用chrome的XPath-Helper插件来帮助我们寻找想要的数据。XPath-Helper的使用?
①获取文本:"a/text()"
-选择文本为下一页三个字的a标签按钮:"//a[text()='下一页']"
②获取属性(使用@符号定位):"a/@href";"//ul[@id='detail-list']/li/p/text()"
③//的使用:在xpath开始的时候表示从当前html中任意位置开始选择
-"a//text()":获取a下的所有文本;"li//":表示li下任何一个标签
注意:使用chrome插件选择标签时候,选中的标签会添加属性class="xh-highlight"
④面对xpath列表每个元素的索引:"div[@div='page']/a[2]"(获取第三个a标签)
-豆瓣剧情片排行榜:"//div[@id='wrapper']//div[@class='movie-list-panel pictext']/div[last()]"
(获取最后一个div标签)
⑤面对xpath列表一些元素的获取:"div[@div='page']/a[position()>4]"
(获取从第5个开始后面的所有a标签,数字是索引)
注意:使用XPath-Helper或者是chrome中的copy xpath都是从element中提取的数据,
但是爬虫获取的是url对应的响应,往往和elements不一样。
所以,这时候lxml类库的一个功能就应运而生:
导入lxml的etree库:from lxml import etree
利用etree.HTML,将字符串转化为Element对象:html=etree.HTML(text)
lxml可以自动修正html代码。
节点选择语法:
/ :从根节点选取。
// :从匹配选择的当前节点选择文档中的节点,而不考虑他们的位置。
. :选取当前节点。
.. :选取当前节点的父节点。
@ :选取属性。
* :匹配任何元素节点。
@* :匹配任何属性节点。
node():匹配任何类型的节点
节点选择语法详细例子说明:
/bookstore/* :选取bookstore元素的所有子元素。
//* :选取文档中的所有元素。
html/node()/meta/@*:选择html下面任意节点下的meta节点的所有属性。
//title[@*] :选取所有带属性的title元素。
from lxml import etree
text='''<div><ul>
<li class="item-1"><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">forth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</ul></div>'''
html=etree.HTML(text)
print(html)
输出结果:
<Element html at 0x1ffec265d48>
#这个时候的html是一个响应状态。
print(etree.tostring(html).decode())
输出结果:
<html><body><div><ul>
<li class="item-1"><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">forth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</ul></div></body></html>
<li class="item-1"><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">forth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</ul></div></body></html>
#查看element对象中包含的字符串
#lxml能够修正HTML代码,但是可能会改错了:
使用etree.tostring观察修改之后的html的样子,根据修改之后的html字符串写xpath。
list_1=html.xpath('//li[@class="item-1"]/a/@href')
print(list_1)
list_2=html.xpath('//li[@class="item-1"]/a/text()')
print(list_2)
for href in list_1:
item={}
item["href"]=href
item["titile"]=list_2[list_1.index(href)]
print(item)
输出结果是:
['link1.html', 'link2.html', 'link4.html']
['first item', 'second item', 'forth item']
{'href': 'link1.html', 'titile': 'first item'}
{'href': 'link2.html', 'titile': 'second item'}
{'href': 'link4.html', 'titile': 'forth item'}
['first item', 'second item', 'forth item']
{'href': 'link1.html', 'titile': 'first item'}
{'href': 'link2.html', 'titile': 'second item'}
{'href': 'link4.html', 'titile': 'forth item'}
#要注意的是:xpath输出的数据类型是列表。
#分组,根据li标签进行分组,对每一组继续写xpath
list_3=html.xpath('//li[@class="item-1"]')
print(list_3)
for i in list_3:
item={}
item["title"]=i.xpath("./a/@href")[0]
item["href"]=i.xpath("./a/text()")[0]
print(item)
输出结果:
[<Element li at 0x1ffec265c88>, <Element li at 0x1ffec265cc8>, <Element li at 0x1ffec265e48>]
{'title': 'link1.html', 'href': 'first item'}
{'title': 'link2.html', 'href': 'second item'}
{'title': 'link4.html', 'href': 'forth item'
{'title': 'link1.html', 'href': 'first item'}
{'title': 'link2.html', 'href': 'second item'}
{'title': 'link4.html', 'href': 'forth item'
#list_3是对象响应的列表,对于这个列表进行进一步xpath获取数据处理。
#今后xpath采取数据建议使用这段方法:
#先把对象响应分组,然后对每一组进行直接抓取数据处理,常用的方法使用.符号。
这段代码提取页面数据的思路:
-先分组,渠道一个包含分组标签的列表
-遍历,取其中每一组进行数据的提现,不会造成数据的对应错乱,避免操作失误的风险。
注意:lxml能够接受bytes和str的字符串