文章目录
- 1.通过异步操作提高爬虫效率
- 2.多线程
- 3.多进程
- 4.线程池与进程池
- 5.线程池实例-新发地菜价保存
- 6.总结
1.通过异步操作提高爬虫效率
一般爬虫过程为,请求网页-响应请求-从响应中提取数据-保存有用数据,每次都是这样,如果有大量的网站,重复这样操作肯定很慢。
现在可以通过异步操作,提高爬虫的效率。
这里异步操作可以是多线程,多进程以及协程。
这里有存在两个容易混淆的定义,线程和进程
进程是资源单位(某几块地方) 每个进程必须包含至少一个线程
线程是执行单位 (这块地方工作的人)
2.多线程
创建多线程有两种方法,第一种是直接调用函数thread函数,将需要创建的新进程函数和传参放入,然后start,就可以开始执行。
import threading
def fun (n,m):
for i in range(n):
print('子线程',i+m)
if __name__=='__main__':
n=100
m=200
T=threading.Thread(target=fun,args=(n,m)) #创建一个新的线程并安排任务 通过args传递参数 只剩下一个参数时候后面的逗号必须要
T.start() #可以开始工作,后面要看cpu是否给他分配
for i in range(n):
print('主线程',i)
也可以通过类的继承方法,创建一个继承thread的类,直接调用新类,即可。
class MyThread(threading.Thread):
def __init__(self,funs,args):
threading.Thread.__init__(self) #不要忘记调用Thread的初始化方法
self.funs=funs
self.args=args
def run(self): #这里需要写成固定的run 因为线程执行时候被执行的就是run
self.funs(*self.args)
def fun(m):
for i in range(100):
print('子线程1',i+m)
def fun1(m):
for i in range(m):
print('子线程2',i)
if __name__ == '__main__':
T=MyThread(fun,(100,)) #继承thread类的方法
T2=MyThread(fun1,(200,)) #继承thread类的方法
T.start()
T2.start()
T.join() #等待t这个线程执行完毕 再执行下面的线程
for i in range(100):
print('主线程',i)
3.多进程
多进程和多线程使用过程很相似,但是里面实现过程,完全不同,因为多进程用的比较少,所以就简单了解下
from multiprocessing import Process
def fun(m):
for i in range(m):
print('子进程',i)
if __name__=='__main__':
P=Process(target=fun,args=(100,))
P1=Process(target=fun,args=(100,))
P.start()
P1.start()
for i in range(100):
print('主进程',i)
4.线程池与进程池
由于用的时候可能要创建很多线程,但是要不浪费线程,要重复使用这些线程,就出现了线程池和进程池的概念。
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
def fun(name):
for i in range(100):
print(name,i)
if __name__=='__main__':
with ThreadPoolExecutor(5) as T: #线程池创建5个线程
for i in range(20): #给线程池20个任务
T.submit(fun,name=f'线程{i}') #提交任务
#必须等以上结束下面才会执行 with 里面相当于有start 和join的功能
print('over!!')
5.线程池实例-新发地菜价保存
import requests
from concurrent.futures import ThreadPoolExecutor
import csv
import time
from collections import deque
url = 'http://www.xinfadi.com.cn/getPriceData.html'
data_queue = deque([])
def getPriceData(pagenumber):
data={
'limit': 20,
'current': pagenumber}
reap = requests.post(url= url,data=data)
reapcontent= reap.json()['list']
reap.close()
data_queue.append(['PG-%d'%pagenumber])
for i in reapcontent:
data_queue.append([i['prodCat'],i['prodName'],i['avgPrice'],i['highPrice'],i['lowPrice'],i['place'],i['pubDate']])
#print(pagenumber,'over!!')
def dataStorage(): #保存数据
with open('新发地菜价.csv',mode='w+',encoding='utf-8',newline='') as f: #保存文件
csvWrite = csv.writer(f)
while True:
try:
dataer = data_queue.popleft()
csvWrite.writerow(dataer) #将结果保存到csv
except:
print('数据已经全部保存!')
break
if __name__=='__main__':
time_start = time.time() #开始计时
with ThreadPoolExecutor(20) as t: #进程池里面进程数量为10
for i in range(200): #给进程池100个任务 打开200个
t.submit(getPriceData,pagenumber=i+1)
dataStorage()
print('over!!')
time_end = time.time() #结束计时
time_c= time_end - time_start #运行所花时间
print('time cost', time_c, 's')
6.总结
今天的多线程其实用途蛮大,对其他语言也有启发性,挺好的,今天就看这么多把。明天继续。