使用线程池来进行发送爬取请求和存储数据
基于multiprocessing.dummy线程池爬取梨视频的视频信息
import re import random import requests from lxml import etree from fake_useragent import UserAgent # 安装fake-useragent库:pip install fake-useragent # 导入线程池模块 from multiprocessing.dummy import Pool # 实例化线程池对象 pool = Pool()
#要爬取的视频网站的url url = 'http://www.pearvideo.com/category_1' # 在有ua列表的情况下可以随机产生UA,防止反扒ua机制 ua = UserAgent().random headers = { 'User-Agent': ua } # 获取首页页面数据 page_text = requests.get(url=url, headers=headers).text # 对获取的首页页面数据中的相关视频详情链接进行解析 tree = etree.HTML(page_text) li_list = tree.xpath('//div[@id="listvideoList"]/ul/li') detail_urls = [] # 存储二级页面的url for li in li_list: detail_url = 'http://www.pearvideo.com/' + li.xpath('./div/a/@href')[0] title = li.xpath('.//div[@class="vervideo-title"]/text()')[0] detail_urls.append(detail_url) vedio_urls = [] # 存储视频的url for url in detail_urls: page_text = requests.get(url=url, headers=headers).text vedio_url = re.findall('srcUrl="(.*?)"', page_text, re.S)[0] vedio_urls.append(vedio_url) # 使用线程池进行视频数据下载 func_request = lambda link: requests.get(url=link, headers=headers).content
#将所有的url放入线程池,让func_request函数去发送请求并获取结果 video_data_list = pool.map(func_request, vedio_urls) # 使用线程池进行视频数据保存 func_saveData = lambda data: save(data) pool.map(func_saveData, video_data_list) def save(data): file_name = str(random.randint(1, 10000)) + '.mp4' with open(file_name, 'wb') as fp: fp.write(data) print(file_name + '已存储') pool.close() pool.join()
总结:对应上例中的所面临的可能同时出现的上千甚至上万次的客户端请求,“线程池”或“连接池”或许可以缓解部分压力,但是不能解决所有问题。总之,多线程模型可以方便高效的解决小规模的服务请求,但面对大规模的服务请求,多线程模型也会遇到瓶颈,可以用非阻塞接口来尝试解决这个问题。