lxml与xpath

lxml是一个Python的一个解析库,用于解析HTML和XML,支持Xpaxth解析。由于lxml底层是使用C语言编写的,所以解析效率非常高。

一.安装lxml

主要是介绍windows下的安装

1.使用pip安装

pip install lxml

如果安装出错,表明缺少依赖库,如libxm12。这时候可以采用wheel方式安装

2.本地安装

这里给出个网址
python包Windows 二进制文件
在该页面下搜索lxml的whl文件即可。
下载完成之后,cmd切换运行到下载解压后的目录,执行如下命令

pip install lxml-4.6.3-cp310-cp310-win_amd64.whl

3。操作XML

lxml可以读取xml文件,也可以使用字符串形式的xml文档。如果要读取xml文件,需要使用parse函数,该函数需要传入一个XML文件名。如果要解析字符串形式的XML文档,需要使用fromstring函数,该函数的参数就是XML字符串。

from lxml import etree
# 读取xml文件
tree   = etree.parse('products.xml')
print(type(tree))
# 将tree重新转化为字符串形式的xml文档,并输出
print(str(etree.tostring(tree,encoding = "utf-8"),'utf-8'))
# 获得根节点
root = tree.getroot()
print(type(root))
# 输出根节点的名称
print('root:',root.tag)
# 获得根节点的所有子节点
children = root.getchildren()
print('--------------输出产品信息--------------')
# 迭代这些子节点,并输出对应的属性和节点文本
for child in children:

    print('product id = ', child.get('id'))
    print('child[0].name = ',child[0].text)
    print('child[1].price = ', child[1].text)


# 分析字符串形式的XML文档
root   = etree.fromstring('''
<products> 
    <product1 name="iPhone"/>
    <product2 name="iPad"/>
</products>
''')

print('------------新产品------------')
# 输出根节点的节点名
print('root =',root.tag)
children = root.getchildren()
# 迭代这些子节点,并输出节点的名称和name属性名
for child in children:
    print(child.tag,'name = ',child.get('name'))

4.操作HTML文档

html本质上与xml类似,都是由若干类似<tag></tag>的节点组成的。他们之间的不同之处在于XML除了这些节点,不能再有其他东西,而HTML的语法比较*,不仅可以有节点,还可以有其他任何文本。
用lxml库操作html与操作XML类似,同样可以通过getroot方法获得根节点,通过get方法获得节点属性值,通过text属性获取节点内容,通过索引的方式引用了子节点。

from lxml import etree
parser = etree.HTMLParser()
print(type(parser))
tree   = etree.parse('test.html', parser)
root = tree.getroot()
result = etree.tostring(root,encoding='utf-8',
                      pretty_print=True, method="html")
print(str(result,'utf-8'))
print(root.tag)
print('lang =',root.get('lang'))
print('charset =',root[0][0].get('charset'))
print('charset =',root[0][1].text)

二.XPath

XPath的英文名称是XML path Language ,中文是XML路径语言,他是一种在XML文档中查找信息的语言,最初是用于在XML文档中搜索节点的,但同样可以用于HTML文档的搜索,因为XML与HTML是同源的;
绝大多数HTML分析库都支持Xpath。这里介绍lxml库中使用Xpath过滤掉HTML代码中的节点
lxml装载HTML代码有如下两种方式
1.从文件装载,通过parse函数指定的HTML文件名
2.从代码装载,通过HTML函数指定HTML代码

2.1提取test.html文件中的标题,以及一段HTML代码中特定a节点的herf属性值和节点文本

from lxml import etree

parser = etree.HTMLParser()
tree   = etree.parse('test.html', parser)
# 使用xpath定位title节点,返回一个节点集合
titles = tree.xpath('/html/head/title')
if len(titles) > 0:
    # 输出title节点的文本
    print(titles[0].text)
# 定义一段html代码
html = '''
<div>
    <ul>
        <li class="item1"><a href="https://geekori.com"> geekori.com</a></li>
        <li class="item2"><a href="https://www.jd.com"> 京东商城</a></li>
        <li class="item3"><a href="https://www.taobao.com">淘宝</a></li>
    </ul>
</div>
'''
# 分析HTML代码
tree = etree.HTML(html)
# 使用xpath定位class属性值为item2的<li>节点
aTags = tree.xpath("//li[@class='item2']")
if len(aTags) > 0:
    # 得到该<li>节点中<a>节点的href属性值和文本
    print(aTags[0][0].get('href'),aTags[0][0].text)
# https://www.jianshu.com/p/2ae6d51522c3

注意:
1.通过XPath定位节点返回的是节点集合,即使只有一个节点,返回的也是一个节点集合
2.使用XPath分析的HTML文档并不一定是标准的,可以么有像`、、这些的、节点。任何一段符合HTML语法标准的代码都可以使用XPath进行定位

2.2选取所有节点

//:以两个斜杠(//)开头的XPath规则会选取所有符合要求的节点。表示任意节点,所以//*表示的是选取所有节点
这里展示一个取出所有的<a>节点,并输出节点的名称

from lxml import etree

parser = etree.HTMLParser()
html   = etree.parse('demo.html', parser)
# 选取demo.html文件中所有的节点
nodes = html.xpath('//*')
print('共',len(nodes),'个节点')
# 输出所有节点的节点名
print(nodes)
for i  in range(0,len(nodes)):
    print(nodes[i].tag,end=' ')

# 按层次输出节点,indent是缩进
def printNodeTree(node, indent):
    print(indent + node.tag)
    indent += "  "
    children = node.getchildren()
    if len(children) > 0:
        for i in range(0,len(children)):
            # 递归调用
            printNodeTree(children[i],indent)

print()
# 按层次输出节点的节点,nodes[0]是根节点(html节点)
printNodeTree(nodes[0],"")
nodes = html.xpath('//a')
print()
print('共',len(nodes),'个<a>节点')
print(nodes)
# 输出所有<a>节点的文本
for i  in range(0,len(nodes)):
    print(nodes[i].text,end=' ')

2.3选取子节点

“/”后是直接子节点。“//”是选取所有该子节点(在该父节点之下的所有)

from lxml import etree

parser = etree.HTMLParser()
html   = etree.parse('demo.html', parser)
nodes = html.xpath('//li/a')
print('共',len(nodes),'个节点')
print(nodes)
for i  in range(0,len(nodes)):
    print(nodes[i].text,end=' ')

print()
nodes = html.xpath('//ul//a')
print('共',len(nodes),'个节点')
print(nodes)
for i  in range(0,len(nodes)):
    print(nodes[i].text,end=' ')

print()
nodes = html.xpath('//ul/a')
print('共',len(nodes),'个节点')
print(nodes)

2.4选取父节点

如果知道子节点,想得到父节点,可以使用"..";“parent:

上一篇:Python练习之使用XPath获取豆瓣电影排行榜


下一篇:xpath的基本使用以及lxml解析html代码和文件