非结构化数据之lxml库

lxml 是一种使用 Python 编写的库,可以迅速、灵活地处理 XML ,支持 XPath (XML Path Language)

lxml python 官方文档

http://lxml.de/index.html

学习目的

利用上节课学习的XPath语法,来快速的定位 特定元素以及节点信息,目的是 提取出 HTML、XML 目标数据

如何安装

  • Ubuntu :
  1. sudo apt-get install libxml2-dev libxslt1-dev python-dev
  2. sudo apt-get install zlib1g-dev
  3. sudo apt-get install libevent-dev
  4. sudo pip install lxml

利用 pip 安装即可

  • Windows:

http://blog.csdn.net/g1apassz/article/details/46574963

http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml

初步使用

首先我们利用lxml来解析 HTML 代码,先来一个小例子来感受一下它的基本用法。

使用 lxml 的 etree 库,然后利用 etree.HTML 初始化,然后我们将其打印出来。

  1. from lxml import etree
  2. text = '''
  3. <div>
  4. <ul>
  5. <li class="item-0"><a href="link1.html">first item</a></li>
  6. <li class="item-1"><a href="link2.html">second item</a></li>
  7. <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>
  8. <li class="item-1"><a href="link4.html">fourth item</a></li>
  9. <li class="item-0"><a href="link5.html">fifth item</a>
  10. </ul>
  11. </div>
  12. '''
  13. #Parses an HTML document from a string
  14. html = etree.HTML(text)
  15. #Serialize an element to an encoded string representation of its XML tree
  16. result = etree.tostring(html)
  17. print result

所以输出结果是这样的

  1. <html><body><div>
  2. <ul>
  3. <li class="item-0"><a href="link1.html">first item</a></li>
  4. <li class="item-1"><a href="link2.html">second item</a></li>
  5. <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>
  6. <li class="item-1"><a href="link4.html">fourth item</a></li>
  7. <li class="item-0"><a href="link5.html">fifth item</a>
  8. </li></ul>
  9. </div>
  10. </body></html>

不仅补全了 li 标签,还添加了 body,html 标签。

XPath实例测试

  • (1)获取所有的 <li> 标签
  1. print type(html)
  2. result = html.xpath('//li')
  3. print result
  4. print len(result)
  5. print type(result)
  6. print type(result[0])

运行结果

  1. <type 'lxml.etree._ElementTree'>
  2. [<Element li at 0x1014e0e18>, <Element li at 0x1014e0ef0>, <Element li at 0x1014e0f38>, <Element li at 0x1014e0f80>, <Element li at 0x1014e0fc8>]
  3. 5
  4. <type 'list'>
  5. <type 'lxml.etree._Element'>

可见,每个元素都是 Element 类型;是一个个的标签元素,类似现在的实例

  1. <Element li at 0x1014e0e18> Element类型代表的就是
  2. <li class="item-0"><a href="link1.html">first item</a></li>
  • [注意]

Element类型是一种灵活的容器对象,用于在内存中存储结构化数据。

每个element对象都具有以下属性:

  1. tag:string对象,标签,用于标识该元素表示哪种数据(即元素类型)。

  2. attrib:dictionary对象,表示附有的属性。

  3. text:string对象,表示element的内容。

  4. tail:string对象,表示element闭合之后的尾迹。

  • 实例
<tag attrib1=1>text</tag>tail
1     2        3         4
result[0].tag
result[0].text
result[0].tail
result[0].attrib
  • (2)获取 <li> 标签的所有 class
html.xpath('//li/@class')

运行结果

['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']
  • (3)获取 <li> 标签下属性 href 为 link1.html 的 <a> 标签
html.xpath('//li/a[@href="link1.html"]')

运行结果

[<Element a at 0x10ffaae18>]
  • (4)获取 <li> 标签下的所有 <span> 标签

注意这么写是不对的

html.xpath('//li/span')

因为 / 是用来获取子元素的,而 <span> 并不是 <li> 的子元素,所以,要用双斜杠

html.xpath('//li//span')

运行结果

[<Element span at 0x10d698e18>]
  • (5)获取 <li> 标签下的所有 class,不包括 <li>
html.xpath('//li/a//@class')

运行结果

['blod']
  • (6)获取最后一个 <li><a> 的 href
html.xpath('//li[last()]/a/@href')

运行结果

['link5.html']
  • (7)获取 class 为 bold 的标签名
result = html.xpath('//*[@class="bold"]')
print result[0].tag

运行结果

span

开始练习

通过以上实例的练习,相信大家对 XPath 的基本用法有了基本的了解

实战项目

以腾讯招聘网站为例

http://hr.tencent.com/position.php?&start=10

from lxml import etree
import urllib2
import urllib
import json

request = urllib2.Request('http://hr.tencent.com/position.php?&start=10#a')
response =urllib2.urlopen(request)
resHtml = response.read()
output =open('tencent.json','w')

html = etree.HTML(resHtml)
result = html.xpath('//tr[@class="odd"] | //tr[@class="even"]')

for site in result:
    item={}

    name = site.xpath('./td[1]/a')[0].text
    detailLink = site.xpath('./td[1]/a')[0].attrib['href']
    catalog = site.xpath('./td[2]')[0].text
    recruitNumber = site.xpath('./td[3]')[0].text
    workLocation = site.xpath('./td[4]')[0].text
    publishTime = site.xpath('./td[5]')[0].text

    print type(name)
    print name,detailLink,catalog,recruitNumber,workLocation,publishTime
    item['name']=name
    item['detailLink']=detailLink
    item['catalog']=catalog
    item['recruitNumber']=recruitNumber
    item['publishTime']=publishTime

    line = json.dumps(item,ensure_ascii=False) + '\n'
    print line
    output.write(line.encode('utf-8'))
output.close()

作业

(1)练习一下lxml、etree、xpath的整个的操作

(2)试试上节课XPath的语法以及Html,自己动手实践