Xpath解析器:
- 什么是XPath蚕礼?
XPath (XML Path Language) 是一門在 XML 文檔中查找信息的語言叶圃,可用來在 XML 文檔中對元素和屬性進(jì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)
選取節(jié)點(diǎn)
XPath 使用路徑表達(dá)式來選取 XML 文檔中的節(jié)點(diǎn)或者節(jié)點(diǎn)集抚吠。這些路徑表達(dá)式和我們在常規(guī)的電腦文件系統(tǒng)中看到的表達(dá)式非常相似。
- 下面列出了最常用的路徑表達(dá)式:
nodename :選取此節(jié)點(diǎn)的所有子節(jié)點(diǎn)弟胀。
/ :從根節(jié)點(diǎn)選取楷力。
// : 從匹配選擇的當(dāng)前節(jié)點(diǎn)選擇文檔中的節(jié)點(diǎn),而不考慮它們的位置孵户。
. : 選取當(dāng)前節(jié)點(diǎn)萧朝。
.. : 選取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)。
@ : 選取屬性夏哭。
在下面的表格中检柬,我們已列出了一些路徑表達(dá)式以及表達(dá)式的結(jié)果:
bookstore :選取 bookstore 元素的所有子節(jié)點(diǎn)。
/bookstore : 選取根元素 bookstore竖配。注釋:假如路徑起始于正斜杠( / )何址,則此路徑始終代表到某元素的絕對路徑!
bookstore/book : 選取屬于 bookstore 的子元素的所有 book 元素进胯。
//book : 選取所有 book 子元素用爪,而不管它們在文檔中的位置。
bookstore//book : 選擇屬于 bookstore 元素的后代的所有 book 元素龄减,而不管它們位于 bookstore 之下的什么位置项钮。
//@lang :選取名為 lang 的所有屬性。
- 小案例:
案例:使用XPath的爬蟲 現(xiàn)在我們用XPath來做一個簡單的爬蟲希停,我們嘗試爬取某個貼吧里的所有帖子烁巫,并且將該這個帖子里每個樓層發(fā)布的圖片下載到本地。
import requests
from lxml import etree
import json
class Tieba:
def __init__(self,tieba_name):
self.tieba_name = tieba_name #接收貼吧名
#設(shè)置為手機(jī)端的UA,也可以是指為瀏覽器的UA
self.headers = {"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"}
def get_total_url_list(self):
'''獲取所有的urllist'''
url = "https://tieba.baidu.com/f?kw="+self.tieba_name+"&ie=utf-8&pn={}&"
url_list = []
for i in range(100): #通過循環(huán)拼接100個url
url_list.append(url.format(i*50))
return url_list #返回100個url的urllist
def parse_url(self,url):
'''一個發(fā)送請求宠能,獲取響應(yīng)亚隙,同時etree處理html'''
print("parsing url:",url)
response = requests.get(url,headers=self.headers,timeout=10) #發(fā)送請求
html = response.content.decode() #獲取html字符串
html = etree.HTML(html) #獲取element 類型的html
return html
def get_title_href(self,url):
'''獲取一個頁面的title和href'''
html = self.parse_url(url)
li_temp_list = html.xpath("http://li[@class='tl_shadow']") #分組,按照li標(biāo)簽分組
total_items = []
for i in li_temp_list: #遍歷分組
href = "https:"+i.xpath("./a/@href")[0] if len(i.xpath("./a/@href"))>0 else None
text = i.xpath("./a/div[1]/span[1]/text()")
text = text[0] if len(text)>0 else None
item = dict( #放入字典
href = href,
text = text
)
total_items.append(item)
return total_items #返回一個頁面所有的item
def get_img(self,url):
'''獲取一個帖子里面的所有圖片'''
html = self.parse_url(url) #返回elemet累心的html违崇,具有xpath方法
img_list = html.xpath('//div[@data-class="BDE_Image"]/@data-url')
img_list = [i.split("src=")[-1] for i in img_list] #提取圖片的url
img_list = [requests.utils.unquote(i) for i in img_list]
return img_list
def save_item(self,item):
'''保存一個item'''
with open("teibatupian.txt","a") as f:
f.write(json.dumps(item,ensure_ascii=False,indent=2))
f.write("\n")
def run(self):
#1阿弃、找到了url規(guī)律诊霹,url list
url_list = self.get_total_url_list()
for url in url_list:
#2、遍歷urllist 發(fā)送請求渣淳,獲得響應(yīng)脾还,etree處理html
# 3、提取title入愧,href
total_item = self.get_title_href(url)
for item in total_item:
href = item["href"]
img_list = self.get_img(href) #獲取到了帖子的圖片列表
item["img"] = img_list
# 4鄙漏、保存到本地
print(item)
self.save_item(item)
if __name__ == "__main__":
tieba = Tieba("美女")
tieba.run()
BeautifulSoup4解析器
和 lxml 一樣,Beautiful Soup 也是一個HTML/XML的解析器棺蛛,主要的功能也是如何解析和提取 HTML/XML 數(shù)據(jù)怔蚌。
lxml 只會局部遍歷,而Beautiful Soup 是基于HTML DOM的旁赊,會載入整個文檔桦踊,解析整個DOM樹,因此時間和內(nèi)存開銷都會大很多终畅,所以性能要低于lxml籍胯。
BeautifulSoup 用來解析 HTML 比較簡單,API非常人性化声离,支持CSS選擇器芒炼、Python標(biāo)準(zhǔn)庫中的HTML解析器,也支持 lxml 的 XML解析器术徊。
Beautiful Soup 3 目前已經(jīng)停止開發(fā)本刽,推薦現(xiàn)在的項(xiàng)目使用Beautiful Soup 4。使用 pip 安裝即可:pip install beautifulsoup4
四大對象種類
Beautiful Soup將復(fù)雜HTML文檔轉(zhuǎn)換成一個復(fù)雜的樹形結(jié)構(gòu),每個節(jié)點(diǎn)都是Python對象,所有對象可以歸納為4種:
- Tag :Tag 通俗點(diǎn)講就是 HTML 中的一個個標(biāo)簽
- NavigableString
- BeautifulSoup:BeautifulSoup 對象表示的是一個文檔的內(nèi)容
- Comment:Comment 對象是一個特殊類型的 NavigableString 對象赠涮,其輸出的內(nèi)容不包括注釋符號子寓。
- 小案例
from bs4 import BeautifulSoup
import urllib
import json # 使用了json格式存儲
def tencent():
url = 'http://hr.tencent.com/'
request = urllib.request.Request(url + 'position.php?&start=10#a')
response =urllib.request.urlopen(request)
resHtml = response.read()
output =open('tencent.json','w')
html = BeautifulSoup(resHtml,'lxml')
# 創(chuàng)建CSS選擇器
result = html.select('tr[class="even"]')
result2 = html.select('tr[class="odd"]')
result += result2
items = []
for site in result:
item = {}
name = site.select('td a')[0].get_text()
detailLink = site.select('td a')[0].attrs['href']
catalog = site.select('td')[1].get_text()
recruitNumber = site.select('td')[2].get_text()
workLocation = site.select('td')[3].get_text()
publishTime = site.select('td')[4].get_text()
item['name'] = name
item['detailLink'] = url + detailLink
item['catalog'] = catalog
item['recruitNumber'] = recruitNumber
item['publishTime'] = publishTime
items.append(item)
# 禁用ascii編碼,按utf-8編碼
line = json.dumps(items,ensure_ascii=False)
output.write(line.encode('utf-8'))
output.close()
if __name__ == "__main__":
tencent()