<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                本文希望達到的目標: 1. 學習Queue模塊 2. 將Queue模塊與多線程編程相結合 3. 通過Queue和threading模塊, 重構爬蟲, 實現多線程爬蟲, 4. 通過以上學習希望總結出一個通用的多線程爬蟲小模版 # 1\. Queue模塊 * * * `Queue`模塊實現了多生產者多消費者隊列, 尤其適合多線程編程.`Queue`類中`實現了所有需要的鎖原語`(這句話非常重要), Queue模塊實現了三種類型隊列: * FIFO(先進先出)隊列, 第一加入隊列的任務, 被第一個取出 * LIFO(后進先出)隊列,最后加入隊列的任務, 被第一個取出(操作類似與棧, 總是從棧頂取出, 這個隊列還不清楚內部的實現) * PriorityQueue(優先級)隊列, 保持隊列數據有序, 最小值被先取出(在C++中我記得優先級隊列是可以自己重寫排序規則的, Python不知道可以嗎) ## 1.1\. 類和異常 ~~~ import Queue #類 Queue.Queue(maxsize = 0) #構造一個FIFO隊列,maxsize設置隊列大小的上界, 如果插入數據時, 達到上界會發生阻塞, 直到隊列可以放入數據. 當maxsize小于或者等于0, 表示不限制隊列的大小(默認) Queue.LifoQueue(maxsize = 0) #構造一LIFO隊列,maxsize設置隊列大小的上界, 如果插入數據時, 達到上界會發生阻塞, 直到隊列可以放入數據. 當maxsize小于或者等于0, 表示不限制隊列的大小(默認) Queue.PriorityQueue(maxsize = 0) #構造一個優先級隊列,,maxsize設置隊列大小的上界, 如果插入數據時, 達到上界會發生阻塞, 直到隊列可以放入數據. 當maxsize小于或者等于0, 表示不限制隊列的大小(默認). 優先級隊列中, 最小值被最先取出 #異常 Queue.Empty #當調用非阻塞的get()獲取空隊列的元素時, 引發異常 Queue.Full #當調用非阻塞的put()向滿隊列中添加元素時, 引發異常 ~~~ ## 1.2\. Queue對象 三種隊列對象`提供公共的方法` ~~~ Queue.empty() #如果隊列為空, 返回True(注意隊列為空時, 并不能保證調用put()不會阻塞); 隊列不空返回False(不空時, 不能保證調用get()不會阻塞) Queue.full() #如果隊列為滿, 返回True(不能保證調用get()不會阻塞), 如果隊列不滿, 返回False(并不能保證調用put()不會阻塞) Queue.put(item[, block[, timeout]]) #向隊列中放入元素, 如果可選參數block為True并且timeout參數為None(默認), 為阻塞型put(). 如果timeout是正數, 會阻塞timeout時間并引發Queue.Full異常. 如果block為False為非阻塞put Queue.put_nowait(item) #等價于put(itme, False) Queue.get([block[, timeout]]) #移除列隊元素并將元素返回, block = True為阻塞函數, block = False為非阻塞函數. 可能返回Queue.Empty異常 Queue.get_nowait() #等價于get(False) Queue.task_done() #在完成一項工作之后,Queue.task_done()函數向任務已經完成的隊列發送一個信號 Queue.join() #實際上意味著等到隊列為空,再執行別的操作 ~~~ 下面是官方文檔給多出的多線程模型: ~~~ def worker(): while True: item = q.get() do_work(item) q.task_done() q = Queue() for i in range(num_worker_threads): t = Thread(target=worker) t.daemon = True t.start() for item in source(): q.put(item) q.join() # block until all tasks are done ~~~ # 2\. Queue模塊與線程相結合 * * * 簡單寫了一個Queue和線程結合的小程序 ~~~ #!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time import Queue SHARE_Q = Queue.Queue() #構造一個不限制大小的的隊列 _WORKER_THREAD_NUM = 3 #設置線程個數 class MyThread(threading.Thread) : def __init__(self, func) : super(MyThread, self).__init__() self.func = func def run(self) : self.func() def worker() : global SHARE_Q while not SHARE_Q.empty(): item = SHARE_Q.get() #獲得任務 print "Processing : ", item time.sleep(1) def main() : global SHARE_Q threads = [] for task in xrange(5) : #向隊列中放入任務 SHARE_Q.put(task) for i in xrange(_WORKER_THREAD_NUM) : thread = MyThread(worker) thread.start() threads.append(thread) for thread in threads : thread.join() if __name__ == '__main__': main() ~~~ # 3\. 重構爬蟲 * * * 主要針對之間寫過的豆瓣爬蟲進行重構: * [Python網絡爬蟲(二)--豆瓣抓站小計](http://andrewliu.tk/2014/12/05/Python%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB-%E4%BA%8C-%E8%B1%86%E7%93%A3%E6%8A%93%E7%AB%99%E5%B0%8F%E8%AE%A1/) ## 3.1\. 豆瓣電影爬蟲重構 通過對Queue和線程模型進行改寫, 可以寫出下面的爬蟲程序 : ~~~ #!/usr/bin/env python # -*- coding:utf-8 -*- # 多線程爬取豆瓣Top250的電影名稱 import urllib2, re, string import threading, Queue, time import sys reload(sys) sys.setdefaultencoding('utf8') _DATA = [] FILE_LOCK = threading.Lock() SHARE_Q = Queue.Queue() #構造一個不限制大小的的隊列 _WORKER_THREAD_NUM = 3 #設置線程的個數 class MyThread(threading.Thread) : def __init__(self, func) : super(MyThread, self).__init__() #調用父類的構造函數 self.func = func #傳入線程函數邏輯 def run(self) : self.func() def worker() : global SHARE_Q while not SHARE_Q.empty(): url = SHARE_Q.get() #獲得任務 my_page = get_page(url) #爬取整個網頁的HTML代碼 find_title(my_page) #獲得當前頁面的電影名 time.sleep(1) SHARE_Q.task_done() ~~~ 完整代碼請查看[Github豆瓣多線程爬蟲](https://github.com/Andrew-liu/dou_ban_spider/blob/master/threading_douban.py) 完成這個程序后, 又出現了新的問題: > 無法保證數據的順序性, 因為線程是并發的, 思考的方法是: 設置一個主線程進行管理, 然后他們的線程工作 # 4\. 通用的多線程爬蟲小模版 * * * 下面是根據上面的爬蟲做了點小改動后形成的模板 ~~~ #!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time import Queue SHARE_Q = Queue.Queue() #構造一個不限制大小的的隊列 _WORKER_THREAD_NUM = 3 #設置線程的個數 class MyThread(threading.Thread) : """ doc of class Attributess: func: 線程函數邏輯 """ def __init__(self, func) : super(MyThread, self).__init__() #調用父類的構造函數 self.func = func #傳入線程函數邏輯 def run(self) : """ 重寫基類的run方法 """ self.func() def do_something(item) : """ 運行邏輯, 比如抓站 """ print item def worker() : """ 主要用來寫工作邏輯, 只要隊列不空持續處理 隊列為空時, 檢查隊列, 由于Queue中已經包含了wait, notify和鎖, 所以不需要在取任務或者放任務的時候加鎖解鎖 """ global SHARE_Q while True : if not SHARE_Q.empty(): item = SHARE_Q.get() #獲得任務 do_something(item) time.sleep(1) SHARE_Q.task_done() def main() : global SHARE_Q threads = [] #向隊列中放入任務, 真正使用時, 應該設置為可持續的放入任務 for task in xrange(5) : SHARE_Q.put(task) #開啟_WORKER_THREAD_NUM個線程 for i in xrange(_WORKER_THREAD_NUM) : thread = MyThread(worker) thread.start() #線程開始處理任務 threads.append(thread) for thread in threads : thread.join() #等待所有任務完成 SHARE_Q.join() if __name__ == '__main__': main() ~~~ > 我感覺其實這個多線程挺凌亂的, 希望以后自己能重構 # 5\. 思考更高效的爬蟲方法 * * * * 使用[twisted](https://twistedmatrix.com/trac/wiki/Documentation)進行異步IO抓取 * 使用`Scrapy`框架(Scrapy 使用了 Twisted 異步網絡庫來處理網絡通訊) # 6\. 參考鏈接 * * * [Queue官方文檔](https://docs.python.org/2/library/queue.html) [Twisted英文入門指南](http://krondo.com/blog/?page_id=1327) [Twisted中文入門指南](http://turtlerbender007.appspot.com/twisted/index.html)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看