|
1 |
| -## lxml |
2 |
| - |
3 |
| -试了这么多 HTML 解析库,好像都是这个的扩展,据说这个是解析速度最快的,那就来试一下的好了。 |
4 |
| - |
5 |
| -爬虫不仅仅只是爬虫,还是需要做一点东西出来的,做一个好一点的。数据分析,数据可视化,然后做一个漂亮的网站展示出来,这才是真正的一个完整的爬虫。 |
6 |
| - |
| 1 | +## lxml |
| 2 | + |
| 3 | +试了这么多 HTML 解析库,好像都是这个的扩展,据说这个是解析速度最快的,那就来试一下的好了。 |
| 4 | + |
| 5 | +爬虫不仅仅只是爬虫,还是需要做一点东西出来的,做一个好一点的。数据分析,数据可视化,然后做一个漂亮的网站展示出来,这才是真正的一个完整的爬虫。 |
| 6 | + |
| 7 | +之前一直使用 BeautifulSoup 做内容解析,后来发现在爬到五千多页面的时候,BeautifulSoup 就会报错 `MemoryError` ,感觉还是用一些基础的库性能会更好一些,比如说用 urllib 取代 requests。 |
| 8 | + |
| 9 | +lxml 是一款高性能的 Python XML 解析库,因为它构建在两个 C 库上,执行效率惊人。 |
| 10 | + |
| 11 | +### 简单使用 |
| 12 | + |
| 13 | +``` |
| 14 | +# coding=utf-8 |
| 15 | +
|
| 16 | +from lxml import etree |
| 17 | +
|
| 18 | +text = """ |
| 19 | +<div> |
| 20 | + <ul> |
| 21 | + <li class="item-0"><a href="link1.html">first item</a></li> |
| 22 | + <li class="item-1"><a href="link2.html">second item</a></li> |
| 23 | + <li class="item-inactive"><a href="link3.html">third item</a></li> |
| 24 | + <li class="item-1"><a href="link4.html">fourth item</a></li> |
| 25 | + <li class="item-0"><a href="link5.html">fifth item</a> |
| 26 | + <br> |
| 27 | + </ul> |
| 28 | + </div> |
| 29 | +""" |
| 30 | +
|
| 31 | +html = etree.HTML(text) |
| 32 | +
|
| 33 | +result = etree.tostring(html) |
| 34 | +print result |
| 35 | +
|
| 36 | +listresult = etree.tostringlist(html) |
| 37 | +print listresult |
| 38 | +
|
| 39 | +unicoderesult = etree.tounicode(html) |
| 40 | +print type(unicoderesult) |
| 41 | +
|
| 42 | +``` |
| 43 | + |
| 44 | +输出 |
| 45 | + |
| 46 | +``` |
| 47 | +<html><body><div> |
| 48 | + <ul> |
| 49 | + <li class="item-0"><a href="link1.html">first item</a></li> |
| 50 | + <li class="item-1"><a href="link2.html">second item</a></li> |
| 51 | + <li class="item-inactive"><a href="link3.html">third item</a></li> |
| 52 | + <li class="item-1"><a href="link4.html">fourth item</a></li> |
| 53 | + <li class="item-0"><a href="link5.html">fifth item</a> |
| 54 | + <br/> |
| 55 | + </li></ul> |
| 56 | + </div> |
| 57 | +</body></html> |
| 58 | +['<html><body><div>\n <ul>\n <li class="item-0"><a href="link1.html">first item</a></li>\n <li class="item-1"><a href="link2.html">second item</a></li>\n <li class="item-inactive"><a href="link3.html">third item</a></li>\n <li class="item-1"><a href="link4.html">fourth item</a></li>\n <li class="item-0"><a href="link5.html">fifth item</a>\n <br/>\n </li></ul>\n </div>\n</body></html>'] |
| 59 | +<type 'unicode'> |
| 60 | +``` |
| 61 | + |
| 62 | +使用 lxml.etree 初始化 HTML 文本,会自动修正代码,可以看到帮我们补全了 li 标签,修正了 br 标签,添加了 html, body 标签。 |
| 63 | + |
| 64 | +我们也可以从文件中导入 HTML 代码 |
| 65 | + |
| 66 | +``` |
| 67 | +# coding=utf-8 |
| 68 | +
|
| 69 | +from lxml import etree |
| 70 | +
|
| 71 | +html = etree.parse('test.html') |
| 72 | +result = etree.tostring(html) |
| 73 | +
|
| 74 | +print result |
| 75 | +``` |
| 76 | + |
| 77 | +与上文效果一致。 |
| 78 | + |
| 79 | +### 使用 xpath |
| 80 | + |
| 81 | +在初始化 HTML 之后,就是使用 xpath 对 DOM 节点进行查找,虽然 xpath 是对 XML 文件进行查找的,但是对于 HTML 文件的解析也是一样没有问题的。 |
| 82 | + |
| 83 | +关于 xpath 解析可以查看 [阮一峰的: xpath 路径表达式笔记](http://www.ruanyifeng.com/blog/2009/07/xpath_path_expressions.html) [W3School: XPath 教程](http://www.w3school.com.cn/xpath/) |
| 84 | + |
| 85 | +``` |
| 86 | +# coding=utf-8 |
| 87 | +
|
| 88 | +from lxml import etree |
| 89 | +
|
| 90 | +text = """ |
| 91 | +<div> |
| 92 | + <ul> |
| 93 | + <li class="item-0"><a href="link1.html">first item</a></li> |
| 94 | + <li class="item-1"><a href="link2.html">second item</a></li> |
| 95 | + <li class="item-inactive"><a href="link3.html">third item</a></li> |
| 96 | + <li class="item-1"><a href="link4.html">fourth item</a></li> |
| 97 | + <li class="item-0"><a href="link5.html">fifth item</a> |
| 98 | + <br> |
| 99 | + </ul> |
| 100 | + </div> |
| 101 | +""" |
| 102 | +
|
| 103 | +html = etree.HTML(text) |
| 104 | +
|
| 105 | +# 查找所有的 li 标签下的 a 标签 的内容 |
| 106 | +result = html.xpath("//li/a/text()") |
| 107 | +print result |
| 108 | +
|
| 109 | +# 查找所有的 li 标签下的 a 标签 的连接 |
| 110 | +result = html.xpath("//li/a/@href") |
| 111 | +print result |
| 112 | +
|
| 113 | +# 查找 class 为 item-inactive 下的 a 标签的内容 |
| 114 | +result = html.xpath("//li[@class='item-inactive']/a/text()") |
| 115 | +print result |
| 116 | +
|
| 117 | +# 查找 最后一个 li 标签的 class |
| 118 | +result = html.xpath("//li[last()]/@class") |
| 119 | +print result |
| 120 | +
|
| 121 | +# 查找 倒数第二个 li 标签下的子节点 |
| 122 | +result = html.xpath("//li[last()-1]/node()") |
| 123 | +print result[0].xpath("text()") |
| 124 | +
|
| 125 | +# 查找 第二个 li 标签的内容 |
| 126 | +result = html.xpath("//li[2]/text()") |
| 127 | +print result |
| 128 | +
|
| 129 | +# 查找 前两个 li 标签的 class |
| 130 | +result = html.xpath("//li[position()<3]/@class") |
| 131 | +print result |
| 132 | +
|
| 133 | +# 查找所有 带有 href 的节点 |
| 134 | +result = html.xpath("//*[@href]/text()") |
| 135 | +print result |
| 136 | +
|
| 137 | +# 从根节点查找所有元素节点 |
| 138 | +result = html.xpath("/*") |
| 139 | +print result[0].xpath("body/div/ul/li[1]/a/text()|body/div/ul/li[last()]/a/@href") |
| 140 | +
|
| 141 | +``` |
| 142 | + |
| 143 | +输出 |
| 144 | + |
| 145 | +``` |
| 146 | +['first item', 'second item', 'third item', 'fourth item', 'fifth item'] |
| 147 | +['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html'] |
| 148 | +['third item'] |
| 149 | +['item-0'] |
| 150 | +['fourth item'] |
| 151 | +[] |
| 152 | +['item-0', 'item-1'] |
| 153 | +['first item', 'second item', 'third item', 'fourth item', 'fifth item'] |
| 154 | +['first item', 'link5.html'] |
| 155 | +``` |
| 156 | + |
0 commit comments