數據解析三種方式
引言:回顧requests實現數據爬取的流程
- 指定url
- 基于requests模塊發起請求
- 獲取響應對象中的數據
- 進行持久化存儲
其實,在上述流程中還需要較為重要的一步,就是在持久化存儲之前需要進行指定數據解析。因為大多數情況下的需求,我們都會指定去使用聚焦爬蟲,也就是爬取頁面中指定部分的數據值,而不是整個頁面的數據。因此,本次課程中會給大家詳細介紹講解三種聚焦爬蟲中的數據解析方式。至此,我們的數據爬取的流程可以修改為:
- 指定url
- 基于requests模塊發起請求
- 獲取響應中的數據
- 數據解析
- 進行持久化存儲
一.正解解析
- 常用正則表達式回顧:
單字符:. : 除換行以外所有字符[] :[aoe] [a-w] 匹配集合中任意一個字符\d :數字 [0-9]\D : 非數字\w :數字、字母、下劃線、中文\W : 非\w\s :所有的空白字符包,括空格、制表符、換頁符等等。等價于 [ \f\n\r\t\v]。\S : 非空白數量修飾:* : 任意多次 >=0+ : 至少1次 >=1? : 可有可無 0次或者1次{m} :固定m次 hello{3,}{m,} :至少m次{m,n} :m-n次邊界:$ : 以某某結尾 ^ : 以某某開頭分組:(ab) 貪婪模式: .*非貪婪(惰性)模式: .*?re.I : 忽略大小寫re.M :多行匹配re.S :單行匹配re.sub(正則表達式, 替換內容, 字符串)
- 回顧練習:
import re
#提取出python
key="javapythonc++php"
re.findall('python',key)[0]
#####################################################################
#提取出hello world
key="<html><h1>hello world<h1></html>"
re.findall('<h1>(.*)<h1>',key)[0]
#####################################################################
#提取170
string = '我喜歡身高為170的女孩'
re.findall('\d+',string)
#####################################################################
#提取出http://和https://
key='http://www.baidu.com and https://boob.com'
re.findall('https?://',key)
#####################################################################
#提取出hello
key='lalala<hTml>hello</HtMl>hahah' #輸出<hTml>hello</HtMl>
re.findall('<[Hh][Tt][mM][lL]>(.*)</[Hh][Tt][mM][lL]>',key)
#####################################################################
#提取出hit.
key='bobo@hit.edu.com'#想要匹配到hit.
re.findall('h.*?\.',key)
#####################################################################
#匹配sas和saas
key='saas and sas and saaas'
re.findall('sa{1,2}s',key)
#####################################################################
#匹配出i開頭的行
string = '''fall in love with you
i love you very much
i love she
i love her'''re.findall('^.*',string,re.M)
#####################################################################
#匹配全部行
string1 = """<div>靜夜思
窗前明月光
疑是地上霜
舉頭望明月
低頭思故鄉
</div>"""re.findall('.*',string1,re.S)
- 項目需求:爬取糗事百科指定頁面的糗圖,并將其保存到指定文件夾中
#!/usr/bin/env python # -*- coding:utf-8 -*- import requests import re import os if __name__ == "__main__":url = 'https://www.qiushibaike.com/pic/%s/'headers={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',}#指定起始也結束頁碼page_start = int(input('enter start page:'))page_end = int(input('enter end page:'))#創建文件夾if not os.path.exists('images'):os.mkdir('images')#循環解析且下載指定頁碼中的圖片數據for page in range(page_start,page_end+1):print('正在下載第%d頁圖片'%page)new_url = format(url % page)response = requests.get(url=new_url,headers=headers)#解析response中的圖片鏈接e = '<div class="thumb">.*?<img src="(.*?)".*?>.*?</div>'pa = re.compile(e,re.S)image_urls = pa.findall(response.text)#循環下載該頁碼下所有的圖片數據for image_url in image_urls:image_url = 'https:' + image_urlimage_name = image_url.split('/')[-1]image_path = 'images/'+image_nameimage_data = requests.get(url=image_url,headers=headers).contentwith open(image_path,'wb') as fp:fp.write(image_data)
?
二.Xpath解析
- 測試頁面數據
<html lang="en">
<head><meta charset="UTF-8" /><title>測試bs4</title>
</head>
<body><div><p>百里守約</p></div><div class="song"><p>李清照</p><p>王安石</p><p>蘇軾</p><p>柳宗元</p><a href="http://www.song.com/" title="趙匡胤" target="_self"><span>this is span</span>宋朝是最強大的王朝,不是軍隊的強大,而是經濟很強大,國民都很有錢</a><a href="" class="du">總為浮云能蔽日,長安不見使人愁</a><img src="http://www.baidu.com/meinv.jpg" alt="" /></div><div class="tang"><ul><li><a href="http://www.baidu.com" title="qing">清明時節雨紛紛,路上行人欲斷魂,借問酒家何處有,牧童遙指杏花村</a></li><li><a href="http://www.163.com" title="qin">秦時明月漢時關,萬里長征人未還,但使龍城飛將在,不教胡馬度陰山</a></li><li><a href="http://www.126.com" alt="qi">岐王宅里尋常見,崔九堂前幾度聞,正是江南好風景,落花時節又逢君</a></li><li><a href="http://www.sina.com" class="du">杜甫</a></li><li><a href="http://www.dudu.com" class="du">杜牧</a></li><li><b>杜小月</b></li><li><i>度蜜月</i></li><li><a href="http://www.haha.com" id="feng">鳳凰臺上鳳凰游,鳳去臺空江自流,吳宮花草埋幽徑,晉代衣冠成古丘</a></li></ul></div>
</body>
</html>
- 常用xpath表達式回顧
屬性定位:#找到class屬性值為song的div標簽//div[@class="song"]
層級&索引定位:#找到class屬性值為tang的div的直系子標簽ul下的第二個子標簽li下的直系子標簽a//div[@class="tang"]/ul/li[2]/a
邏輯運算:#找到href屬性值為空且class屬性值為du的a標簽//a[@href="" and @class="du"]
模糊匹配://div[contains(@class, "ng")]//div[starts-with(@class, "ta")]
取文本:# /表示獲取某個標簽下的文本內容# //表示獲取某個標簽下的文本內容和所有子標簽下的文本內容//div[@class="song"]/p[1]/text()//div[@class="tang"]//text()
取屬性://div[@class="tang"]//li[2]/a/@href
- 代碼中使用xpath表達式進行數據解析:
1.下載:pip install lxml
2.導包:from lxml import etree3.將html文檔或者xml文檔轉換成一個etree對象,然后調用對象中的方法查找指定的節點2.1 本地文件:tree = etree.parse(文件名)tree.xpath("xpath表達式")2.2 網絡數據:tree = etree.HTML(網頁內容字符串)tree.xpath("xpath表達式")
- 安裝xpath插件在瀏覽器中對xpath表達式進行驗證:可以在插件中直接執行xpath表達式
-
將xpath插件拖動到谷歌瀏覽器拓展程序(更多工具)中,安裝成功
-
?
啟動和關閉插件 ctrl + shift + x
-
-
項目需求:獲取好段子中段子的內容和作者? ?http://www.haoduanzi.com
from lxml import etree import requestsurl='http://www.haoduanzi.com/category-10_2.html' headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36',} url_content=requests.get(url,headers=headers).text #使用xpath對url_conten進行解析 #使用xpath解析從網絡上獲取的數據 tree=etree.HTML(url_content) #解析獲取當頁所有段子的標題 title_list=tree.xpath('//div[@class="log cate10 auth1"]/h3/a/text()')ele_div_list=tree.xpath('//div[@class="log cate10 auth1"]')text_list=[] #最終會存儲12個段子的文本內容 for ele in ele_div_list:#段子的文本內容(是存放在list列表中)text_list=ele.xpath('./div[@class="cont"]//text()')#list列表中的文本內容全部提取到一個字符串中text_str=str(text_list)#字符串形式的文本內容防止到all_text列表中text_list.append(text_str) print(title_list) print(text_list)
三.BeautifulSoup解析
- 環境安裝
- 需要將pip源設置為國內源,阿里源、豆瓣源、網易源等- windows(1)打開文件資源管理器(文件夾地址欄中)(2)地址欄上面輸入 %appdata%(3)在這里面新建一個文件夾 pip(4)在pip文件夾里面新建一個文件叫做 pip.ini ,內容寫如下即可[global]timeout = 6000index-url = https://mirrors.aliyun.com/pypi/simple/trusted-host = mirrors.aliyun.com- linux(1)cd ~(2)mkdir ~/.pip(3)vi ~/.pip/pip.conf(4)編輯內容,和windows一模一樣
- 需要安裝:pip install bs4bs4在使用時候需要一個第三方庫,把這個庫也安裝一下pip install lxml
- 基礎使用
使用流程: - 導包:from bs4 import BeautifulSoup- 使用方式:可以將一個html文檔,轉化為BeautifulSoup對象,然后通過對象的方法或者屬性去查找指定的節點內容(1)轉化本地文件:- soup = BeautifulSoup(open('本地文件'), 'lxml')(2)轉化網絡文件:- soup = BeautifulSoup('字符串類型或者字節類型', 'lxml')(3)打印soup對象顯示內容為html文件中的內容基礎鞏固:(1)根據標簽名查找- soup.a 只能找到第一個符合要求的標簽(2)獲取屬性- soup.a.attrs 獲取a所有的屬性和屬性值,返回一個字典- soup.a.attrs['href'] 獲取href屬性- soup.a['href'] 也可簡寫為這種形式(3)獲取內容- soup.a.string- soup.a.text- soup.a.get_text()【注意】如果標簽還有標簽,那么string獲取到的結果為None,而其它兩個,可以獲取文本內容(4)find:找到第一個符合要求的標簽- soup.find('a') 找到第一個符合要求的- soup.find('a', title="xxx")- soup.find('a', alt="xxx")- soup.find('a', class_="xxx")- soup.find('a', id="xxx")(5)find_all:找到所有符合要求的標簽- soup.find_all('a')- soup.find_all(['a','b']) 找到所有的a和b標簽- soup.find_all('a', limit=2) 限制前兩個(6)根據選擇器選擇指定的內容select:soup.select('#feng')- 常見的選擇器:標簽選擇器(a)、類選擇器(.)、id選擇器(#)、層級選擇器- 層級選擇器:div .dudu #lala .meme .xixi 下面好多級div > p > a > .lala 只能是下面一級【注意】select選擇器返回永遠是列表,需要通過下標提取指定的對象
- 需求:使用bs4實現將詩詞名句網站中三國演義小說的每一章的內容爬去到本地磁盤進行存儲? ?http://www.shicimingju.com/book/sanguoyanyi.html
#!/usr/bin/env python # -*- coding:utf-8 -*- import requests from bs4 import BeautifulSoupheaders={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',} def parse_content(url):#獲取標題正文頁數據page_text = requests.get(url,headers=headers).textsoup = BeautifulSoup(page_text,'lxml')#解析獲得標簽ele = soup.find('div',class_='chapter_content')content = ele.text #獲取標簽中的數據值return contentif __name__ == "__main__":url = 'http://www.shicimingju.com/book/sanguoyanyi.html'reponse = requests.get(url=url,headers=headers)page_text = reponse.text#創建soup對象soup = BeautifulSoup(page_text,'lxml')#解析數據a_eles = soup.select('.book-mulu > ul > li > a')print(a_eles)cap = 1for ele in a_eles:print('開始下載第%d章節'%cap)cap+=1title = ele.stringcontent_url = 'http://www.shicimingju.com'+ele['href']content = parse_content(content_url)with open('./sanguo.txt','w') as fp:fp.write(title+":"+content+'\n\n\n\n\n')print('結束下載第%d章節'%cap)