最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python并發(fā)爬蟲常用實現(xiàn)方法解析

 更新時間:2020年11月19日 15:22:57   作者:迎風而來  
這篇文章主要介紹了Python并發(fā)爬蟲常用實現(xiàn)方法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

在進行單個爬蟲抓取的時候,我們不可能按照一次抓取一個url的方式進行網(wǎng)頁抓取,這樣效率低,也浪費了cpu的資源。目前python上面進行并發(fā)抓取的實現(xiàn)方式主要有以下幾種:進程,線程,協(xié)程。進程不在的討論范圍之內(nèi),一般來說,進程是用來開啟多個spider,比如我們開啟了4進程,同時派發(fā)4個spider進行網(wǎng)絡抓取,每個spider同時抓取4個url。

所以,我們今天討論的是,在單個爬蟲的情況下,盡可能的在同一個時間并發(fā)抓取,并且抓取的效率要高。

一.順序抓取

順序抓取是最最常見的抓取方式,一般初學爬蟲的朋友就是利用這種方式,下面是一個測試代碼,順序抓取8個url,我們可以來測試一下抓取完成需要多少時間:

HEADERS = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9',         
  'Accept-Language': 'zh-CN,zh;q=0.8',                            
  'Accept-Encoding': 'gzip, deflate',}                            
URLS = ['http://www.cnblogs.com/moodlxs/p/3248890.html',                   
    'https://www.zhihu.com/topic/19804387/newest',                    
    'http://blog.csdn.net/yueguanghaidao/article/details/24281751',            
    'https://my.oschina.net/visualgui823/blog/36987',                   
    'http://blog.chinaunix.net/uid-9162199-id-4738168.html',               
    'http://www.tuicool.com/articles/u67Bz26',                      
    'http://rfyiamcool.blog.51cto.com/1030776/1538367/',                 
    'http://itindex.net/detail/26512-flask-tornado-gevent']                
                                               
#url為隨機獲取的一批url                                        
                                               
def func():                                          
  """                                            
  順序抓取                                           
  """                                            
  import requests                                      
  import time                                        
  urls = URLS                                        
  headers = HEADERS                                     
  headers['user-agent'] = "Mozilla/5.0+(Windows+NT+6.2;+WOW64)+AppleWebKit/537" \      
              ".36+(KHTML,+like+Gecko)+Chrome/45.0.2454.101+Safari/537.36"   
  print(u'順序抓取')                                      
  starttime= time.time()                                  
  for url in urls:                                     
    try:                                         
      r = requests.get(url, allow_redirects=False, timeout=2.0, headers=headers)    
    except:                                        
      pass                                       
    else:                                         
      print(r.status_code, r.url)                            
  endtime=time.time()                                    
  print(endtime-starttime)                                 
                                               
func()       

我們直接采用內(nèi)建的time.time()來計時,較為粗略,但可以反映大概的情況。下面是順序抓取的結果計時:

可以從圖片中看到,顯示的順序與urls的順序是一模一樣的,總共耗時為7.763269901275635秒,一共8個url,平均抓取一個大概需要0.97秒??傮w來看,還可以接受。

二.多線程抓取

線程是python內(nèi)的一種較為不錯的并發(fā)方式,我們也給出相應的代碼,并且為每個url創(chuàng)建了一個線程,一共8線程并發(fā)抓取,下面的代碼:

下面是我們運行8線程的測試代碼:

HEADERS = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9',               
  'Accept-Language': 'zh-CN,zh;q=0.8',                                  
  'Accept-Encoding': 'gzip, deflate',}                                  
URLS = ['http://www.cnblogs.com/moodlxs/p/3248890.html',                          
    'https://www.zhihu.com/topic/19804387/newest',                           
    'http://blog.csdn.net/yueguanghaidao/article/details/24281751',                  
    'https://my.oschina.net/visualgui823/blog/36987',                         
    'http://blog.chinaunix.net/uid-9162199-id-4738168.html',                      
    'http://www.tuicool.com/articles/u67Bz26',                             
    'http://rfyiamcool.blog.51cto.com/1030776/1538367/',                        
    'http://itindex.net/detail/26512-flask-tornado-gevent']                      
                                                      
def thread():                                               
  from threading import Thread                                      
  import requests                                            
  import time                                              
  urls = URLS                                              
  headers = HEADERS                                           
  headers['user-agent'] = "Mozilla/5.0+(Windows+NT+6.2;+WOW64)+AppleWebKit/537.36+" \          
              "(KHTML,+like+Gecko)+Chrome/45.0.2454.101+Safari/537.36"            
  def get(url):                                             
    try:                                                
      r = requests.get(url, allow_redirects=False, timeout=2.0, headers=headers)           
    except:                                              
      pass                                              
    else:                                               
      print(r.status_code, r.url)                                  
                                                      
  print(u'多線程抓取')                                            
  ts = [Thread(target=get, args=(url,)) for url in urls]                         
  starttime= time.time()                                         
  for t in ts:                                              
    t.start()                                             
  for t in ts:                                              
    t.join()                                              
  endtime=time.time()                                          
  print(endtime-starttime)                                        
thread()

多線程抓住的時間如下:

可以看到相較于順序抓取,8線程的抓取效率明顯上升了3倍多,全部完成只消耗了2.154秒。可以看到顯示的結果已經(jīng)不是urls的順序了,說明每個url各自完成的時間都是不一樣的。線程就是在一個進程中不斷的切換,讓每個線程各自運行一會,這對于網(wǎng)絡io來說,性能是非常高的。但是線程之間的切換是挺浪費資源的。

三.gevent并發(fā)抓取

gevent是一種輕量級的協(xié)程,可用它來代替線程,而且,他是在一個線程中運行,機器資源的損耗比線程低很多。如果遇到了網(wǎng)絡io阻塞,會馬上切換到另一個程序中去運行,不斷的輪詢,來降低抓取的時間
下面是測試代碼:

HEADERS = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9',
  'Accept-Language': 'zh-CN,zh;q=0.8',
  'Accept-Encoding': 'gzip, deflate',}

URLS = ['http://www.cnblogs.com/moodlxs/p/3248890.html',
    'https://www.zhihu.com/topic/19804387/newest',
    'http://blog.csdn.net/yueguanghaidao/article/details/24281751',
    'https://my.oschina.net/visualgui823/blog/36987',
    'http://blog.chinaunix.net/uid-9162199-id-4738168.html',
    'http://www.tuicool.com/articles/u67Bz26',
    'http://rfyiamcool.blog.51cto.com/1030776/1538367/',
    'http://itindex.net/detail/26512-flask-tornado-gevent']

def main():
  """
  gevent并發(fā)抓取
  """
  import requests
  import gevent
  import time

  headers = HEADERS
  headers['user-agent'] = "Mozilla/5.0+(Windows+NT+6.2;+WOW64)+AppleWebKit/537.36+" \
              "(KHTML,+like+Gecko)+Chrome/45.0.2454.101+Safari/537.36"
  urls = URLS
  def get(url):
    try:
      r = requests.get(url, allow_redirects=False, timeout=2.0, headers=headers)
    except:
      pass
    else:
      print(r.status_code, r.url)

  print(u'基于gevent的并發(fā)抓取')
  starttime= time.time()
  g = [gevent.spawn(get, url) for url in urls]
  gevent.joinall(g)
  endtime=time.time()
  print(endtime - starttime)
main()

協(xié)程的抓取時間如下:

正常情況下,gevent的并發(fā)抓取與多線程的消耗時間差不了多少,但是可能是我網(wǎng)絡的原因,或者機器的性能的原因,時間有點長......,請各位小主在自己電腦進行跑一下看運行時間

四.基于tornado的coroutine并發(fā)抓取

tornado中的coroutine是python中真正意義上的協(xié)程,與python3中的asyncio幾乎是完全一樣的,而且兩者之間的future是可以相互轉換的,tornado中有與asyncio相兼容的接口。
下面是利用tornado中的coroutine進行并發(fā)抓取的代碼:

利用coroutine編寫并發(fā)略顯復雜,但這是推薦的寫法,如果你使用的是python3,強烈建議你使用coroutine來編寫并發(fā)抓取。

下面是測試代碼:

HEADERS = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9',
  'Accept-Language': 'zh-CN,zh;q=0.8',
  'Accept-Encoding': 'gzip, deflate',}

URLS = ['http://www.cnblogs.com/moodlxs/p/3248890.html',
    'https://www.zhihu.com/topic/19804387/newest',
    'http://blog.csdn.net/yueguanghaidao/article/details/24281751',
    'https://my.oschina.net/visualgui823/blog/36987',
    'http://blog.chinaunix.net/uid-9162199-id-4738168.html',
    'http://www.tuicool.com/articles/u67Bz26',
    'http://rfyiamcool.blog.51cto.com/1030776/1538367/',
    'http://itindex.net/detail/26512-flask-tornado-gevent']
import time
from tornado.gen import coroutine
from tornado.ioloop import IOLoop
from tornado.httpclient import AsyncHTTPClient, HTTPError
from tornado.httpclient import HTTPRequest

#urls與前面相同
class MyClass(object):

  def __init__(self):
    #AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient")
    self.http = AsyncHTTPClient()

  @coroutine
  def get(self, url):
    #tornado會自動在請求首部帶上host首部
    request = HTTPRequest(url=url,
              method='GET',
              headers=HEADERS,
              connect_timeout=2.0,
              request_timeout=2.0,
              follow_redirects=False,
              max_redirects=False,
              user_agent="Mozilla/5.0+(Windows+NT+6.2;+WOW64)+AppleWebKit/537.36+\
              (KHTML,+like+Gecko)+Chrome/45.0.2454.101+Safari/537.36",)
    yield self.http.fetch(request, callback=self.find, raise_error=False)

  def find(self, response):
    if response.error:
      print(response.error)
    print(response.code, response.effective_url, response.request_time)


class Download(object):

  def __init__(self):
    self.a = MyClass()
    self.urls = URLS

  @coroutine
  def d(self):
    print(u'基于tornado的并發(fā)抓取')
    starttime = time.time()
    yield [self.a.get(url) for url in self.urls]
    endtime=time.time()
    print(endtime-starttime)

if __name__ == '__main__':
  dd = Download()
  loop = IOLoop.current()
  loop.run_sync(dd.d)

抓取的時間如下:

可以看到總共花費了128087秒,而這所花費的時間恰恰就是最后一個url抓取所需要的時間,tornado中自帶了查看每個請求的相應時間。我們可以從圖中看到,最后一個url抓取總共花了1.28087秒,相較于其他時間大大的增加,這也是導致我們消耗時間過長的原因。那可以推斷出,前面的并發(fā)抓取,也在這個url上花費了較多的時間。

總結:

以上測試其實非常的不嚴謹,因為我們選取的url的數(shù)量太少了,完全不能反映每一種抓取方式的優(yōu)劣。如果有一萬個不同的url同時抓取,那么記下總抓取時間,是可以得出一個較為客觀的結果的。

并且,已經(jīng)有人測試過,多線程抓取的效率是遠不如gevent的。所以,如果你使用的是python2,那么我推薦你使用gevent進行并發(fā)抓?。蝗绻闶褂玫氖莗ython3,我推薦你使用tornado的http客戶端結合coroutine進行并發(fā)抓取。從上面的結果來看,tornado的coroutine是高于gevent的輕量級的協(xié)程的。但具體結果怎樣,我沒測試過。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • Python中用format函數(shù)格式化字符串的用法

    Python中用format函數(shù)格式化字符串的用法

    這篇文章主要介紹了Python中用format函數(shù)格式化字符串的用法,格式化字符串是Python學習當中的基礎知識,本文主要針對Python2.7.x版本,需要的朋友可以參考下
    2015-04-04
  • 如何對python的字典進行排序

    如何對python的字典進行排序

    在本篇文章里小編給大家整理了關于python的字典進行排序方法,需要的朋友們可以學習下。
    2020-06-06
  • pygame編寫音樂播放器的實現(xiàn)代碼示例

    pygame編寫音樂播放器的實現(xiàn)代碼示例

    這篇文章主要介紹了pygame編寫音樂播放器的實現(xiàn)代碼示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11
  • Django中的Signal代碼詳解

    Django中的Signal代碼詳解

    這篇文章主要介紹了Django中的Signal代碼詳解,分享了相關代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02
  • Python smtp郵件發(fā)送模塊用法教程

    Python smtp郵件發(fā)送模塊用法教程

    這篇文章主要介紹了Python smtp郵件發(fā)送模塊用法教程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • Python中zip()函數(shù)的解釋和可視化(實例詳解)

    Python中zip()函數(shù)的解釋和可視化(實例詳解)

    zip() 函數(shù)用于將可迭代的對象作為參數(shù),將對象中對應的元素打包成一個個元組,然后返回由這些元組組成的列表。這篇文章主要介紹了Python中zip()函數(shù)的解釋和可視化,需要的朋友可以參考下
    2020-02-02
  • Django ManyToManyField 跨越中間表查詢的方法

    Django ManyToManyField 跨越中間表查詢的方法

    今天小編就為大家分享一篇Django ManyToManyField 跨越中間表查詢的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • python?dataframe獲得指定行列簡單例子

    python?dataframe獲得指定行列簡單例子

    在DataFrame中取特定行列的數(shù)據(jù)是一個常見的操作,這篇文章主要給大家介紹了關于python?dataframe獲得指定行列的簡單例子,需要的朋友可以參考下
    2024-03-03
  • python實現(xiàn)根據(jù)ip地址反向查找主機名稱的方法

    python實現(xiàn)根據(jù)ip地址反向查找主機名稱的方法

    這篇文章主要介紹了python實現(xiàn)根據(jù)ip地址反向查找主機名稱的方法,涉及Python使用socket解析IP的相關技巧,非常具有實用價值,需要的朋友可以參考下
    2015-04-04
  • python黑魔法之參數(shù)傳遞

    python黑魔法之參數(shù)傳遞

    這篇文章主要介紹了python黑魔法之參數(shù)傳遞,分析了python參數(shù)傳遞的方法,感興趣的小伙伴們可以參考一下
    2016-02-02

最新評論

顺平县| 红桥区| 新闻| 阳东县| 康保县| 枝江市| 罗定市| 且末县| 天门市| 泸定县| 磐石市| 浏阳市| 扶绥县| 龙井市| 云梦县| 朔州市| 肇州县| 潍坊市| 湘阴县| 连平县| 茶陵县| 广丰县| 濮阳市| 新河县| 滁州市| 休宁县| 阿巴嘎旗| 普陀区| 衢州市| 南丰县| 锡林郭勒盟| 天等县| 宁津县| 沛县| 普陀区| 竹北市| 西宁市| 肃宁县| 琼结县| 开封市| 霍州市|