什么叫“多任務(wù)”谓罗?
就是操作系統(tǒng)可以同時(shí)運(yùn)行多個(gè)任務(wù)。(至少同時(shí)有3個(gè)任務(wù)正在運(yùn)行)
單核CPU如何執(zhí)行多任務(wù)? 多核CPU如何執(zhí)行多任務(wù)铅忿?
真正的并行執(zhí)行多任務(wù)只能在多核CPU上實(shí)現(xiàn),但是灵汪,由于任務(wù)數(shù)量遠(yuǎn)遠(yuǎn)多于CPU的核心數(shù)量檀训,所以,操作系統(tǒng)也會(huì)自動(dòng)把很多任務(wù)輪流調(diào)度到每個(gè)核心上執(zhí)行享言。
并發(fā):指的是任務(wù)數(shù)多余cpu核數(shù)峻凫,通過(guò)操作系統(tǒng)的各種任務(wù)調(diào)度算法,實(shí)現(xiàn)用多個(gè)任務(wù)“一起”執(zhí)行
(實(shí)際上總有一些任務(wù)不在執(zhí)行览露,因?yàn)榍袚Q任務(wù)的速度相當(dāng)快荧琼,看上去一起執(zhí)行而已)
并行:指的是任務(wù)數(shù)小于等于cpu核數(shù),即任務(wù)真的是一起執(zhí)行的
線程:python的thread模塊是比較底層的模塊,python的threading模塊是對(duì)thread做了一些包裝的铭腕,可以更加方便的被使用
線程-注意點(diǎn):線程執(zhí)行代碼的封裝 通過(guò)上一小節(jié)银择,能夠看出,通過(guò)使用threading模塊能完成多任務(wù)的程序開(kāi)發(fā)累舷,為了讓每個(gè)線程的封裝性更完美浩考,所以使用threading模塊時(shí),往往會(huì)定義一個(gè)新的子類(lèi)class被盈,只要繼承threading.Thread就可以了析孽,然后重寫(xiě)run方法
進(jìn)程:一個(gè)程序運(yùn)行起來(lái)后,代碼+用到的資源 稱(chēng)之為進(jìn)程只怎,它是操作系統(tǒng)分配資源的基本單元袜瞬。
不僅可以通過(guò)線程完成多任務(wù),進(jìn)程也是可以的(進(jìn)程間不同享全局變量)
進(jìn)程的狀態(tài)
就緒態(tài):運(yùn)行的條件都已經(jīng)慢去身堡,正在等在cpu執(zhí)行
執(zhí)行態(tài):cpu正在執(zhí)行其功能
等待態(tài):等待某些條件滿足邓尤,例如一個(gè)程序sleep了,此時(shí)就處于等待態(tài)
進(jìn)程間通信-Queue
進(jìn)程池Pool
(1).當(dāng)需要?jiǎng)?chuàng)建的子進(jìn)程數(shù)量不多時(shí)贴谎,可以直接利用multiprocessing中的Process動(dòng)態(tài)成生多個(gè)進(jìn)程汞扎,但如果是上百甚至上千個(gè)目標(biāo),手動(dòng)的去創(chuàng)建進(jìn)程的工作量巨大擅这,此時(shí)就可以用到multiprocessing模塊提供的Pool方法澈魄。
(2).初始化Pool時(shí),可以指定一個(gè)最大進(jìn)程數(shù)仲翎,當(dāng)有新的請(qǐng)求提交到Pool中時(shí)痹扇,如果池還沒(méi)有滿,那么就會(huì)創(chuàng)建一個(gè)新的進(jìn)程用來(lái)執(zhí)行該請(qǐng)求溯香;但如果池中的進(jìn)程數(shù)已經(jīng)達(dá)到指定的最大值鲫构,那么該請(qǐng)求就會(huì)等待,直到池中有進(jìn)程結(jié)束逐哈,才會(huì)用之前的進(jìn)程來(lái)執(zhí)行新的任務(wù)
進(jìn)程與線程的對(duì)比:
(1).功能
進(jìn)程芬迄,能夠完成多任務(wù),比如 在一臺(tái)電腦上能夠同時(shí)運(yùn)行多個(gè)QQ
線程昂秃,能夠完成多任務(wù)禀梳,比如 一個(gè)QQ中的多個(gè)聊天窗口
(2).定義的不同
a).進(jìn)程是系統(tǒng)進(jìn)行資源分配基本單位.
b).線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.
c).線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線程共享所在進(jìn)程所擁有的全部資源
(3).區(qū)別
a).一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程.
b).線程的劃分尺度小于進(jìn)程(資源比進(jìn)程少),使得多線程程序的并發(fā)性高肠骆。
c).進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元算途,而多個(gè)線程共享內(nèi)存,從而極大地提高了程序的運(yùn)行效率
d).線線程不能夠獨(dú)立執(zhí)行蚀腿,必須依存在進(jìn)程中
(4).優(yōu)缺點(diǎn):線程和進(jìn)程在使用上各有優(yōu)缺點(diǎn):線程執(zhí)行開(kāi)銷(xiāo)小嘴瓤,但不利于資源的管理和保護(hù)扫外;而進(jìn)程正相反。
(5).使用場(chǎng)景:
a). 多進(jìn)程常用來(lái)處理計(jì)算密集型任務(wù): 計(jì)算密集型任務(wù)的特點(diǎn):是要進(jìn)行大量的計(jì)算廓脆,消耗CPU資源筛谚,比如計(jì)算圓周率、對(duì)視頻進(jìn)行高清解碼等等停忿,全靠CPU的運(yùn)算能力驾讲。計(jì)算密集型任務(wù)可以用多任務(wù)完成,但是任務(wù)越多席赂,花在任務(wù)切換的時(shí)間就越多吮铭,CPU執(zhí)行任務(wù)的效率就越低,所以颅停,要最高效地利用CPU谓晌,計(jì)算密集型任務(wù)同時(shí)進(jìn)行的數(shù)量應(yīng)當(dāng)?shù)扔贑PU的核心數(shù)。
b).多線程常用來(lái)處理IO密集型任務(wù): IO密集型:涉及到網(wǎng)絡(luò)癞揉、磁盤(pán)IO的任務(wù)都是IO密集型任務(wù)纸肉,特點(diǎn)是CPU消耗很少,任務(wù)的大部分時(shí)間都在等待IO操作完成(因?yàn)镮O的速度遠(yuǎn)遠(yuǎn)低于CPU和內(nèi)存的速度)喊熟。但是也要切記毁靶,在執(zhí)行多任務(wù)時(shí),并不是越多線程越好逊移。
互斥鎖:
(1).當(dāng)多個(gè)線程幾乎同時(shí)修改某一個(gè)共享數(shù)據(jù)的時(shí)候,需要進(jìn)行同步控制龙填,線程同步能夠保證多個(gè)線程安全訪問(wèn)競(jìng)爭(zhēng)資源胳泉,最簡(jiǎn)單的同步機(jī)制是引入互斥鎖。
(2).互斥鎖為資源引入一個(gè)狀態(tài):鎖定/非鎖定
(3).某個(gè)線程要更改共享數(shù)據(jù)時(shí)岩遗,先將其鎖定扇商,此時(shí)資源的狀態(tài)為“鎖定”,其他線程不能更改宿礁;直到該線程釋放資源案铺,將資源的狀態(tài)變成“非鎖定”,其他的線程才能再次鎖定該資源梆靖】睾海互斥鎖保證了每次只有一個(gè)線程進(jìn)行寫(xiě)入操作,從而保證了多線程情況下數(shù)據(jù)的正確性返吻。
注意:如果這個(gè)鎖之前是沒(méi)有上鎖的姑子,那么acquire不會(huì)堵塞
如果在調(diào)用acquire對(duì)這個(gè)鎖上鎖之前 它已經(jīng)被 其他線程上了鎖,那么此時(shí)acquire會(huì)堵塞测僵,直到這個(gè)鎖被解鎖為止街佑。
鎖的好處:確保了某段關(guān)鍵代碼只能由一個(gè)線程從頭到尾完整地執(zhí)行
鎖的壞處:
(1).阻止了多線程并發(fā)執(zhí)行,包含鎖的某段代碼實(shí)際上只能以單線程模式執(zhí)行,效率就大大地下降了
(2).由于可以存在多個(gè)鎖沐旨,不同的線程持有不同的鎖森逮,并試圖獲取對(duì)方持有的鎖時(shí),可能會(huì)造成死鎖
死鎖:在線程間共享多個(gè)資源的時(shí)候磁携,如果兩個(gè)線程分別占有一部分資源并且同時(shí)等待對(duì)方的資源褒侧,就會(huì)造成死鎖。
迭代器
迭代是訪問(wèn)集合元素的一種方式颜武。迭代器是一個(gè)可以記住遍歷的位置的對(duì)象璃搜。迭代器對(duì)象從集合的第一個(gè)元素開(kāi)始訪問(wèn),直到所有的元素被訪問(wèn)完結(jié)束鳞上。迭代器只能往前不會(huì)后退这吻。(一個(gè)實(shí)現(xiàn)了iter方法和next方法的對(duì)象,就是迭代器篙议。)
1. 可迭代對(duì)象: 我們已經(jīng)知道可以對(duì)list唾糯、tuple、str等類(lèi)型的數(shù)據(jù)使用for...in...的循環(huán)語(yǔ)法從其中依次拿到數(shù)據(jù)進(jìn)行使用鬼贱,我們把這樣的過(guò)程稱(chēng)為遍歷移怯,也叫迭代。
2. 可迭代對(duì)象的本質(zhì): 可迭代對(duì)象進(jìn)行迭代使用的過(guò)程这难,每迭代一次(即在for...in...中每循環(huán)一次)都會(huì)返回對(duì)象中的下一條數(shù)據(jù)舟误,一直向后讀取數(shù)據(jù)直到迭代了所有數(shù)據(jù)后結(jié)束。
可迭代對(duì)象通過(guò)iter方法向我們提供一個(gè)迭代器姻乓,我們?cè)诘粋€(gè)可迭代對(duì)象的時(shí)候嵌溢,實(shí)際上就是先獲取該對(duì)象提供的一個(gè)迭代器,然后通過(guò)這個(gè)迭代器來(lái)依次獲取對(duì)象中的每一個(gè)數(shù)據(jù).
一個(gè)具備了 iter 方法的對(duì)象蹋岩,就是一個(gè) 可迭代對(duì)象
3.iter()函數(shù)與next()函數(shù):
list赖草、tuple等都是可迭代對(duì)象,我們可以通過(guò)iter()函數(shù)獲取這些可迭代對(duì)象的迭代器剪个。然后我們可以對(duì)獲取到的迭代器不斷使用next()函數(shù)來(lái)獲取下一條數(shù)據(jù)秧骑。iter()函數(shù)實(shí)際上就是調(diào)用了可迭代對(duì)象的iter方法。
生成器
- 生成器 利用迭代器扣囊,我們可以在每次迭代獲取數(shù)據(jù)(通過(guò)next()方法)時(shí)按照特定的規(guī)律進(jìn)行生成乎折。但是我們?cè)趯?shí)現(xiàn)一個(gè)迭代器時(shí),關(guān)于當(dāng)前迭代到的狀態(tài)需要我們自己記錄如暖,進(jìn)而才能根據(jù)當(dāng)前狀態(tài)生成下一個(gè)數(shù)據(jù)笆檀。為了達(dá)到記錄當(dāng)前狀態(tài),并配合next()函數(shù)進(jìn)行迭代使用盒至,我們可以采用更簡(jiǎn)便的語(yǔ)法酗洒,即生成器(generator)士修。生成器是一類(lèi)特殊的迭代器。
2.創(chuàng)建生成器方法:在使用生成器實(shí)現(xiàn)的方式中樱衷,我們將原本在迭代器next方法中實(shí)現(xiàn)的基本邏輯放到一個(gè)函數(shù)中來(lái)實(shí)現(xiàn)棋嘲,但是將每次迭代返回?cái)?shù)值的return換成了yield,此時(shí)新定義的函數(shù)便不再是函數(shù)矩桂,而是一個(gè)生成器了沸移。簡(jiǎn)單來(lái)說(shuō):只要在def中有yield關(guān)鍵字的 就稱(chēng)為 生成器
協(xié)程
因?yàn)閰f(xié)程占用的資源非常少,資源保存在CPU寄存器的上下文中,
協(xié)程切換的速度非持读瘢快(比線程和進(jìn)程快),
當(dāng)遇到耗時(shí)操作時(shí),會(huì)先暫停,將資源保存(CPU寄存器的上下文中),
切換到其他協(xié)程中執(zhí)行其他任務(wù),一旦耗時(shí)操作執(zhí)行完畢,
會(huì)切換到之前的暫停的位置,繼續(xù)執(zhí)行
進(jìn)程是資源分配的單位
線程是操作系統(tǒng)調(diào)度的單位
進(jìn)程切換需要的資源很最大雹锣,效率很低
線程切換需要的資源一般,效率一般(當(dāng)然了在不考慮GIL的情況下)
協(xié)程切換任務(wù)資源很小癞蚕,效率高
多進(jìn)程蕊爵、多線程根據(jù)cpu核數(shù)不一樣可能是并行的,但是 協(xié)程 是在一個(gè) 線程中 所以是 并發(fā)的.
**Selenium **
我們使用的有界面瀏覽器桦山,它雖然方便我們觀察攒射,但是在實(shí)際運(yùn)用中是非常消耗性能的 我們也可以使用Chrome的無(wú)界面瀏覽器,除了沒(méi)有瀏覽器界面以外,其它的相關(guān)操作都與有界面瀏覽器相同
谷歌驅(qū)動(dòng)(chromedriver)下載地址: http://chromedriver.storage.googleapis.com/index.html
火狐驅(qū)動(dòng)下載路徑(GeckoDriver):https://github.com/mozilla/geckodriver/releases (2.3.8是最新的,下載的驅(qū)動(dòng)版本一定要支持你當(dāng)前的瀏覽器版本)
selenium不自帶瀏覽器,必須跟第三方的瀏覽器配合使用
(1).通關(guān)節(jié)點(diǎn)的name屬性查找對(duì)應(yīng)的節(jié)點(diǎn)
chrome_driver.find_element_by_name()
(2).通過(guò)節(jié)點(diǎn)的class_name找到對(duì)應(yīng)的節(jié)點(diǎn)
chrome_driver.find_element_by_class_name()
(3).通過(guò)css選擇器查找對(duì)應(yīng)的節(jié)點(diǎn)
chrome_driver.find_element_by_css_selector()
(4).通過(guò)連接所在標(biāo)簽的部分文字找到對(duì)應(yīng)的節(jié)點(diǎn)
chrome_driver.find_element_by_partial_link_text()
(5).通過(guò)xpath路徑找對(duì)對(duì)應(yīng)的節(jié)點(diǎn)
chrome_driver.find_element_by_xpath()
顯示等待:同樣可以指定一個(gè)等待時(shí)間,不過(guò)更加靈活,可以指定一個(gè)最長(zhǎng)等待時(shí)
將圖片轉(zhuǎn)換為灰度圖
image5 = image3.convert("L")
image5.save('l'+'captcha.jpeg')
圖片的二值化處理
設(shè)置圖片的伐值
pointvalue = 150
table = []
for i in range(256):
if i < pointvalue:
table.append(0)
else:
table.append(1)
Scrapy 框架:
(1).Scrapy是用純Python實(shí)現(xiàn)一個(gè)為了爬取網(wǎng)站數(shù)據(jù)恒水、提取結(jié)構(gòu)性數(shù)據(jù)而編寫(xiě)的應(yīng)用框架会放,用途非常廣泛。
(2).框架的力量钉凌,用戶只需要定制開(kāi)發(fā)幾個(gè)模塊就可以輕松的實(shí)現(xiàn)一個(gè)爬蟲(chóng)咧最,用來(lái)抓取網(wǎng)頁(yè)內(nèi)容以及各種圖片,非常之方便御雕。
(3).Scrapy 使用了 Twisted['tw?st?d] 異步網(wǎng)絡(luò)框架來(lái)處理網(wǎng)絡(luò)通訊窗市,可以加快我們的下載速度,不用自己去實(shí)現(xiàn)異步框架饮笛,并且包含了各種中間件接口,可以靈活的完成各種需求论熙。
異步:調(diào)用在發(fā)出之后福青,這個(gè)調(diào)用就直接返回,不管有無(wú)結(jié)果 非阻塞:關(guān)注的是程序在等待調(diào)用結(jié)果(消息脓诡,返回值)時(shí)的狀態(tài)无午,指在不能立刻得到結(jié)果之前,該調(diào)用不會(huì)阻塞當(dāng)前線程
Scrapy架構(gòu)圖:
Scrapy Engine(引擎): 負(fù)責(zé)Spider祝谚、ItemPipeline宪迟、Downloader、Scheduler中間的通訊交惯,信號(hào)次泽、數(shù)據(jù)傳遞等穿仪。
Scheduler(調(diào)度器): 它負(fù)責(zé)接受引擎發(fā)送過(guò)來(lái)的Request請(qǐng)求,并按照一定的方式進(jìn)行整理排列意荤,入隊(duì)啊片,當(dāng)引擎需要時(shí),交還給引擎玖像。
Downloader(下載器):負(fù)責(zé)下載Scrapy Engine(引擎)發(fā)送的所有Requests請(qǐng)求紫谷,并將其獲取到的Responses交還給Scrapy Engine(引擎),由引擎交給Spider來(lái)處理捐寥,
Spider(爬蟲(chóng)):它負(fù)責(zé)處理所有Responses,從中分析提取數(shù)據(jù)笤昨,獲取Item字段需要的數(shù)據(jù),并將需要跟進(jìn)的URL提交給引擎握恳,再次進(jìn)入Scheduler(調(diào)度器)瞒窒,
Item Pipeline(管道):它負(fù)責(zé)處理Spider中獲取到的Item,并進(jìn)行進(jìn)行后期處理(詳細(xì)分析睡互、過(guò)濾根竿、存儲(chǔ)等)的地方.
Downloader Middlewares(下載中間件):你可以當(dāng)作是一個(gè)可以自定義擴(kuò)展下載功能的組件。
Spider Middlewares(Spider中間件):你可以理解為是一個(gè)可以自定擴(kuò)展和操作引擎和Spider中間通信的功能組件(比如進(jìn)入Spider的Responses;和從Spider出去的Requests)