scrapy呼叫parse()中使用yield引發對yield的分析
阿新 • • 發佈:2019-02-06
1. yield解析: yield 的作用就是把一個函式變成一個生成器(generator),帶有yield的函式不再是一個普通函式, Python直譯器會將其視為一個generator,單獨呼叫(如fab(5))不會執行fab函式,而是返回一個 iterable 物件! 在for迴圈執行時,每次迴圈都會執行fab函式內部的程式碼,執行到yield b時,fab函式就返回一個迭代值,下次迭代時,程式碼從 yield b 的下一條語句繼續執行,而函式的本地變數看起來和上次中斷執行前是完全一樣的,於是函式繼續執行,直到再次遇到 yield。參考例項如下:def fab(max): n, a, b = 0, 0, 1 while n < max: # print b yield b # print b a, b = b, a + b n = n + 1 print(fab(5)) # 輸出:<generator object fab at 0x00000000069D8A68> for n in fab(5): print n # 依次1,1,2,3,5 #對於含有yield的函式,外部要以迭代的方式呼叫,當函式執行結束時,generator 自動丟擲 StopIteration 異常,表示迭代完成。 # 在 for 迴圈裡,無需處理 StopIteration 異常,迴圈會正常結束。def ff(max): a,b = 0,1 yield max # yield不在迴圈中,這裡已經到函式最後所以直接返回,相當於return for n in ff(5): print n # 輸出:5 結論:綜上可知,yield要使用在迴圈中,這樣生成器才有使用的意義。 2. 對scrapy中使用yield迴圈處理網頁url的分析 首先,scrapy框架對含有yield關鍵字的parse()方法的呼叫是以迭代的方式進行的。相當於 for n in parse(self, response): pass 其次,python將parse()函式視為生成器,但首次呼叫才會開始執行程式碼,每次迭代請求(即上面的for迴圈)才會執行yield處的迴圈程式碼,生成每次迭代的值。如下方法:def parse(self, response): # 具體處理邏輯:如,分析頁面,找到頁面中符合規則的內容(校花圖片),儲存 hxs = HtmlXPathSelector(response) # 建立查詢物件 # 獲取所有的url,繼續訪問,並在其中尋找相同的url all_urls = hxs.select('//a/@href').extract() for url in all_urls: if url.startswith('http://www.xiaohuar.com/list-1-'): yield Request(url, callback=self.parse) # 遞迴的找下去 print(url) # Scrapy框架開始執行spider,即是對parse()方法迭代的過程{for n in parse(self, response)}, # 首先程式會將第一個response物件分析提取需要的東西,然後提取該response中所有的urls進行迴圈處理 # 對urls迴圈處理過程中,首次執行到parse-for-yield處,會返回一個迭代值,即生成一個Request1 物件(其中定義了回撥方法為parse); # 此時,第一次迭代結束。 # 第一次迭代過程中生成的Request1物件,即一個新的url請求,會返回一個新的response,然後框架會使用該response執行回撥函式,進行另一個分支的迭代處理 # 分支迭代的程式處理完成,進行第二次迭代,會從yield的下一條語句開始,即print,然後繼續執行for迴圈,最後執行到yield,又會生 # 成一個request2 物件, # 生成request2 物件,相當於又開始了一個新的分支,這個分支處理完後返回一個物件後開始回到主程式 # 接下來,開始第三次迭代,又從yield後面的print開始執行..... # 最終,直到迴圈結束。 注:這裡有個疑問,主程式執行到yield後,是等到該次遞迴呼叫完全結束後(即第一次迴圈的url,它內部所有子url都處理完),才進行的第二次迭代嗎? 這可以實際測試下,最好子url不要與父url重複。 參考文章:https://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/ https://www.cnblogs.com/kongqi816-boke/p/5827243.html