python多线程爬取糗百

分析多线程爬取糗百

为了加快爬取网站的效率,我们将使用多线程来爬取任务,我们最简单爬取数据大致思路可以分为三步:

  • 1.爬取数据
  • 2.解析数据
  • 3.保存数据

在使用多线程时,我们就变成了多个线程爬取数据,解析数据。这样我们需要借助队列,并且上锁,来避免线程之间的恶意竞争资源。那么我们可以将思路步骤分为:

  • 1.爬取数据写入队列
  • 2.队列读取数据
  • 3.解析数据写入队列
  • 4.队列读取数据
  • 5.保存数据

代码解析如下:

导包

导入锁,线程
from threading import Lock,Thread
导入队列
from queue import Queue
请求处理
import requests
解析库
from lxml import etree
导入数据库
import pymongo

采集数据类


class CrawlThread(Thread):
    def __init__(self,threadName,pageQueue,dataQueue):
         继承父类实例属性的同时  拓展父类属性
        super().__init__()
        线程名
        self.threadName = threadName
        页码队列
        self.pageQueue = pageQueue
        数据队列
        self.dataQueue = dataQueue
        请求头
        self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36",}
    重新定义底层run方法
    def run(self):
        初始一个静态url,为拼接做准备
        url = "https://www.qiushibaike.com/text/page/%s/"
        while True:
            try:
                 可选参数block,默认值为Ture
                如果队列为空  block 为 True 那么进入阻塞状态
                 如果队列为空  block 为 False 那么会抛出异常
                从队列中获取要拼接url的页码
                取一个数字,先进先出
                page = self.pageQueue.get(block=False)
                print("%s开始工作..."%self.threadName)
                response = requests.get(url=url%page,headers=self.headers)
                content = response.text
                 获取请求的页面,并写入队列中,已备解析使用
                self.dataQueue.put(content)
                print("%s工作结束..."%self.threadName)
            except:
                break
                

解析数据类


class ParseThread(Thread):
    def __init__(self,threadName,dataQueue,lock):
        同理调用父类初始化方法
        super().__init__()
        自定义解析线程名称
        self.threadName = threadName
        自定义数据队列
        self.dataQueue = dataQueue
        自定义锁
        self.lock = lock
    重新写run方法,处理数据
    def run(self):
        while True:
            try:
                从采集数据的队列中获取到页面
                html = self.dataQueue.get(block=False)
                print("%s开始处理数据.........."%self.threadName)
                将获取的页面传递给parse函数进行解析
                self.parse(html)
                print("%s数据处理完毕.........."%self.threadName)
            except:
                break
    解析页面
    def parse(self,html):
        转成lxml进行匹配
        html = etree.HTML(html)
        div_list = html.xpath('//div[@id="content-left"]/div')
        for div in div_list:
            try:
                name = div.xpath('.//div[@class="author clearfix"]/a/h2/text()')[0]
                joke = div.xpath('.//span[@class="stats-vote"]/i/text()')[0]
                con = div.xpath('.//span[@class="stats-comments"]//i/text()')[0]
                item = {"作者": name, "搞笑": joke, "评论": con}
                上个锁,当一个线程进行解析时,其它将不解析这一条
                 with 后面有两个必须执行的操作:__enter__ 和 _exit__
                                不管里面的操作结果如何,都会执行打开、关闭
                                 打开锁、处理内容、释放锁
                with self.lock:
                    讲述得到的数据传到save函数中进行数据库保存
                    self.save(item)
            except:
                pass
    mongo数据库保存数据
    def save(self,item):
        建立mongo数据库连接
        conn = pymongo.MongoClient("localhost",27017)
        创建数据库
        db = conn.qiubai
        创建表
        table = db.qiubai
        插入数据
        table.insert_one(item)
        关闭数据库
        conn.close()

主程序准备类工作的材料

def main():
    页码队列
    pageQueue = Queue()
    数据队列
    dataQueue = Queue()
    准备锁
    lock = Lock()
    构建循环,准备页码
    for i in range(1,14):
        将页码写入页码队列
        pageQueue.put(i)

**采集线程**
    准备三个采集线程名字
    crawlList = ["采集1号","采集2号","采集3号"]
    存储三个采集线程
    ThreadCrawl = []
    for var in crawlList:
        实例化采集类
        c = CrawlThread(var,pageQueue,dataQueue)
        #启动采集线程
        c.start()
        将线程写入列表
        ThreadCrawl.append(c)
    for var in ThreadCrawl:
				        采集线程等待,解决程序紊乱
				        join的作用:join所完成的工作就是线程同步,
				         即主线程任务结束之后,进入阻塞状态,一直等待其他的
				         子线程执行结束之后,主线程再终止
				         
        var.join()
解析线程
    准备三个解析线程名字
    parseList = ["解析1号","解析2号","解析3号"]
    ThreadParse = []
    for var in parseList:
        实例化解析线程类
        p = ParseThread(var,dataQueue,lock)
        启动解析线程
        p.start()
        存储三个解析线程
        ThreadParse.append(p)
    for var in ThreadParse:
        解析线程等待
        var.join()
if __name__ == '__main__':
    main()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值