仅记录lxml的etree,其中以xpath为重点,因为其他的我可能用得不多。
xpath
简单例子
import requests
from lxml import etree
url = 'https://dblp.org/pers/hd/p/Petersen:Karin'
html = requests.get(url)
html = etree.HTML(html.text) #初始化生成一个XPath解析对象
items = html.xpath('//div[contains(@class,"data")]/span//text()')
for i in items:
print(i)
xpath语法
| 表达式 | 说明 |
|---|---|
/ |
从当前节点选取直接子节点 |
// |
从当前节点选取子孙节点 |
. |
选取当前节点 |
.. |
选取当前节点的父节点 |
@ |
选取属性 |
* |
通配符,选择所有元素节点与元素名 |
@* |
选取所有属性 |
[@attrib] |
选取具有给定属性的所有元素 |
[@attrib='value'] |
选取给定属性具有给定值的所有元素 |
[tag] |
选取所有具有指定元素的直接子节点 |
[tag='text'] |
选取所有具有指定元素并且文本内容是text节点 |
xpath例子
html.xpath('//li') #获取所有子孙节点的li节点
html.xpath('//li/a') #获取所有子孙节点的li节点下的所有直接a节点
result=html.xpath('//li[@class="item"]') 匹配class="item"的li
html.xpath('//a[@href="tab"]/../@class') 获取a的父节点的class值
html.xpath('//a[@href="tab"]/parent::*/@class')获取a的父节点的class值
html.xpath('//li[@class="item"]/a/text()') #获取a节点下的内容
html.xpath('//li[@class="item"]//text()') #获取li下所有子孙节点的内容
html.xpath('//li/a/@href') #获取a的href属性
html.xpath('//li//@href') #获取所有li子孙节点的href属性
# 按熟悉选择
html.xpath('//li[@class="aaa"]/a') 只能匹配class仅为'aaa'的节点
html.xpath('//li[contains(@class,"aaa")]/a') 匹配class有'aaa'的节点
#and or 的用法
html.xpath('//li[@class="aaa" and @name="fore"]/a/text()')
html.xpath('//li[contains(@class,"aaa") and @name="fore"]/a/text()')
# 按顺序选择
html.xpath('//li[1]/a/text()') #获取第一个li下a的内容
html.xpath('//li[last()]/a/text()') #获取最后一个li下a的内容
html.xpath('//li[position()>2 and position()<4]/a/text()') #获取大于2小于4的
html.xpath('//li[last()-2]/a/text()') #获取倒数第三个
# XPath提供了很多节点选择方法,包括获取子元素、兄弟元素、父元素、祖先元素等,示例如下:
html.xpath('//li[1]/ancestor::*') #获取所有祖先节点
html.xpath('//li[1]/ancestor::div') #获取div祖先节点
html.xpath('//li[1]/attribute::*') #获取所有属性值
html.xpath('//li[1]/child::*') #获取所有直接子节点
html.xpath('//li[1]/descendant::a') #获取所有子孙节点的a节点
html.xpath('//li[1]/following::*') #获取当前子节之后的所有节点
html.xpath('//li[1]/following-sibling::*') #获取当前节点的所有同级节点
xpath的内容转载于这里
其他方法
HTML
构造了一个XPath解析对象并对HTML文本进行自动修正
参数是字符串
tostring
输出修正后的结果,类型是bytes,这是包括便签的
获取部分html
思路:
1 用xpath解析
2 tostring 转换为bytes
3 decode 转换字符串
from lxml import etree
text = '''
<div>
<ul id="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</div>
'''
html = etree.HTML(text)
result = html.xpath("//ul[@id='list']")[0]
ul_ele = etree.tostring(result, method='html', encoding="utf8")
res = ul_ele.decode('utf8')
print(res)
strip_elements
删除子孙节点etree.strip_elements(html, 'element_name', with_tag=True/False)
参数说明:
html: 经过etree.HTML()后的对象element_name: 要删除哪一个标签with_tag: 是否删除尾文本(看例子就知道什么意思了)
from lxml import etree
text = '''
<div>
<ul id="list">
<li>1<a href="#">1</a>尾巴1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<a href="#">6</a>尾巴2
</ul>
</div>
'''
html = etree.HTML(text)
etree.strip_elements(html, 'a', with_tail=True)
ul_ele = etree.tostring(html, method='html', encoding="utf8")
res = ul_ele.decode('utf8')
print(res)
结果:
<html><body><div>
<ul id="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</div>
</body></html>
注意HTML方法会补全html,注意:a标签及其后面的文本不见了
假如是这样:
from lxml import etree
text = '''
<div>
<ul id="list">
<li>1<a href="#">1</a>尾巴1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<a href="#">6</a>尾巴2
</ul>
</div>
'''
html = etree.HTML(text)
etree.strip_elements(html, 'a', with_tail=False)
ul_ele = etree.tostring(html, method='html', encoding="utf8")
res = ul_ele.decode('utf8')
print(res)
其结果:
<html>
<body>
<div>
<ul id="list">
<li>1尾巴1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
尾巴2
</ul>
</div>
</body>
</html>
尾文本被保留了下了
另外一种删除标签的方式
使用
.remove()方法,删除子节点
前面的strip_elements是删除子孙都行,所以与remove有区别:要找到父节点
from lxml import etree
text = '''
<div>
<ul id="list">
<li>1<a href="#">1</a>尾巴1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<a href="#">6</a>尾巴2
</ul>
</div>
'''
html = etree.HTML(text)
nodes = html.xpath("//a")
for node in nodes:
parent = node.getparent()
if parent is None: continue
parent.remove(node)
ul_ele = etree.tostring(html, method='html', encoding="utf8")
res = ul_ele.decode('utf8')
print(res)
结果:
<html>
<body>
<div>
<ul id="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</div>
</body>
</html>