爬虫類ノート(5)分布式

3153 ワード

単機の下ではマルチスレッドとマルチプロセスを用いて機械の十分な利用を実現することができるが,単機の能力は限られており,より多くの機械を採用すれば爬虫類の効率をさらに向上させることができる.ここでは分布式爬虫類を導入する.分散爬虫類の場合、Redisを使用してタスクキューを実装すると、システム構成が大幅に簡素化されます.
1.Redis入門
  • Redis redis-serverを起動するサーバ側はredis-serverであり、パラメータなしで直接起動することができる.redis-serverのデフォルトのポート番号は6379で、デフォルトではリモート接続できません.プロファイルを使用することで、デフォルト設定
  • を変更できます.
    bind 0.0.0.0
    port 6666
    

    bindは指定されたバインドipに使用され、0.0.0.0は任意のリモートまたはローカル接続を受け入れることができ、portはポート番号を指定するために使用されます.
  • 接続Redis redis-cliはRedisシステムに付属するクライアントで、パラメータなしで直接起動し、デフォルトのポートの下のローカルRedisサーバに接続できます.-pでポートを指定し、-hでサーバアドレスを指定することもできます.
  • redis-cli -h localhost -p 6666
    
  • データ型Redisはkey-valueタイプのデータベースとして、valueは複数のデータ型をサポートします.
  • a.文字列文字列はRedisの最も簡単なデータ型であり、keyのタイプはすべて文字列であることに注意する.バイナリデータも文字列です.たとえば、画像ファイルの内容をvalueに存在させることができます.valueの長さは512 MBを超えてはならない.

  • >set name 'dongge' #        
    OK
    >get name
    "dongge"
    >keys * #     key
    "name"
    >set counter 100
    OK
    >incr counter
    (integer)101
    >incryby counter 50
    (integer)151
    >exists name #  key    
    (integer)1
    >type name
    string
    >del name #    key
    (integer)1
    >type name
    none
    
  • b.リストRedisリストは双方向チェーンテーブルで下位構造を実現し、前または後から操作することができる.
  • >rpush mylist A #        
    (integer)1
    >rpush mylist B
    (integer)2
    >lpush mylist C #        
    (integer)3
    >lrange mylist 0 -1
    1) "C"
    2) "A"
    3) "B"
    >rpop mylist #      lpop      
    "B"
    

    Redisリストにはブロック操作があり,この操作はプロセス間通信の実現に非常に有用である.rpopとlpopはブロック機能を実現していないので,プロセス間通信の要求を達成するためにはポーリングが必要であり,このような戦略は明らかにだめである.BRPOPとBLPOPはブロック操作を実現し、リストが空の場合、設定された時間になるまでブロックされます.Redisデータ型
  • Redisサーバ
  • を停止する.
    redis-cli shutdown (redis-cli -p 6666 -h localhost)
    

    2.分布式爬虫類
    分散型爬虫類はメインサーバ(master)とスレーブサーバ(slave)に分けられ、メインサーバはurlをタスクキューに割り当て、リンクデータを受信する.サーバから指定したページを抽出し、データを分析し、データベースにデータを格納し、メインサーバに戻るリンクを担当します.
  • サーバ
  • import redis
    def server(init_url):
        s = set()#         
        s.add(init_url)
        conn = redis.Redis()
        conn.rpush('url',init_url)
        while  True:
            data = conn.brpop('data')
            #print data
            if data != None and data[0] == 'data':
                data = eval(data[1])
                urls = data['urls']
                for url in urls:
                    if url not in s:
                        s.add(url)
                        conn.rpush('url',url)
    if __name__ == '__main__':
        server('http://www.qiushibaike.com')
    
  • クライアント
  • '''
      {“urls”:[],"data":[]}
    '''
    def handlepage(html):
        pass
    def subprocess(url,host = 'localhost'):
        conn = redis.Redis(host)
        while True:
          url = conn.brpop('url')
          html = loadurl(url[1])#    
          ret = handlepage(html)#    
          conn.rpush('urls',ret['urls'])# server  urls
          save(ret['data'])#    
    def client(num,host='localhost'):
          for i in range(num):
              p = Process(target = subprocess,args=(host,)
              p.start()