# 本程序亲测有效,用于理解爬虫相关的基础知识,不足之处希望大家批评指正
from queue import Queueimport requestsfrom lxml import etreefrom multiprocessing.dummy import Poolimport time"""爬取目标:http://www.qiushibaike.com/8hr/page/1 利用线程池实现"""class QiuShi: def __init__(self): # url和headers self.base_url = 'http://www.qiushibaike.com/8hr/page/{}' self.headers = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36' # 定义队列,用来传递数据 self.url_queue = Queue() self.request_queue = Queue() self.html_queue = Queue() # 初始化线程池 self.pool = Pool() # 定义计数器 self.request_num = 0 self.response_num = 0 self.is_running = True def get_url_list(self): """获取所有的url""" for i in range(1, 14): target_url = self.base_url.format(i) print(target_url) self.request_num += 1 self.url_queue.put(target_url) def request_url(self): """向url发起请求""" target_url = self.url_queue.get() response = requests.get(target_url, self.headers) self.request_queue.put(response) self.url_queue.task_done() def get_content(self): """获取数据""" html_text = self.request_queue.get().content.decode() html = etree.HTML(html_text) div_list = html.xpath('//div[@id="content-left"]/div') content_list = [] for div in div_list: item = {} item['author'] = div.xpath('.//h2/text()')[0].strip() item['content'] = div.xpath('.//span/text()')[0].strip() print(item) content_list.append(item) self.html_queue.put(content_list) self.request_queue.task_done() def save_data(self): """保存入库""" data_list = self.html_queue.get() for data in data_list: with open('qiushi.text', 'a+') as f: f.write(str(data)) f.write('\r\n') self.html_queue.task_done() def execute_request_response_save(self): """线程池子,执行请求,回应,保存""" self.request_url() self.get_content() self.save_data() self.response_num += 1 def _callback(self,temp): """线程池的回调函数:""" if self.is_running: self.pool.apply_async(self.execute_request_response_save, callback=self._callback) def main(self): """主程序逻辑""" self.get_url_list() # 执行线程池 for n in range(4): # 用4个线程去执行线程池任务 self.pool.apply_async(self.execute_request_response_save,callback=self._callback) # time.sleep(10) while True: if self.request_num == self.response_num: self.is_running = False break #思考: 为什么要加上这个while? """ 如果不写这个while循环,那么,线程池的异步任务在没有进入回调函数的时候,主线程就结束了 那问题又来了,python3中主线程不是不影响用户子线程的吗? 注意了:我们这里用的是单进程单线程任务,只不过用的是线程池的方法来解决问题 当主进程结束了,那么进程内部的线程也会一起结束 这个while循环就是让主线程在这里等待线程池中的子线程,等子线程所有的任务都完成了,再一起结束 他的作用类似于join()函数 """if __name__ == '__main__': qiushi = QiuShi() qiushi.main()