XPath:爬取百度贴吧图片,并保存本地
使用XPath,我們可以先將?HTML文件?轉(zhuǎn)換成?XML文檔,然后用?XPath?查找?HTML?節(jié)點(diǎn)或元素。
什么是XML
- XML?指可擴(kuò)展標(biāo)記語言(EXtensible?Markup?Language)
- XML?是一種標(biāo)記語言,很類似?HTML
- XML?的設(shè)計宗旨是傳輸數(shù)據(jù),而非顯示數(shù)據(jù)
- XML?的標(biāo)簽需要我們自行定義。
- XML?被設(shè)計為具有自我描述性。
- XML?是?W3C?的推薦標(biāo)準(zhǔn)
- W3School官方文檔:http://www.w3school.com.cn/xml/index.asp
XML?和?HTML?的區(qū)別
XML文檔示例
<?xml version="1.0" encoding="utf-8"?><bookstore> <book category="cooking"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="children"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="web"> <title lang="en">XQuery Kick Start</title> <author>James McGovern</author> <author>Per Bothner</author> <author>Kurt Cagle</author> <author>James Linn</author> <author>Vaidyanathan Nagarajan</author> <year>2003</year> <price>49.99</price> </book> <book category="web" cover="paperback"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> </bookstore>HTML?DOM?模型示例
HTML?DOM?定義了訪問和操作?HTML?文檔的標(biāo)準(zhǔn)方法,以樹結(jié)構(gòu)方式表達(dá)?HTML?文檔。
?
XML的節(jié)點(diǎn)關(guān)系
1.?父(Parent)
?
每個元素以及屬性都有一個父。
?
下面是一個簡單的XML例子中,book?元素是?title、author、year?以及?price?元素的父:
<?xml?version="1.0"?encoding="utf-8"?><book><title>Harry?Potter</title><author>J?K.?Rowling</author><year>2005</year><price>29.99</price> </book>?
2.?子(Children)
元素節(jié)點(diǎn)可有零個、一個或多個子。
在下面的例子中,title、author、year?以及?price?元素都是?book?元素的子:
<?xml?version="1.0"?encoding="utf-8"?><book><title>Harry?Potter</title><author>J?K.?Rowling</author><year>2005</year><price>29.99</price></book>3.?同胞(Sibling)
擁有相同的父的節(jié)點(diǎn)
在下面的例子中,title、author、year?以及?price?元素都是同胞:
<?xml?version="1.0"?encoding="utf-8"?><book><title>Harry?Potter</title><author>J?K.?Rowling</author><year>2005</year><price>29.99</price></book>4.?先輩(Ancestor)
某節(jié)點(diǎn)的父、父的父,等等。
在下面的例子中,title?元素的先輩是?book?元素和?bookstore?元素:
<?xml?version="1.0"?encoding="utf-8"?><bookstore><book><title>Harry?Potter</title><author>J?K.?Rowling</author><year>2005</year><price>29.99</price></book></bookstore>5.?后代(Descendant)
某個節(jié)點(diǎn)的子,子的子,等等。
在下面的例子中,bookstore?的后代是?book、title、author、year?以及?price?元素:
<?xml?version="1.0"?encoding="utf-8"?><bookstore><book><title>Harry?Potter</title><author>J?K.?Rowling</author><year>2005</year><price>29.99</price></book></bookstore>?
什么是XPath?
XPath?(XML?Path?Language)?是一門在?XML?文檔中查找信息的語言,可用來在?XML?文檔中對元素和屬性進(jìn)行遍歷。
W3School官方文檔:http://www.w3school.com.cn/xpath/index.asp
?
XPath?開發(fā)工具
開源的XPath表達(dá)式編輯工具:XMLQuire(XML格式文件可用)
Chrome插件?XPath?Helper
Firefox插件?XPath?Checker
選取節(jié)點(diǎn)
?
XPath?使用路徑表達(dá)式來選取?XML?文檔中的節(jié)點(diǎn)或者節(jié)點(diǎn)集。
這些路徑表達(dá)式和我們在常規(guī)的電腦文件系統(tǒng)中看到的表達(dá)式非常相似。
?
路徑表達(dá)式:
在下面的表格中,我們已列出了一些路徑表達(dá)式:
謂語(Predicates)
?
謂語用來查找某個特定的節(jié)點(diǎn)或者包含某個指定的值的節(jié)點(diǎn),被嵌在方括號中。
在下面的表格中,我們列出了帶有謂語的一些路徑表達(dá)式,以及表達(dá)式的結(jié)果:
選取未知節(jié)點(diǎn)
XPath?通配符可用來選取未知的?XML?元素。
在下面的表格中,我們列出了一些路徑表達(dá)式,以及這些表達(dá)式的結(jié)果:
?
選取若干路徑
?
通過在路徑表達(dá)式中使用“|”運(yùn)算符,您可以選取若干個路徑。
實(shí)例
在下面的表格中,我們列出了一些路徑表達(dá)式,以及這些表達(dá)式的結(jié)果:
下面列出了可用在?XPath?表達(dá)式中的運(yùn)算符:
?
這些就是XPath的語法內(nèi)容,在運(yùn)用到Python抓取時要先轉(zhuǎn)換為xml。
?
XPath實(shí)例測試
?
1.?獲取所有的?<li>?標(biāo)簽
#?xpath_li.pyfrom?lxml?import?etreehtml?=?etree.parse('hello.html') print?type(html)??#?顯示etree.parse()?返回類型result?=?html.xpath('//li')print?result??#?打印<li>標(biāo)簽的元素集合 print?len(result) print?type(result) print?type(result[0])?
輸出結(jié)果:
?
<type?'lxml.etree._ElementTree'>
[<Element?li?at?0x1014e0e18>,?<Element?li?at?0x1014e0ef0>,?<Element?li?at?0x1014e0f38>,?<Element?li?at?0x1014e0f80>,?<Element?li?at?0x1014e0fc8>]
5
<type?'list'>
<type?'lxml.etree._Element'>
2.?繼續(xù)獲取<li>?標(biāo)簽的所有?class屬性
#?xpath_li.pyfrom?lxml?import?etreehtml?=?etree.parse('hello.html') result?=?html.xpath('//li/@class')print?result運(yùn)行結(jié)果
['item-0',?'item-1',?'item-inactive',?'item-1',?'item-0']
?
3.?繼續(xù)獲取<li>標(biāo)簽下hre?為?link1.html?的?<a>?標(biāo)簽
#?xpath_li.pyfrom?lxml?import?etreehtml?=?etree.parse('hello.html') result?=?html.xpath('//li/a[@href="link1.html"]')print?result運(yùn)行結(jié)果
[<Element?a?at?0x10ffaae18>]
?
4.?獲取<li>?標(biāo)簽下的所有?<span>?標(biāo)簽
#?xpath_li.pyfrom?lxml?import?etreehtml?=?etree.parse('hello.html')#result?=?html.xpath('//li/span')?
#注意這么寫是不對的:
#因?yàn)?/?是用來獲取子元素的,而?<span>?并不是?<li>?的子元素,所以,要用雙斜杠
result?=?html.xpath('//li//span')
print?result
運(yùn)行結(jié)果
[<Element?span?at?0x10d698e18>]
5.?獲取?<li>?標(biāo)簽下的<a>標(biāo)簽里的所有?class
#?xpath_li.pyfrom?lxml?import?etreehtml?=?etree.parse('hello.html') result?=?html.xpath('//li/a//@class')print?result運(yùn)行結(jié)果
['blod']
?
6.?獲取最后一個?<li>?的?<a>?的?href
#?xpath_li.pyfrom?lxml?import?etreehtml?=?etree.parse('hello.html')result?=?html.xpath('//li[last()]/a/@href') #?謂語?[last()]?可以找到最后一個元素 print?result運(yùn)行結(jié)果
['link5.html']
?
7.?獲取倒數(shù)第二個元素的內(nèi)容
#?xpath_li.pyfrom?lxml?import?etreehtml?=?etree.parse('hello.html') result?=?html.xpath('//li[last()-1]/a')#?text?方法可以獲取元素內(nèi)容 print?result[0].text運(yùn)行結(jié)果
fourth?item
?
8.?獲取?class?值為?bold?的標(biāo)簽名
#?xpath_li.pyfrom?lxml?import?etreehtml?=?etree.parse('hello.html')result?=?html.xpath('//*[@class="bold"]')#?tag方法可以獲取標(biāo)簽名 print?result[0].tag運(yùn)行結(jié)果
span
?
使用XPath的爬蟲
?
現(xiàn)在我們用XPath來做一個簡單的爬蟲,我們嘗試爬取某個貼吧里的所有帖子,并且將該這個帖子里每個樓層發(fā)布的圖片下載到本地。
?
?
# tieba_xpath.py#!/usr/bin/env python # -*- coding:utf-8 -*-import os import urllib import urllib2 from lxml import etreeclass Spider:def __init__(self):self.tiebaName = raw_input("請需要訪問的貼吧:")self.beginPage = int(raw_input("請輸入起始頁:"))self.endPage = int(raw_input("請輸入終止頁:"))self.url = 'http://tieba.baidu.com/f'self.ua_header = {"User-Agent" : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1 Trident/5.0;"}# 圖片編號self.userName = 1def tiebaSpider(self):for page in range(self.beginPage, self.endPage + 1):pn = (page - 1) * 50 # page numberword = {'pn' : pn, 'kw': self.tiebaName}word = urllib.urlencode(word) #轉(zhuǎn)換成url編碼格式(字符串)myUrl = self.url + "?" + word# 示例:http://tieba.baidu.com/f? kw=%E7%BE%8E%E5%A5%B3 & pn=50# 調(diào)用 頁面處理函數(shù) load_Page# 并且獲取頁面所有帖子鏈接,links = self.loadPage(myUrl) # urllib2_test3.py# 讀取頁面內(nèi)容def loadPage(self, url):req = urllib2.Request(url, headers = self.ua_header)html = urllib2.urlopen(req).read()# 解析html 為 HTML 文檔selector=etree.HTML(html)#抓取當(dāng)前頁面的所有帖子的url的后半部分,也就是帖子編號# http://tieba.baidu.com/p/4884069807里的 “p/4884069807”links = selector.xpath('//div[@class="threadlist_lz clearfix"]/div/a/@href')# links 類型為 etreeElementString 列表# 遍歷列表,并且合并成一個帖子地址,調(diào)用 圖片處理函數(shù) loadImagefor link in links:link = "http://tieba.baidu.com" + linkself.loadImages(link)# 獲取圖片def loadImages(self, link):req = urllib2.Request(link, headers = self.ua_header)html = urllib2.urlopen(req).read()selector = etree.HTML(html)# 獲取這個帖子里所有圖片的src路徑imagesLinks = selector.xpath('//img[@class="BDE_Image"]/@src')# 依次取出圖片路徑,下載保存for imagesLink in imagesLinks:self.writeImages(imagesLink)# 保存頁面內(nèi)容def writeImages(self, imagesLink):'''將 images 里的二進(jìn)制內(nèi)容存入到 userNname 文件中'''print imagesLinkprint "正在存儲文件 %d ..." % self.userName# 1. 打開文件,返回一個文件對象file = open('./images/' + str(self.userName) + '.png', 'wb')# 2. 獲取圖片里的內(nèi)容images = urllib2.urlopen(imagesLink).read()# 3. 調(diào)用文件對象write() 方法,將page_html的內(nèi)容寫入到文件里file.write(images)# 4. 最后關(guān)閉文件file.close()# 計數(shù)器自增1self.userName += 1# 模擬 main 函數(shù) if __name__ == "__main__":# 首先創(chuàng)建爬蟲對象mySpider = Spider()# 調(diào)用爬蟲對象的方法,開始工作mySpider.tiebaSpider()運(yùn)行效果:
總結(jié)
以上是生活随笔為你收集整理的XPath:爬取百度贴吧图片,并保存本地的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机考研复试---英文问题
- 下一篇: 如何对纸质文档进行数字化处理