多線程,多進程下微博圖片
概述
爬了微博後圖片一直是用鏈接保存的,前陣子喜歡上了優子醬,喜歡著裝風格,瘋狂找圖片,於是爬了她的粉絲微博,下了所有的圖片。由於這個實現起來沒有順序,相對簡單,下一步就要考慮用多線程和多進程對微博爬蟲進行改造了,不過這個需要時間,等技術更加純熟再弄可能會更好。
主要內容
下載函數urlretrieve
參數finename指定了保存本地路徑(如果參數未指定,urllib會生成一個臨時文件保存數據。)
參數reporthook是一個回調函數,當連接上伺服器、以及相應的數據塊傳輸完畢時會觸發該回調,我們可以利用這個回調函數來顯示當前的下載進度。
參數data指 post 到伺服器的數據,該方法返回一個包含兩個元素的(filename, headers)元組,filename 表示保存到本地的路徑,header 表示伺服器的響應頭
多線程Threading
概念
多線程是並行的一種。計算機只有一個CPU核心,同時只能處理一個任務。這樣的情況下,多線程可以理解為開闢多條道路,但道路的出口只有一個。哪條路上的車搶到了通行權這條路上的汽車就會優先通過,直到下條路上的車搶到通行權,此時其他路上的汽車都會進入等待狀態。使用多線程,可以大大的增加程序的性能和效率。
多線程的使用
在python3 中一般使用 threading 庫
參數function_name用於指定執行多線程的函數名字(只要名字)
參數args是前述函數的參數
此函數也可通過類的繼承使用
輸出
線程之間的同步
多線程同時對同一數據進行修改時,為保證數據正確,需要多線程同步。
多線程的優勢在於可以同時運行多個任務(至少感覺起來是這樣)。
使用 Thread 對象的 Lock 和 Rlock 可以實現簡單的線程同步,這兩個對象都有 acquire 方法和 release 方法,對於那些需要每次只允許一個線程操作的數據,可以將其操作放到 acquire 和 release 方法之間。如下:
考慮這樣一種情況:一個列表裡所有元素都是0,線程"set"從後向前把所有元素改成1,而線程"print"負責從前往後讀取列表並列印。
那麼,可能線程"set"開始改的時候,線程"print"便來列印列表了,輸出就成了一半0一半1,這就是數據的不同步。為了避免這種情況,引入了鎖的概念。
鎖有兩種狀態——鎖定和未鎖定。每當一個線程比如"set"要訪問共享數據時,必須先獲得鎖定;如果已經有別的線程比如"print"獲得鎖定了,那麼就讓線程"set"暫停,也就是同步阻塞;等到線程"print"訪問完畢,釋放鎖以後,再讓線程"set"繼續。
經過這樣的處理,列印列表時要麼全部輸出0,要麼全部輸出1,不會再出現一半0一半1的尷尬場面。
——引自菜鳥教程,Python3 多線程
輸出
注意對比區別
線程中還有線程優先順序隊列等,沒有用到不介紹。
多進程Multiprocessing
Process 類
Process 類用來描述一個進程對象,用於新建子進程。創建子進程的時候,只需要傳入一個執行函數和函數的參數即可完成 Process 示例的創建。
start() 方法啟動進程,
join() 方法實現進程間的同步,等待所有進程退出。
close() 用來阻止多餘的進程湧入進程池 Pool 造成進程阻塞。
target是函數名字,需要調用的函數(只要名字)
args函數需要的參數,以 tuple 的形式傳入
Pool類
同時創建多個進程也可用Pool類
pool.apply_async()是apply()的並行版本,apply()是apply_async()的阻塞版本,也是Python內置的函數,兩者等價。在這個函數中輸出結果並不是按照代碼for循環中的順序輸出的。
pool.apply_async(func, (msg, ))可返回值,它返回pool中所有進程的值的對象(注意是對象,不是值本身)。
成果
放幾張我優子的美照!
來自粉絲微博(最終來自優子Ins帳號等),非商用!
源代碼
TAG:MISaD |