我们运用爬虫进行数据爬取的过程中,如果遇到海量的数据导致爬取时间过长无疑狠影响效率。这时,聪明的爬虫工程师就想到了一种爬取提高效率,缩短时间的方法——多线程爬虫。
我们列举一个案例——爬取腾讯招聘技术类前十页的数据。先po代码!
import requests
from urllib import parse
from bs4 import BeautifulSoup
import threading
import time
from queue import Queue
content_q = Queue #创建了一个response队列
flag =False #立一个flag,令他为false
class Thread_product(threading.Thread): #这里用了生产者和消费者的概念,将获取网页数据的类方法作为生产者,解析网页数据生成想要数据的类方法作为消费者
def __init__(self,i,q):
threading.Thread.__init__(self)
self.i=i
self.q=q
def run(self):
while True:
if self.q.empty(): #当页码队列为空时,结束传值
break
timeout = 4 #设定请求次数,为四次
page = self.q.get() #创建页码——从页码队列中传值得到
while True: #请求次数,一共四次
if timeout == 0: #当请求四次仍然没有传值,则跳出
break
try:
url = 'https://hr.tencent.com/position.php?keywords=python&lid=2156&tid=0&start={}'.format(page*20)
response = self.content(url) #执行网页下载器
content_q.put(response) #将代码传入下载器的队列
break
except:
timeout-=1
def content(self,url): #获取网页信息方法
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
}
response = requests.get(url=url, headers=headers).text
return response
class Thread_consumer(threading.Thread):
def __init__(self, i, content_q):
threading.Thread.__init__(self)
self.i = i
self.q = content_q #实例化网页信息队列
def run(self): #运行函数
while not flag: #如果状态为True,则执行分析操作
try:
self.data(self.q.get(block=False)) #block=false是当队列为空时,停止进行分析
except:
pass
def data(self,response):
##页面解析
soup = BeautifulSoup(response, 'lxml')
tr_list = soup.find_all('tr')
re_box = tr_list[1:-2]
for tr in re_box:
td_list = tr.select('td')
# print(td_list)
# 职位名称:
name = td_list[0].select('a')[0].get_text()
# 职位类型:
type = td_list[1].get_text()
# 人数:
num = td_list[2].get_text()
# 地点:
place = td_list[3].get_text()
# 发布时间:
public_time = td_list[4].get_text()
item = name + ',' + type + ',' + num + ',' + place + ',' + public_time + '\n'
with open('tenxun.txt', 'a', encoding='utf-8')as f:
f.write(item)
if __name__ == '__main__':
start_time = time.time() #获得程序开始时的时间戳
q=Queue() #这里创建队列,将页码传进队列,保证队列的get方法可以每次都能get出一个页码
for i in range(10): #创建页码队列
q.put(i)
#线程列表
crawl_list = [] #创建一个线程列表,将每一个对应了的页码和线程传进来
crawl_name = ['a1','a2','a3','a4','a5','a6','a7','a8','a9','a10',] #这里创建了一个线程名列表,创建的线程越多,效率越高
for i in crawl_name:
crawl = Thread_product(i,q) #这里创建生产者,传进生产者的类方法中,传进页码和线程
crawl.start() #执行这个程序
crawl_list.append(crawl) #每执行一次都王线程列表中传进生产者
customers = ['customers1', 'customers2', 'customers3'] #这个表是把所有执行解析的消费者列出来
for name in customers:
customer = Thread_consumer(name,content_q) #这里创建消费者,往解析类中传消费者名和已经爬取到的网页信息的队列
customer.start() #开始这个解析程序
for threadi in crawl_list: #阻塞主线程 为记录爬取时间
threadi.join()
end_time = time.time()#获得程序结束时的时间戳
print('任务完成耗,耗时{}'.format(end_time-start_time))
以上,我们运用消费者和生产者的思维,将网页下载器方法和解析器方法分为来个类方法,在运用多线程的方法,对下载的网页信息进行“加速”,大大提高了下载器的效率。
以上