【前情回顾】如何灵活的解析网页,提取我们想要的数据,是猿人们写爬虫时非常关心和需要解决的问题。从Python众多的可利用工具中,我们选择了lxml,它的好我们知道,它的妙待我们探讨。前面我们已经从html字符串转换成HtmlElement对象,接下来我们就探讨该如何操作这个HtmlElement对象。
lxml.html 的 HtmlElement 对象的各种属性和方法
这个HtmlElement对象有各种方法,我们重点讨论跟解析网页相关的函数,而修改这个对象的方法若与提取内容相关也一并介绍,介绍过程结合下面这段html代码以便更好说明问题:
<div class="post" id="123"> <p class="para">abc<a href="/to-go">link</a></p> </div>
.attrib 属性和 .get()方法
前者是html tag的属性集合,以字典表示;后者是取得某个属性的值,相当于字典的.get()方法。看示例:
In [35]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>') In [37]: doc.attrib Out[37]: {'class': 'post', 'id': '123'} In [38]: doc.get('class') Out[38]: 'post'
.drop_tag()方法
移除该html tag,但保留它的子节点和文本并合并到该tag的父节点。
In [46]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>') In [47]: doc.find('.//p').drop_tag() In [48]: lxml.html.tostring(doc) Out[48]: b'<div class="post" id="123">abc<a href="/to-go">link</a></div>'
.drop_tree()方法
移除该节及其子节点和文本,而它后面的文本(tail text)合并到前面一个节点或父节点。
In [50]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>') In [51]: doc.find('.//p').drop_tree() In [52]: lxml.html.tostring(doc) Out[52]: b'<div class="post" id="123"></div>'
.find(path), .findall(path), .findtext(path)方法
通过path(Xpath)或tag查找特定节点,前者返回找到的第一个,第二个返回找到的全部HTMLElement,第三个返回找到的第一个的节点的文本(.text)
In [55]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>') In [56]: doc.find('p') Out[56]: <Element p at 0x7fc40a4dd6d8> In [57]: doc.find('.//a') Out[57]: <Element a at 0x7fc409fee4a8> In [58]: doc.findall('p') Out[58]: [<Element p at 0x7fc40a4dd6d8>] In [76]: doc.findtext('.//a') Out[76]: 'link'
.find_class(class_name)方法
通过class名称查找所有含有class_name的元素,返回HtmlElement的列表
In [70]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p><p class="para p2"></p></div>') In [71]: doc.find_class('para') Out[71]: [<Element p at 0x7fc40a3ff278>, <Element p at 0x7fc40a3ffc78>]
.get_element_by_id(id) 方法
得到第一个id为输入id的节点。如果有多个相同id的节点(按道理讲,一个HTML文档里面的id是唯一的)只返回第一个。
In [79]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>') In [80]: doc.get_element_by_id('123') Out[80]: <Element div at 0x7fc409fda2c8>
.getchildren()、getparent() 方法
顾名思义,获取 孩子节点和父节点。需要注意的是,还是可以有多个(返回list),父亲只有一个。
In [83]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>') In [84]: doc.getchildren() Out[84]: [<Element p at 0x7fc410836b38>] In [85]: doc.getparent() Out[85]: <Element body at 0x7fc40a3ff9a8> # 注意:输入的本没有body,div已经是最上层节点,它的父节点就是body了
.getnext() .getprevious() 方法
获取后一个或前一个节点,如果没有则返回None。
In [109]: doc = lxml.html.fromstring('<div><p>abc</p><p>xyz</p></div>') In [110]: doc.getnext() In [111]: doc.find('p').getnext() Out[111]: <Element p at 0x7fc409fdad68> In [112]: doc.find('p').getprevious()
.getiterator()、.iter() 方法
从该节点开始,按文档顺序(深度优先)遍历所有子节点。可以指定只遍历某些tag。
In [127]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>') In [128]: for itr in doc.getiterator(): ...: print(itr.tag) ...: div p a In [129]: for itr in doc.iter(): ...: print(itr.tag) ...: div p a
.iterchildren() 方法
只遍历子节点。
.iterancestors() .iterdescendants()方法
前者遍历前辈(从父亲节点开始),后者遍历后辈(从子辈开始),都跳过该节点。
In [134]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>') In [135]: a = doc.find('.//a') In [136]: for itr in doc.iterancestors(): ...: print(itr.tag) ...: body html In [137]: for itr in a.iterancestors(): ...: print(itr.tag) ...: p div body html In [138]: for itr in doc.iterdescendants(): ...: print(itr.tag) ...: p a
.iterfind(path) 方法
遍历所有符合path的子节点,类似于findall()
.make_links_absolute(base_url)
很多网页的链接都是类似href=”/path/a.html”没有写全网址,这个方法的作用就是补全网址。
.tag 属性
该节点的html tag 名称
.text .tail 属性
都是该节点的文本内容,不同的是一个在tag内,一个在尾部:
<p>text</p>tail
再看下面的代码
In [173]: doc = lxml.html.fromstring('<div><p class="para">abc<a href="/to-go">link</a>worod</p>apple</div>') In [174]: p = doc.find('p') In [175]: p.text Out[175]: 'abc' In [176]: p.tail Out[176]: 'apple'
.text_content() 方法
返回给节点及其子节点包含的所有文本
In [178]: doc.text_content() Out[178]: 'abclinkworodapple'
以上就是我们从网页提取内容时用到的主要属性和方法。下一节,我们将以实例讲解具体提取数据的过程。
神龙|纯净稳定代理IP免费测试>>>>>>>>天启|企业级代理IP免费测试>>>>>>>>IPIPGO|全球住宅代理IP免费测试