xpath学习记录
第一次接触xpath, 发现使用得好的话可以爬取任何网页的某个元素节点的内容,也可以通过一些逻辑关系、比较关系等进行爬取
导入包:
from lxml import etree
需要进行操作的html页面:
html= """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>测试页面</title>
</head>
<body>
<ol>
<li class="haha">醉卧沙场君莫笑,古来征战几人回</li>
<li class="heihei">两岸猿声啼不住,轻舟已过万重山</li>
<li id="hehe" class="nene">一骑红尘妃子笑,无人知是荔枝来</li>
<li class="xixi">停车坐爱枫林晚,霜叶红于二月花</li>
<li class="lala">商女不知亡国恨,隔江犹唱后庭花</li>
</ol>
<div id="pp">
<div>
<a href="http://www.baidu.com">李白</a>
</div>
<ol>
<li class="huanghe">君不见黄河之水天上来,奔流到海不复回</li>
<li id="tata" class="hehe">李白乘舟将欲行,忽闻岸上踏歌声</li>
<li class="tanshui">桃花潭水深千尺,不及汪伦送我情</li>
</ol>
<div class="hh">
<a href="http://mi.com">雷军</a>
</div>
<ol>
<li class="dudu">are you ok</li>
<li class="meme">会飞的猪</li>
</ol>
</div>
</body>
</html>"""
这里使用到导入的包,etree作用是HTML字符串用一个属性结构来表现出来,称为节点树 1. 用etree把html页面加载进来,创建一个节点树
html_tree = etree.HTML(html)
2.获取节点
获取test文件中的第一个li, xpath语法中数字从1开始
ret = html_tree.xpath("/html/body/ol/li[1]")
print(ret) # [<Element li at 0x240c97a4088>] 以列表形式显示 获取到第一个li节点
xpath方法可以根据xpath语法把符合语法的所有节点对象放入一个列表返回出来
ret = html_tree.xpath("/html/body/div/div[1]/a")
print(ret) # [<Element a at 0x2685610cf48>] 返回的是一个列表
3.获取节点属性和内容
3.1)获取节点文本内容
ret = html_tree.xpath("/html/body/ol/li/text()")
print(ret)
# ['醉卧沙场君莫笑,古来征战几人回', '两岸猿声啼不住,轻舟已过万重山', '一骑红尘妃子笑,无人知是荔枝来', '停车坐爱枫林晚,霜叶红于二月花', '商女不知亡国恨,隔江犹唱后庭花']
3.2)获取节点里面的属性
ret = html_tree.xpath("/html/body/div/div[1]/a/@href")
print(ret) # 获取节点的指定属性内容
# ['http://www.baidu.com']
4、定位
4.1)层级定位
查找页面上所有的li
ret = html_tree.xpath("//li/text()")
print(ret)
# ['醉卧沙场君莫笑,古来征战几人回', '两岸猿声啼不住,轻舟已过万重山', '一骑红尘妃子笑,无人知是荔枝来', '停车坐爱枫林晚,霜叶红于二月花', '商女不知亡国恨,隔江犹唱后庭花', '君不见黄河之水天上来,奔流到海不复回', '李白乘舟将欲行,忽闻岸上踏歌声', '桃花潭水深千尺,不及汪伦送我情', 'are you ok', '会飞的猪']
在xpath语法中“/”代表两层节点中间只相隔一层,“//”代表相隔若干层
ret = html_tree.xpath("//ol//@class") # ol下所有层的class的属性内容
print(ret)
# ['haha', 'heihei', 'nene', 'xixi', 'lala', 'huanghe', 'hehe', 'tanshui', 'dudu', 'meme']
4.2)属性定位
查找页面上所有带id属性的li
ret = html_tree.xpath("//li[@id]/text()")
print(ret)
# ['一骑红尘妃子笑,无人知是荔枝来', '李白乘舟将欲行,忽闻岸上踏歌声']
查找页面上所有的class值为dudu的li
ret = html_tree.xpath("//li[@class='dudu']/text()")
print(ret) # ['are you ok']
xpath语法中所有的属性前面要用@点缀
ret = html_tree.xpath("//li[@class='hehe jj']/text()") # 【注意】xpath属性修饰的时候一定要把属性的值写全
print(ret) # [] 这里是错误示范,没有写全的话会爬取不到数据
5、模糊匹配
5.1)包含contains:查找所有的class值中包含he的li
ret = html_tree.xpath("//li[contains(@class,'he')]/text()")
print(ret)
# ['两岸猿声啼不住,轻舟已过万重山', '君不见黄河之水天上来,奔流到海不复回', '李白乘舟将欲行,忽闻岸上踏歌声']
5.2)开头 starts-with:查找所有的class值以h开头的li
ret = html_tree.xpath("//li[starts-with(@class,'h')]/text()")
print(ret)
# ['醉卧沙场君莫笑,古来征战几人回', '两岸猿声啼不住,轻舟已过万重山', '君不见黄河之水天上来,奔流到海不复回', '李白乘舟将欲行,忽闻岸上踏歌声']
6、逻辑匹配
6.1) 与 and :查找所有的含有id属性并且含有class的那些li
ret = html_tree.xpath("//li[@id='hh' and @class]")
print(ret) # [] 条件不符合则返回空
6.2)或 or :查找id属性为hh,class属性为meme的li
ret = html_tree.xpath("//li[@id='hh' or @class='meme']/text()")
print(ret)