鱼C论坛

 找回密码
 立即注册

725

已有 417 次阅读2018-7-25 21:50

解析库的使用  1xpath 2beautifulsoup 3pyquery
用正则表达式提取页面信息多多少少还是有些繁琐。
对于网页的节点来说,可以定义id、class等属性,而且节点之间也有层次关系
那么,我们用xpath定位提取一个或多个节点,再调用相应方法获取其正文内容、属性,就可以得到我们想要的信息!
xpath常见规则
nodename:选取此节点的所有子节点
/:从当前节点选取直接子节点
//:从当前节点选取子孙节点
.:选取当前节点
。。:选取当前节点的父节点
@:选取属性
比如://title[@lang='eng'] 它代表选择所有名称为title,同时属性lang为eng的节点

from lxml import etree
text='''
<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>
</u>
'''
html=etree.HTML(text)
result=etree.tostring(html)
print(result.decode('utf-8'))
首先导入了etree模块,然后声明了HTML文本,调用html类进行初始化,这样就构造出了XPath解析对象
我们可以看出,文本最后一个li节点并没有封闭,但,etree可以自动修正
然后调用tostring方法可以输出为二进制html代码,然后再用decode方法转化为str
也可以直接读取文本文件进行解析
from lxml import etree
html=etree.parse('./test.html,etree.HTMLParse())
result=etree.tostring(html)
print(result.decode('utf-8'))


所有节点:
如果我们要选取所有节点,我们可以这么做:
from lxml import etree
html=etree.parse('./test.html',etree.HTMLParse())
result=html.xpath('//*')
print(result)
这里的*代表所有节点,也就是说文本中的所有节点都会被抓取,返回一个列表。变为element+名称

如果想匹配所有的li节点:
from lxml import etree
html=etree.parse('./test.html',etree.HTMLParse())
result=html.xpath('//li')
print(result)
print(result[0])
这里使用了//直接加上节点名称,调用时是用xpath方法。因为返回的是一个列表,
所以result[0]可以取出一个对象。

子节点:
我们通过/或//查找元素的子节点或子孙节点。如果想选择li节点的所有直接a子节点:
from lxml import etree
html=etree.parse('./test.html',etree.HTMLParse())
result=html.xpath('//li/a')
print(result)
这里通过追加/a,选择了li节点的所有直接a子节点
如果想获取所有子孙a节点,则可以用result=html.xpath('//ul//a')

父节点:我们用..来查找父节点。
from lxml import etree
html=etree.parse('./test.html',etree.HTMLParse())
result=html.xpath('//a[@href='link4.html']/../@class')
print(result)
我们首先选中href属性为link4.html的a节点,然后获取其父节点,最后获取其class属性。
同样的,parent::也可以用来获取父节点:
from lxml import etree
html=etree.parse('./test.html',etree.HTMLParse())
result=html.xpath('//a[@href='link4.html]/parent::*/@class)
print(result)

属性匹配:我们可以用@进行属性过滤,比如这里要选取class为item-0的li节点。
from lxml import etree
html=etree.parse('./test.html',etree.HTMLParse())
result=html.xpath('//[@class='item-0']')
print(result)
这里我们通过加入[@class='item-0']限制了节点的class属性为item-0.

文本获取:我们用text()方法获取节点中的文本接下来尝试获取前面li节点的文本
如果我们想获取li节点内部文本,1:选a节点后在获取文本。2:使用//
from lxml import etree
html=etree.parse('./test.html,etree.HTMLParser())
result=html.xpath('//li[@class='item-0']/a/text()')
print(result)

from lxml import etree
html=etree.parse('./test.html,etree.HTMLParser())
result=html.xpath('//li[@class='item-0']//text()')
print(result)
想要获取文本的话最好使用第二种方式。

属性获取 用@进行属性获取
from lxml import etree
html=etree.parse('./test.html,etree.HTMLParser())
result=html.xpath('//li/a/@href')
print(result)
这里我们通过@href获取节点的href属性。
注:属性匹配是中括号加属性名和值限定某个属性,如[@href='link。html']
而此处的@href指的是获取某个节点的属性。
多属性值匹配:
from lxml import etree
text=
'''
<li class='li li-first'><a href='link.html'>first item</a></li>
'''
html=etree.HTML(text)
result=html.xpath('//li[@class='li']/a/text()')\
print(result)
这里面li节点的class属性有两个值li与li-first。此时就用contains()函数。
from lxml import etree
text=
'''
<li class='li li-first'><a href='link.html'>first item</a></li>
'''
html=etree.HTML(text)
result=html.xpath('//li[contains(@class,'li')]/a/text()')
print(result)
这样应用contains()方法,第一个参数传入属性名称,第二个参数传入属性值,
只要此属性包含所传入的属性值,就完成匹配

多属性匹配:如果要根据多个属性确定一个节点,这时用运算符and连接
from lxml import etree
text=
'''
<li class='li li-first',name='item'><a href='link.html'>first item</a></li>
'''
html=etree.HTML(text)
result=html.xpath('//li[contains(@class,'li'and @name='item']/a/text()')
print(result)
这里的li节点增加了一个属性name,需要同时根据class和name属性选择
一个条件是class属性里包含li字符串 另一个条件是name属性为item字符串,二者用and操作符连接

13 按序选择
某些属性可能同时匹配了多个节点,但是我们只想要其中的一个

14节点轴选择
from lxml import etree
text='''
<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>
</u>
'''
html=etree.HTML(text)
result=html.xpath('//li[1]/ancestor::*')
print(result)
result=html.xpath('//li[1]/ancestor::div')
print(result)
result=html.xpath('//li[1]/attribute::*')
print(result)
result=html.xpath('//li[1]/child::a[@href="link1.html"]')
print(result)
result=html.xpath('//li[1]/descendant::span')
print(result)
result=html.xpath('//li[1]/following::*[2]')
print(result)
result=html.xpath('//li[1]/following-sibling::*')
print(result)

result=html.xpath('//li[1]/ancestor::*')
第一次调用了ancestor轴,可以获取搜游祖先节点,后面需跟两个冒号,然后我们用*代表所有节点。
因此返回的是第一个节点li的所有祖先节点


result=html.xpath('//li[1]/ancestor::div')
只能获取div这个祖先节点了

result=html.xpath('//li[1]/attribute::*')
调用了attribute轴,可以获取所有属性值返回了li节点的所有属性值

result=html.xpath('//li[1]/child::a[@href="link1.html"]')
调用了child轴,可以获取所有直接子节点。故,得到了href属性为link1.html的a节点

result=html.xpath('//li[1]/descendant::span')
调用了descendant轴,可以获取所有子孙节点,这里加入了限定条件获取span节点,故返回的结果只包含
span节点

result=html.xpath('//li[1]/following::*[2]')
调用了following轴,可以获取当前节点之后的所有节点,这句获取了第二个后续节点
result=html.xpath('//li[1]/following-sibling::*')
调用了following-sibling轴,可以获取当前节点之后的所有同级节点。由于是*,所示所有后续同级节点。































路过

雷人

握手

鲜花

鸡蛋

全部作者的其他最新日志

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-16 14:14

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

返回顶部