lxml + XPath 处理 HTML 实践
用 python 处理 HTML 文本时,re/pyquery 的可维护性都不高,尝试用 XPath
文档来源 XPath 教程
XPath 路径表达式
nodename次节点的所有子节点/从根节点选取//从所有叶子节点选取.选取当前节点..选取当前节点父节点@选取属性*任何元素节点@*任何属性节点node()匹配任何类型的节点|选取多个路径::步轴名称::节点测试[谓语]
XPath 实例
bookstorebookstore 元素的所有子节点/bookstore选择根元素 bookstore//book选择所有 book 叶子节点bookstore//bookbookstore 节点下的所有 book 叶子节点//@lang名为 lang 的所有属性/bookstore/book[1]选取属于 bookstore 子元素的第一个 book 元素/bookstore/book[last()]选取属于 bookstore 子元素的最后一个 book 元素/bookstore/book[last()-1]选取属于 bookstore 子元素的倒数第二个 book 元素/bookstore/book[position()<3]选取最前面的两个属于 bookstore 元素的子元素的 book 元素//title[@lang]选取所有拥有名为 lang 的属性的 title 元素//title[@lang='eng']选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性/bookstore/book[price>35.00]选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00/bookstore/book[price>35.00]/title选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00/bookstore/*bookstore 的所有子元素//*所有元素//title[@*]带有 title 属性的所有元素//title | //price所有 title / price 节点child::book属于当前节点子元素的 book 节点attribute::lang选取当前节点的 lang 属性child::*选取当前节点所有子元素attribute::*当前节点的所有属性child::text()当前节点的所有文本子节点child::node()当前节点的所有子节点descendant::book当前节点的所有 book 后代ancestor::book当前节点的所有 book 父节点ancestor-or-self::book当前节点的所有 book 父节点 + 当前节点child::*/child::price当前节点的所有子节点的 price 子节点(第二代子节点)
XPath 运算符
|两个节点集+-*div加法 减法 乘法 除法=!=<<=>>=orandmodmod 计算余数
函数
XPath 含有超过 100 个内建的函数。这些函数用于字符串值、数值、日期和时间比较、节点和 QName 处理、序列处理、逻辑值等等
简单 lxml + XPath 处理 HTML 代码
 1 # encoding: utf-8
 2 from StringIO import StringIO
 3 
 4 from lxml import etree
 5 
 6 broken_html = """<html>
 7 <head>
 8     <title>Tank</title>
 9 </head>
10 <body>
11 <header>
12     <ul>
13         <li>Home</li>
14         <li>About</li>
15     </ul>
16 </header>
17 <div class="container">
18     <div class="row">
19         <div class="col-md-6">
20             <table>
21                 <thead>
22                     <th>ID</th>
23                     <th>Name</th>
24                 </thead>
25                 <tbody>
26                     <tr><td>1</td><td>Tank</td></tr>
27                     <tr><td>2</td><td>Caption</td></tr>
28                     <tr><td>3</td><td>Coco</td></tr>
29                 </tbody>
30             </table>
31         </div>
32         <div class="col-md-6"></div>
33     </div>
34 </div>
35 <footer>Powered by Cooper</footer>
36 </body>
37 </html>
38 """
39 
40 parser = etree.HTMLParser()
41 tree = etree.parse(StringIO(broken_html), parser)
42 
43 
44 def t_xpath():
45     x_exp = "//div[@class='col-md-6']"
46     print 'xpath', x_exp
47     for foot in tree.xpath(x_exp):
48         print foot.tag, foot.getparent().attrib
49 
50     x_exp = '//tr/td[2]'
51     print 'xpath', x_exp
52     for td in tree.xpath(x_exp):
53         print td.tag, td.text
54 
55     x_exp = '//tr/td[1][text()>1]'
56     print 'xpath', x_exp
57     for td in tree.xpath(x_exp):
58         print td.tag, td.text
59 
60     x_exp = '//div[@class]'
61     print 'xpath', x_exp
62     for td in tree.xpath(x_exp):
63         print td.tag, td.attrib
64 
65 
66 def pretty_print():
67     result = etree.tostring(
68         tree.getroot(),
69         pretty_print=True,
70         method="html")
71     print result
72 
73     html = etree.HTML(broken_html)
74     print etree.tostring(html, pretty_print=True, method='html')
75 
76 
77 # pretty_print()
78 t_xpath()输出
xpath //div[@class='col-md-6']
div {'class': 'row'}
div {'class': 'row'}
xpath //tr/td[2]
td Tank
td Caption
td Coco
xpath //tr/td[1][text()>1]
td 2
td 3
xpath //div[@class]
div {'class': 'container'}
div {'class': 'row'}
div {'class': 'col-md-6'}
div {'class': 'col-md-6'}未完待续
					
  
blog comments powered by Disqus