提高爬取效率
线程 进程
线程:执行单位(例子:公司里的员工)
进程:资源单位(例子:公司里的资源)
一个进程至少里一个线程
启动一个程序 默认一个主线程
多线程
第一套写法
if __name__=='__main__':
当程序是主程序运行时 才运行
例如 被当作模块导入 其他程序时 其下代码不会运行
导入库
from threading import Thread
创建线程并安排任务
def cc(): for i in range(20): print(i)t=Thread(target=cc())#创建一个进程 安排任务为target函数t.start()#多线程设为可以开始的状态,具体开始的时间由cpu决
例子
def cc(): for i in range(20): print('第一个',i)cc()for ii in range(5): print('第二个',ii)
这个程序 他是先执行第一个 再执行第二个
使用多线程
from threading import Threaddef cc(): for i in range(1000): print('第一个',i)t=Thread(target=cc)# 注意只有函数名 没有括号t.start()for ii in range(1000): print('第二个',ii)
会发现 第一个 夹杂着第二个(target调用时注意函数不要加括号)
原理图
两个线程
t2 t3.......可以启用多个线程
创建线程 任务函数的参数传递
from threading import Threaddef cc(name): for i in range(1000): print(name,i)t=Thread(target=cc,args=('周杰伦',))# 注意只有函数名 没有括号t.start()
通过 arg参数 传递参数
记住参数必须是元组 一个参数就加上括号
第二套写法
继承 定义子类
from threading import Threadclass MyThread(Thread): def run(self): for i in range(1000): print('子进程',i)t=MyThread()t.start()#默认执行run 记住千万不要t.run() 那样相当于调用还是单线程、#主进程for ii in range(1000): print('主进程',ii)
记住千万不能 t.run() 那样相当于调用 是单线程
多进程
开创多进程 消耗的资源大于多线程
导入库
from multiprocessing import Process
创建子进程
同子线程
from multiprocessing import Processdef func(): for i in range(1000): print('子进程',i)if __name__=='__main__': t = Process(target=func) # 创建子进程 t.start() for ii in range(1000): print('主进程', ii)
执行结果 同多线程
线程池与进程池
线程池:一次开辟一些线程 用户直接给线程池提交任务
线程任务交给线程池 我们不用管
导入线程,进程池 库
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
线程池的创建
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutordef fn(name):#创建一个任务 for i in range(1000): print(name,' ',i)with ThreadPoolExecutor(50) as t:#创建一个50个线程的线程池 for ii in range(100):#分配100个任务 t.submit(fn,name="线程{0}".format(ii))#提交任务的函数print('123')#外面的程序 只有等到线程任务执行完才执行
多线程一次性提交多个任务用for 循环
实战
农业网 1单个页面如何提取
2多个页面如何提取
思路 重要
定义函数 参入url参数可以爬取 url
再用线程池执行
适合多页的数据
代码
#爬取多页数据 效率高用线程池from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutorfrom lxml import etreeimport requestsdef pachon(url):#这是一个功能函数 # 爬取电影天堂 2019必看热片为例 reqs = requests.get(url) reqs.encoding = 'gb2312' tree = etree.HTML(reqs.text) res = tree.xpath('//*[@id="content"]/div/div/div/div[1]/div[2]/div/table/tbody/tr') jishu = 0 # 计数器控制每行11个书名 for i in res: name = i.xpath('./td[2]/div/a[1]/text()') print(name) with open('xiaoshuo.txt', 'a') as fp: fp.write(str(name)) if jishu == 5: fp.write('
') jishu = 0 jishu += 1#线程池with ThreadPoolExecutor(5) as t:#创建一个5个线程的线程池 for ii in range(1,6):#爬取前5页数据 url = 'http://www.quannovel.com/shuku/0_0_0_0_0_' + str(ii) + '_0.html' t.submit(pachon,url) print(url,'已经完成')
注意这是多个线程同时进行的 所以顺序可能会乱