分布式豆瓣爬虫(三): 控制节点-控制调度器

一、实现原理

控制调度器主要是产生并启动 URL 管理进程、数据提取进程和数据存储进程,同时维护4个队列保持进程间的通信,分别为 url_q、result_q、conn_q、store_q。4个队列说明如下:

  • url_q:队列是 URL 管理进程将 URL 传递给爬虫节点的通道。
  • result_q:队列是爬虫节点将数据返回给数据提取进程的通道。
  • conn_q:队列是数据提取进程将新的 URL 数据提交给 URL 管理进程的通道。
  • store_q:队列是数据提取进程将获取到的数据交给数据存储进程的通道。

二、代码如下

  1 from multiprocessing.managers import BaseManager
  2 from multiprocessing import Queue, Process
  3 from DataOutput import DataOutput
  4 from UrlManager import UrlManager
  5 import time
  6 
  7 
  8 class NodeManager:
  9     def start_manager(self, url_q, result_q):
 10         """
 11         创建一个分布式管理器
 12         :param url_q: url 队列
 13         :param result_q: 结果队列
 14         :return: BaseManager
 15         """
 16         # 把创建的两个队列注册在网络上,利用 register 方法,callable 参数关联了 Queue 对象
 17         # 将 Queue 对象在网络中暴露
 18         BaseManager.register('get_task_queue', callable=lambda:url_q)
 19         BaseManager.register('get_result_queue', callable=lambda:result_q)
 20         # 绑定端口 8001,设置验证口令"douban",相当于对象的初始化并返回
 21         return BaseManager(address=('', 8001), authkey='douban'.encode('utf-8'))
 22 
 23     def url_manager_proc(self, url_q, conn_q, root_url):
 24         """
 25         url 管理进程
 26         :param url_q: url 队列
 27         :param conn_q: 解析得到的 url 队列
 28         :param root_url: 起始 url
 29         :return: None
 30         """
 31         url_manage = UrlManager()
 32         url_manage.add_new_url(root_url)
 33         while True:
 34             while url_manage.has_new_url():
 35                 print('old_urls={}'.format(url_manage.old_urls_size()))
 36                 new_url = url_manage.get_new_url()
 37                 url_q.put(new_url)
 38                 urls = conn_q.get()
 39                 url_manage.add_new_urls(urls)
 40             else:
 41                 url_q.put('end')
 42                 print('控制节点发起结束通知')
 43                 url_manage.save_progress('old_urls.txt', url_manage.old_urls)
 44                 url_manage.save_progress('new_urls.txt', url_manage.new_urls)
 45                 return
 46 
 47     def result_solve_proc(self, result_q, conn_q, store_q):
 48         """
 49         数据提取进程
 50         :param result_q: 未处理数据队列
 51         :param conn_q: 解析得到的 url 队列
 52         :param store_q: 解析后的数据队列
 53         :return:
 54         """
 55         while True:
 56             try:
 57                 if not result_q.empty():
 58                     content = result_q.get()
 59                     if content['new_urls'] == 'end':
 60                         print('结果分析进程接收通知然后结束')
 61                         store_q.put('end')
 62                         return
 63 
 64                     conn_q.put(content['new_urls'])
 65                     store_q.put(content['data'])
 66                 else:
 67                     time.sleep(0.1)
 68             except:
 69                 time.sleep(0.1)
 70 
 71     def store_proc(self, store_q):
 72         """
 73         数据存储进程
 74         :param store_q: 解析后的数据队列
 75         :return:
 76         """
 77         output = DataOutput()
 78         while True:
 79             if not store_q.empty():
 80                 data = store_q.get()
 81 
 82                 if data == 'end':
 83                     print('存储进程接收结束通知然后结束')
 84                     return
 85 
 86                 for item in data:
 87                     output.output_csv(item)
 88             else:
 89                 time.sleep(0.1)
 90 
 91 
 92 if __name__ == '__main__':
 93     # 初始化 4 个队列
 94     url_q = Queue()
 95     result_q = Queue()
 96     conn_q = Queue()
 97     store_q = Queue()
 98     # 创建分布式管理器
 99     node = NodeManager()
100     manager = node.start_manager(url_q, result_q)
101     # 创建 url 管理进程、数据提取进程和数据存储进程
102     url = 'https://movie.douban.com/top250?start=0'
103     url_manager_proc = Process(target=node.url_manager_proc, args=(url_q, conn_q, url,))
104     result_solve_proc = Process(target=node.result_solve_proc, args=(result_q, conn_q, store_q,))
105     store_proc = Process(target=node.store_proc, args=(store_q,))
106     # 启动 3 个进程和分布式管理器
107     url_manager_proc.start()
108     result_solve_proc.start()
109     store_proc.start()
110     manager.get_server().serve_forever()

猜你喜欢

转载自www.cnblogs.com/mxsf/p/10153876.html