多线程requests爬虫小结

  • 多线程requests爬虫
    • 单线程爬虫思路
    • 多线程爬虫思路
    • 多线程爬虫注意点
    • 完整代码

多线程requests爬虫

为了提高爬虫程序效率,由于python解释器GIL,导致同一进程中即使有多个线程,实际上也只会有一个线程在运行,但通过request.get发送请求获取响应时有阻塞,所以采用了多线程依然可以提高爬虫效率:

单线程爬虫思路

先来个单线程的思路图,针对规则url地址的网站:

Created with Raphaël 2.1.2 url list url list 发送请求,获取响应 发送请求,获取响应 提取数据 提取数据 保存 保存 单线程 单线程 单线程

多线程爬虫思路

待过两天有空再画个多线程的,先mark一下下拉。

多线程爬虫注意点

  • 解耦

    • 整个程序分为4部分,url list模块、发送请求,获取响应模块、数据提取模块、保存模块,如果某一模块出现问题,互相之间不会影响。
  • 规则url

    • 本文程序针对规则url,比如贴吧、内涵段子、糗事百科等,其他不规则url网址,在程序结构上只需要修改url部分即可。
  • 资源竞争

    • 由于使用了多线程,不同线程在共享数据时,容易产生资源竞争,假设共享数据放入列表中,那么同一时刻有可能2个线程去列表中取同一个数据,重复使用。
    • 解决办法是使用队列,使得某一线程get数据时,其他线程无法get同一数据,真正起到保护作用,类似互斥锁。
    • 下面以url列表为例对队列进行说明(只列举部分代码,全代码在最下方):
import requests
import queue import Queue
pass

class Spider_s:
        def __init__(self):
            self.url_regular = pass
            self.headers = pass
            self.myurl_queue = Queue()
            pass
        def myurl_list(self):
            for i in range(100): #构造100个规则rul地址
                self.myurl_queue.put(self.url_regular.format(i+1)) #把100个url地址放入队列中
        pass
  • 队列常用方法介绍
    • 首先from queue import Queue (q=Queue()):
方法 说明
q.empty() 判断队列q是否为空,返回True或False
q.full() 判断队列q是否满了,返回True或False
q.qsize() 获取队列中保存数据的个数
方法 说明 注意点
q.get() 从队列中取一个数据
q.get_nowait() 不等待直接取

注意:get和get_nowait两者的区别是当队列取完了即队列为空时,get()会阻塞,等待着新数据继续取,而get_nowait()会报错.

方法 说明
q.put() 把数据放入队列
q.put_nowait() 不等待直接取

注意:put和put_nowait 两者的区别是当队列为满时,put_nowait()会报错.

  • 队列重点方法join task_done注意点

    • 重点注意q.join()方法,在python3中,join()会等待子线程、子进程结束之后,主线程、主进程才会结束.
    • 重点注意task_done()的使用:
      • 队列中put,队列计数会+1,get时计数不会减1,但当get+task_done时,队列计数才会减1,如果没有task_done则程序跑到最后不会终止哟.
      • 注意task_done()的位置,应该放在方法的最后以保证所有任务全部完成.
  • setDaemon方法
    把子线程设置为守护线程,即认为该方法不是很重要,记住主线程结束,则该子线程结束

  • join方法和setDaemon方法搭配使用
    主线程进行到join()处,join的效果是让主线程阻塞,等待子线程中队列任务完成之后再解阻塞,等子线程结束,join效果失效,之后主线程结束,由于使用了setDaemon(True),所以子线程跟着结束,此时整个程序结束。

完整代码

  • 本文以xxx为例,完整代码如下:下次补上啦啦啦啦

你可能感兴趣的:(爬虫)