爬虫--多线程编程-提高效率--泛见(犯贱)志趣图标题和链接爬取
#还需要调试 从头调试 import threading import time from queue import Queue import requests from lxml import etree import json #创建一个列表用来存放采集线程 g_crawl_list = [] #创建一个列表用来存放解析线程 g_parse_list = [] #创建采集线程对象 采集线程对象需要用到两个队列 页码的队列 存页面源码的队列 class CrawlThread(threading.Thread): def __init__(self,name,page_queue,data_queue): super().__init__() self.name = name self.page_queue = page_queue self.data_queue = data_queue self.url = "http://www.ifanjian.net/latest-{}" self.headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36' } #启动采集线程后开始运行的函数 def run(self): print('%s-----线程启动'% self.name) #线程要一直跑 要是不这样的话 他只能跑你创建的个数页 while 1: #判断采集线程何时退出 要爬取的页数队列空了就结束了 if self.page_queue.empty(): break #从队列中取出页码 page = self.page_queue.get() # print(page) # exit() #拼接url 发送请求 url = self.url.format(page) # print(url) # exit() r = requests.get(url=url,headers = self.headers) # print(r.text) # exit() #将响应内容存放到data_queue队列中 self.data_queue.put(r.text) print('%s-----线程结束'% self.name) #创建解析线程对象 解析线程只需要页面源码这个队列 解析出的东西存入别的列表 最后输出 class ParserThread(threading.Thread): def __init__(self,name,data_queue,fp,lock): super().__init__() self.name = name self.data_queue = data_queue self.fp = fp self.lock = lock def run(self): print('%s-----线程启动'% self.name) while 1: # if self.data_queue.empty(): # break #从data_queue中取出一页数据 data = self.data_queue.get() # print(data) # exit() #解析内容即可 self.parse_content(data) print('%s-----线程结束'% self.name) def parse_content(self,data): tree = etree.HTML(data) #先查找所有的li再从li里面找自己的标题和url li_list = tree.xpath('//ul[@class = "cont-list"]/li') # print(li_list) # print(len(li_list)) # exit() ##建立一个空列表存数据 #items = [] for oli in li_list: #获取图片标题 title = oli.xpath('.//h2/a/text()')[0] # print(title) # exit() #获取图片url image_url = oli.xpath('.//div[contains(@class,"cont-list-main")]/p/img[@class= "lazy"]/@data-src') # print(image_url) # exit() #存放到一个字典中 item = { '标题':title, '链接':image_url } # print(item) # exit() #写到文件中 但是需要先上锁 self.lock.acquire() self.fp.write(str(item)+'\n') self.lock.release() #创建采集线程 就是实例化采集线程对象的函数 def create_crawl_thread(page_queue,data_queue): crawl_name = ['采集线程一号','采集线程二号','采集线程三号'] for name in crawl_name: tcrawl = CrawlThread(name,page_queue,data_queue) #每次线程工作完一次把结果存放到采集列表 g_crawl_list.append(tcrawl) #创建解析线程 就是实例化解析线程对象的函数 def create_parse_thread(data_queue,fp,lock): parse_name = ['解析线程一号','解析线程二号','解析线程三号'] for name in parse_name: tparse = ParserThread(name,data_queue,fp,lock) #每次线程工作完一次把结果存放到解析列表 g_parse_list.append(tparse) #创建队列函数 def create_queue(): #创建页码队列 page_queue = Queue() #这里添加爬取页数 目前是1到5页 for page in range(1,20): page_queue.put(page) #创建队列内容 data_queue = Queue() return page_queue,data_queue #主函数 def main(): #创建队列函数 page_queue,data_queue = create_queue() #打开文件 fp = open('fanjianzhi.txt','a',encoding='utf8') #创建锁 lock = threading.Lock() #创建采集线程 create_crawl_thread(page_queue,data_queue) #一开始解析队列为空 所以需要等待一会 time.sleep(10) #创建解析线程 解析线程存档时会用到fp 将其作为参数传入 create_parse_thread(data_queue,fp,lock) #启动所有采集线程 for tcrawl in g_crawl_list: tcrawl.start() #启动所有解析线程 for tparse in g_parse_list: tparse.start() #主线程等待两个子线程结束 for tcrawl in g_crawl_list: tcrawl.join() for tparse in g_parse_list: tparse.join() #在这里关闭文件 fp.close() print("主线程子线程全部结束") if __name__ == '__main__': main()
这线程玩起来确实比常规爬取写起来要困难,但是据说效率高,而且也是爬虫正规化的必由之路,没办法,也得学
作者:求知鱼
-------------------------------------------
个性签名:你有一个苹果,我有一个苹果,我们交换一下,一人还是只有一个苹果;你有一种思想,我有一种思想,我们交换一下,一个人就有两种思想。
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
独学而无友,则孤陋而寡闻,开源、分享、白嫖!