一赵辕、爬蟲是什么?
如果我們把互聯(lián)網(wǎng)比作一張大的蜘蛛網(wǎng)啊研,數(shù)據(jù)便是存放于蜘蛛網(wǎng)的各個節(jié)點(diǎn),而爬蟲就是一只小蜘蛛,
沿著網(wǎng)絡(luò)抓取自己的獵物(數(shù)據(jù))爬蟲指的是:向網(wǎng)站發(fā)起請求恍飘,獲取資源后分析并提取有用數(shù)據(jù)的程序;
從技術(shù)層面來說就是通過程序模擬瀏覽器請求站點(diǎn)的行為谴垫,把站點(diǎn)返回的HTML代碼/JSON數(shù)據(jù)/二進(jìn)制數(shù)據(jù)(圖片章母、視頻) 爬到本地,進(jìn)而提取自己需要的數(shù)據(jù)翩剪,存放起來使用乳怎;
?
二、爬蟲的基本流程:
用戶獲取網(wǎng)絡(luò)數(shù)據(jù)的方式:
方式1:瀏覽器提交請求--->下載網(wǎng)頁代碼--->解析成頁面
方式2:模擬瀏覽器發(fā)送請求(獲取網(wǎng)頁代碼)->提取有用的數(shù)據(jù)->存放于數(shù)據(jù)庫或文件中
爬蟲要做的就是方式2前弯;
1蚪缀、發(fā)起請求
使用http庫向目標(biāo)站點(diǎn)發(fā)起請求,即發(fā)送一個Request
Request包含:請求頭恕出、請求體等?
Request模塊缺陷:不能執(zhí)行JS 和CSS 代碼
2询枚、獲取響應(yīng)內(nèi)容
如果服務(wù)器能正常響應(yīng),則會得到一個Response
Response包含:html浙巫,json金蜀,圖片刷后,視頻等
3、解析內(nèi)容
解析html數(shù)據(jù):正則表達(dá)式(RE模塊)渊抄,第三方解析庫如Beautifulsoup尝胆,pyquery等
解析json數(shù)據(jù):json模塊
解析二進(jìn)制數(shù)據(jù):以wb的方式寫入文件
4拟枚、保存數(shù)據(jù)
數(shù)據(jù)庫(MySQL鹉动,Mongdb、Redis)
文件
三姥闭、http協(xié)議 請求與響應(yīng)
Request:用戶將自己的信息通過瀏覽器(socket client)發(fā)送給服務(wù)器(socket server)
Response:服務(wù)器接收請求嘶炭,分析用戶發(fā)來的請求信息抱慌,然后返回?cái)?shù)據(jù)(返回的數(shù)據(jù)中可能包含其他鏈接,如:圖片眨猎,js抑进,css等)
ps:瀏覽器在接收Response后,會解析其內(nèi)容來顯示給用戶睡陪,而爬蟲程序在模擬瀏覽器發(fā)送請求然后接收Response后寺渗,是要提取其中的有用數(shù)據(jù)。
四兰迫、request
1信殊、請求方式:
常見的請求方式:GET / POST
2、請求的URL
url全球統(tǒng)一資源定位符汁果,用來定義互聯(lián)網(wǎng)上一個唯一的資源 例如:一張圖片涡拘、一個文件、一段視頻都可以用url唯一確定
url編碼
https://www.baidu.com/s?wd=圖片
圖片會被編碼(看示例代碼)
網(wǎng)頁的加載過程是:
加載一個網(wǎng)頁据德,通常都是先加載document文檔鳄乏,
在解析document文檔的時候,遇到鏈接棘利,則針對超鏈接發(fā)起下載圖片的請求
3橱野、請求頭
User-agent:請求頭中如果沒有user-agent客戶端配置,服務(wù)端可能將你當(dāng)做一個非法用戶host善玫;
cookies:cookie用來保存登錄信息
注意:一般做爬蟲都會加上請求頭
請求頭需要注意的參數(shù):
(1)Referrer:訪問源至哪里來(一些大型網(wǎng)站水援,會通過Referrer 做防盜鏈策略;所有爬蟲也要注意模擬)
(2)User-Agent:訪問的瀏覽器(要加上否則會被當(dāng)成爬蟲程序)
(3)cookie:請求頭注意攜帶
4茅郎、請求體
請求體
如果是get方式蜗元,請求體沒有內(nèi)容(get請求的請求體放在 url后面參數(shù)中,直接能看到)
如果是post方式系冗,請求體是format data
????ps:
????1奕扣、登錄窗口,文件上傳等毕谴,信息都會被附加到請求體內(nèi)
????2成畦、登錄,輸入錯誤的用戶名密碼涝开,然后提交循帐,就可以看到post,正確登錄后頁面通常會跳轉(zhuǎn)舀武,無法捕捉到post
五拄养、響應(yīng)Response
1、響應(yīng)狀態(tài)碼
200:代表成功
301:代表跳轉(zhuǎn)
404:文件不存在
403:無權(quán)限訪問
502:服務(wù)器錯誤
2银舱、respone header
響應(yīng)頭需要注意的參數(shù):
(1)Set-Cookie:BDSVRTM=0; path=/:可能有多個瘪匿,是來告訴瀏覽器,把cookie保存下來
(2)Content-Location:服務(wù)端響應(yīng)頭中包含Location返回瀏覽器之后寻馏,瀏覽器就會重新訪問另一個頁面
3棋弥、preview就是網(wǎng)頁源代碼
JSO數(shù)據(jù)
如網(wǎng)頁html,圖片
二進(jìn)制數(shù)據(jù)等
六诚欠、總結(jié)
1顽染、總結(jié)爬蟲流程:
?爬取--->解析--->存儲
2、爬蟲所需工具:
?請求庫:requests,selenium(可以驅(qū)動瀏覽器解析渲染CSS和JS轰绵,但有性能劣勢(有用沒用的網(wǎng)頁都會加載)粉寞;)?解析庫:正則,beautifulsoup左腔,pyquery?存儲庫:文件唧垦,MySQL,Mongodb液样,Redis
3振亮、爬獲校花網(wǎng)
最后送給大家點(diǎn)福利吧
基礎(chǔ)版:
import reimport requests
respose=requests.get('http://www.xiaohuar.com/v/')# print(respose.status_code)# 響應(yīng)的狀態(tài)碼# print(respose.content)? #返回字節(jié)信息# print(respose.text)? #返回文本內(nèi)容urls=re.findall(r'class="items".*?href="(.*?)"',respose.text,re.S)#re.S 把文本信息轉(zhuǎn)換成1行匹配url=urls[5]
result=requests.get(url)
mp4_url=re.findall(r'id="media".*?src="(.*?)"',result.text,re.S)[0]
video=requests.get(mp4_url)
with open('D:\\a.mp4','wb') as f:
? ? f.write(video.content)
函數(shù)封裝版
import reimport requestsimport hashlibimport time# respose=requests.get('http://www.xiaohuar.com/v/')# # print(respose.status_code)# 響應(yīng)的狀態(tài)碼# # print(respose.content)? #返回字節(jié)信息# # print(respose.text)? #返回文本內(nèi)容# urls=re.findall(r'class="items".*?href="(.*?)"',respose.text,re.S)? #re.S 把文本信息轉(zhuǎn)換成1行匹配# url=urls[5]# result=requests.get(url)# mp4_url=re.findall(r'id="media".*?src="(.*?)"',result.text,re.S)[0]#
# video=requests.get(mp4_url)#
# with open('D:\\a.mp4','wb') as f:#? ? f.write(video.content)#def get_index(url):
? ? respose = requests.get(url)
? ? ifrespose.status_code==200:
? ? ? ? return respose.textdef parse_index(res):
? ? urls = re.findall(r'class="items".*?href="(.*?)"', res,re.S)# re.S 把文本信息轉(zhuǎn)換成1行匹配return urlsdef get_detail(urls):
? ? forurlin urls:
? ? ? ? ifnoturl.startswith('http'):
? ? ? ? ? ? url='http://www.xiaohuar.com%s'%url
? ? ? ? result = requests.get(url)
? ? ? ? ifresult.status_code==200 :
? ? ? ? ? ? mp4_url_list = re.findall(r'id="media".*?src="(.*?)"', result.text, re.S)
? ? ? ? ? ? if mp4_url_list:
? ? ? ? ? ? ? ? mp4_url=mp4_url_list[0]
? ? ? ? ? ? ? ? print(mp4_url)
? ? ? ? ? ? ? ? # save(mp4_url)def save(url):
? ? video = requests.get(url)
? ? ifvideo.status_code==200:
? ? ? ? m=hashlib.md5()
? ? ? ? m.updata(url.encode('utf-8'))
? ? ? ? m.updata(str(time.time()).encode('utf-8'))
? ? ? ? filename=r'%s.mp4'% m.hexdigest()
? ? ? ? filepath=r'D:\\%s'%filename
? ? ? ? with open(filepath, 'wb') as f:
? ? ? ? ? ? f.write(video.content)def main():
? ? foriinrange(5):
? ? ? ? res1 = get_index('http://www.xiaohuar.com/list-3-%s.html'% i )
? ? ? ? res2 = parse_index(res1)
? ? ? ? get_detail(res2)if__name__=='__main__':
? ? main()
并發(fā)版(如果一共需要爬30個視頻蓄愁,開30個線程去做双炕,花的時間就是 其中最慢那份的耗時時間)
import reimport requestsimport hashlibimport timefromconcurrent.futuresimport ThreadPoolExecutor
p=ThreadPoolExecutor(30)#創(chuàng)建1個程池中,容納線程個數(shù)為30個撮抓;def get_index(url):
? ? respose = requests.get(url)
? ? ifrespose.status_code==200:
? ? ? ? return respose.textdef parse_index(res):
? ? res=res.result()#進(jìn)程執(zhí)行完畢后妇斤,得到1個對象urls = re.findall(r'class="items".*?href="(.*?)"', res,re.S)# re.S 把文本信息轉(zhuǎn)換成1行匹配forurlin urls:
? ? ? ? p.submit(get_detail(url))? #獲取詳情頁 提交到線程池defget_detail(url):#只下載1個視頻ifnoturl.startswith('http'):
? ? ? ? ? ? url='http://www.xiaohuar.com%s'%url
? ? ? ? result = requests.get(url)
? ? ? ? ifresult.status_code==200 :
? ? ? ? ? ? mp4_url_list = re.findall(r'id="media".*?src="(.*?)"', result.text, re.S)
? ? ? ? ? ? if mp4_url_list:
? ? ? ? ? ? ? ? mp4_url=mp4_url_list[0]
? ? ? ? ? ? ? ? print(mp4_url)
? ? ? ? ? ? ? ? # save(mp4_url)def save(url):
? ? video = requests.get(url)
? ? ifvideo.status_code==200:
? ? ? ? m=hashlib.md5()
? ? ? ? m.updata(url.encode('utf-8'))
? ? ? ? m.updata(str(time.time()).encode('utf-8'))
? ? ? ? filename=r'%s.mp4'% m.hexdigest()
? ? ? ? filepath=r'D:\\%s'%filename
? ? ? ? with open(filepath, 'wb') as f:
? ? ? ? ? ? f.write(video.content)def main():
? ? foriinrange(5):
? ? ? ? p.submit(get_index,'http://www.xiaohuar.com/list-3-%s.html'% i ).add_done_callback(parse_index)
? ? ? ? #1、先把爬主頁的任務(wù)(get_index)異步提交到線程池#2丹拯、get_index任務(wù)執(zhí)行完后站超,會通過回調(diào)函add_done_callback()數(shù)通知主線程,任務(wù)完成乖酬;#2死相、把get_index執(zhí)行結(jié)果(注意線程執(zhí)行結(jié)果是對象,調(diào)用res=res.result()方法咬像,才能獲取真正執(zhí)行結(jié)果)算撮,當(dāng)做參數(shù)傳給parse_index#3生宛、parse_index任務(wù)執(zhí)行完畢后,#4肮柜、通過循環(huán)陷舅,再次把獲取詳情頁 get_detail()任務(wù)提交到線程池執(zhí)行if__name__=='__main__':
? ? main()
涉及知識:多線程多進(jìn)程
計(jì)算密集型任務(wù):使用多進(jìn)程,因?yàn)槟躊ython有GIL审洞,多進(jìn)程可以利用上CPU多核優(yōu)勢莱睁;
IO密集型任務(wù):使用多線程,做IO切換節(jié)省任務(wù)執(zhí)行時間(并發(fā))
線程池
多說一句芒澜,很多人學(xué)Python過程中會遇到各種煩惱問題仰剿,沒有人解答容易放棄。小編是一名python開發(fā)工程師痴晦,這里有我自己整理了一套最新的python系統(tǒng)學(xué)習(xí)教程南吮,包括從基礎(chǔ)的python腳本到web開發(fā)、爬蟲誊酌、數(shù)據(jù)分析旨袒、數(shù)據(jù)可視化、機(jī)器學(xué)習(xí)等术辐。想要這些資料的可以關(guān)注小編砚尽,并在后臺私信小編:“01”即可領(lǐng)取。