美文网首页
多线程爬虫

多线程爬虫

作者: libdream | 来源:发表于2018-12-27 10:42 被阅读0次

Python通过两个标准库threadthreading提供对线程的支持。thread提供了低级别的、原始的线程以及一个简单的锁。threading是对thread进行封装的高级模块,一般情况下只需要学习这个就可以了。

threading 模块提供的其他方法:

threading.currentThread()     返回当前的线程变量。
threading.enumerate()    返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount()   返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:

run()      用以表示线程活动的方法。
start()    启动线程活动。
join([time])  等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
isAlive()     返回线程是否活动的。
getName()     返回线程名。
setName()     设置线程名。

线程同步

如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。

使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。如下:

多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)。但是当线程需要共享数据时,可能存在数据不同步的问题。

考虑这样一种情况:一个列表里所有元素都是0,线程"set"从后向前把所有元素改成1,而线程"print"负责从前往后读取列表并打印。

那么,可能线程"set"开始改的时候,线程"print"便来打印列表了,输出就成了一半0一半1,这就是数据的不同步。为了避免这种情况,引入了锁的概念。

锁有两种状态——锁定和未锁定。每当一个线程比如"set"要访问共享数据时,必须先获得锁定;如果已经有别的线程比如"print"获得锁定了,那么就让线程"set"暂停,也就是同步阻塞;等到线程"print"访问完毕,释放锁以后,再让线程"set"继续。

经过这样的处理,打印列表时要么全部输出0,要么全部输出1,不会再出现一半0一半1的尴尬场面。

线程优先级队列( Queue)

Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。

Queue模块中的常用方法:

Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False
Queue.full 与 maxsize 大小对应
Queue.get([block[, timeout]])获取队列,timeout等待时间
Queue.get_nowait() 相当Queue.get(False)
Queue.put(item) 写入队列,timeout等待时间
Queue.put_nowait(item) 相当Queue.put(item, False)
Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
Queue.join() 实际上意味着等到队列为空,再执行别的操作

多线程爬虫使用方法如下:
首先导入多线程以及队列模块

import threading
import queue as Queue

示例代码如下:

import pymongo
import requests
import threading
import queue as Queue
import time


client = pymongo.MongoClient('localhost', 27017)
mydb = client['mydb']
library = mydb['library']#连接数据库及集合

headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 \
(KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
    }

class myThread(threading.Thread):   #继承父类threading.Thread
    #初始化参数
    def __init__(self, name, q):
        threading.Thread.__init__(self)
        self.name = name
        self.q = q

    def run(self):  #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数 
        print('开始' + self.name)
        while True:
            try:
                crawler(self.name, self.q)  #调用crawler()爬虫函数
            except:
                break
        print('退出' + self.name)

def crawler(threadName, q):
    #自定义爬虫函数,传入线程名和队列
    url = q.get(timeout=2)  #获取队列中的url,timeout是等待时间
    try:
        r = requests.get(url,timeout=20)
        print(q.qsize(), threadName, r.status_code, url)    #打印队列大小,进程名等...
    except Exception as e:
        print(q.qsize(), threadName, url, 'Error:', e)
        

if __name__ == '__main__':        
    urls = [items['real_url'] for items in library.find()]  #待爬取url列表
    start = time.time() #计时开始
    threadList = ['Thread-1','Thread-2','Thread-3','Thread-4','Thread-5']   #线程名列表
    workQueue = Queue.Queue(len(urls))  #指明队列存放的上限,一旦达到上限,插入会导致阻塞,直到队列中的数据被消费掉。如果maxsize小于或者等于0,队列大小没有限制。
    threads = []    #定义空进程列表

    #遍历线程名列表,创建新线程
    for tName in threadList:
        thread = myThread(tName, workQueue) #实例化新线程,传入线程名和队列上限
        thread.start()      #开启线程
        threads.append(thread)  #添加线程到线程列表

    #将url填充到workQueue队列
    for url in list(urls):
        workQueue.put(url)

    #等待所有线程完成
    for t in threads:
        t.join()

    end = time.time()
    print('Queue多线程爬虫的总时间为:', end-start)
    print('退出主线程')


相关文章

  • Python爬虫第七天:多线程爬虫|Scrapy框架

    内容简述: 一:多线程爬虫 二:Scrapy框架 一:多线程爬虫原理 【示例见代码】 二:Scrapy框架...

  • Python爬虫基础教程(三)

    九、多线程爬虫 9.1利用多线程爬虫爬取糗事百科的资源: 十、爬虫代码总结: 要实现一个完整的爬虫,无外乎4...

  • 「爬虫」12爬虫之多线程爬虫

    1.多线程爬虫 多线程就是程序中的某些程序段并行执行,合理地设置多线程,可以让爬虫效率更高。 2.单线程实例 以爬...

  • Thread

    队列 线程锁 多线程,线程池 队列 多线程爬虫示例 多线程 自定义线程 线程池

  • [CP_12] Python多线程爬虫应用实践(社招职位名称获取

    目录结构 一、多线程爬虫的使用 1. 多线程实现 <关联> [Pt_04] Python进程|多进程|线程|多线程...

  • 爬虫基础05

    多线程爬虫 队列(from multiprocessing import Queue)UrlQueue = Que...

  • 男子大学生的無駄日常

    关键词:Python,爬虫,requests,BeautifulSoup,opencv,python多线程,正则表...

  • 多线程爬虫实战——爬取糗事百科

    多线程爬虫思路 我们之前写的爬虫网页,往往是等待一页内容爬取完毕后,再爬取另一页内容,效率很低,而用多线程和队列之...

  • 多线程爬虫

    1、多线程爬虫,可考虑放到线程池,把我们需要解析的URL 地址存入我们的队列中,然后去触发多线程进行操作、 代码如...

  • 多线程爬虫

    多线程爬虫 有些时候,比如下载图片,因为下载图片是一个耗时的操作。如果采用之前那种同步的方式下载。那效率肯会特别慢...

网友评论

      本文标题:多线程爬虫

      本文链接:https://www.haomeiwen.com/subject/ipvhlqtx.html