我们运用爬虫进行数据爬取的过程中,如果遇到海量的数据导致爬取时间过长无疑狠影响效率。这时,聪明的爬虫工程师就想到了一种爬取提高效率,缩短时间的方法——多线程爬虫。

Python 多线程 小说爬虫 多线程爬虫案例_Python 多线程 小说爬虫


我们列举一个案例——爬取腾讯招聘技术类前十页的数据。先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))

以上,我们运用消费者和生产者的思维,将网页下载器方法和解析器方法分为来个类方法,在运用多线程的方法,对下载的网页信息进行“加速”,大大提高了下载器的效率。

以上