多线程爬虫

普通多线程爬虫

import threading
import requests
import time

link_list = []
with open('alexa.txt', 'r') as file:
    file_list = file.readlines()
    for each in file_list:
        link = each.replace('\n', '')
        link_list.append(link)


class MyThread(threading.Thread):
    def __init__(self, name, link_range):
        threading.Thread.__init__(self)
        self.link_range = link_range
        self.name = name

    def run(self):
        print("Starting" + self.name)
        self.crawler(self.name, self.link_range)
        print("Exiting" + self.name)

    def crawler(self, thread_name, link_range):
        for i in range(link_range[0], link_range[1] + 1):
            try:
                requests.get(link_list[i], timeout=20)
            except Exception as e:
                print(thread_name, 'Error:', e)


if __name__ == '__main__':
    start = time.time()
    thread_list = []
    link_range_list = [(0, 200), (201, 400), (401, 600), (601, 800), (801, 1000)]
    # 创建新线程
    for i in range(1, 6):
        thread = MyThread("Thread-" + str(i), link_range_list[i - 1])
        thread.start()
        thread_list.append(thread)
    # 等待所有线程完成
    for thread in thread_list:
        thread.join()
    end = time.time()
    print('简单多线程爬虫的总时间为:', end - start)
    print("Exiting Main Thread")

在上述代码中,我们将1000个网页分成了5份,每一份是200个网页,即:link_ range_list=[(0,200)(201,400),(401,600),(601,800),(801,1000)]然后利用一个for循环创建5个线程,将这些网页分别指派到5个线程中运行,即:thread MyThread(“Thread-”+str(i), link_range_list[i-1])在每一个线程中,我们将之前单线程爬虫中获取网页部分的代码放入 crawler函数中,抓取这些网页。为了让这些子线程执行完后再执行主进程,这里使用了 threadjoin(方法等待各个线程执行完毕。最后,还会记录下所有线程执行完成的时间end- start,从而得到多线程爬虫完成获取1000个网页任务所需的时间。
上述代码存在一些可以改进之处:因为我们把整个链接列表分成了5等份,所以当某个线程先完成200条网页的爬虫后会退出线程,这样就只剩下有4个线程在运行。相对于5个线程,速度会有所下降,到最后剩下一个线程在运行时,就会变成单线程。

使用 Queue的多线程爬虫

使用 Queue. PythonQueue的模块中提供了同步的、线程安全的队列类,包括FFO(先入先出)队列Queue、LIFO(后入先出)队列Lifo Queue和优先级队列 PriorityQueue将这1000个网页 Queue放入的队列
中,各个线程都是从这个队列中获取链接,直到完成所有的网页抓取为止,代码如下:

import threading
import requests
import time
import queue as Queue

link_list = []
with open('alexa.txt', 'r') as file:
    file_list = file.readlines()
    for each in file_list:
        link = each.replace('\n', '')
        link_list.append(link)


class MyThread(threading.Thread):
    def __init__(self, name, q):
        threading.Thread.__init__(self)
        self.q = q
        self.name = name

    def run(self):
        print("Starting" + self.name)
        while True:
            try:
                self.crawler(self.name, self.q)
            except:
                break
        print("Exiting" + self.name)

    def crawler(self, thread_name, q):
        url = q.get(timeout=2)
        try:
            r = requests.get(url, timeout=20)
            print(q.qsize(), thread_name, r.status_code, url)
        except Exception as e:
            print(q.qsize(), thread_name, url, 'Error:', e)


if __name__ == '__main__':
    threadList = ["Thread-1", "Thread-2", "Thread--3", "Thread--4", "Thread-5"]
    workQueue = Queue.Queue(1000)
    threads = []
    start = time.time()
    # 创建新线程
    for tName in threadList:
        thread = MyThread(tName, workQueue)
        thread.start()
        threads.append(thread)
    # 填充队列
    for url in link_list:
        workQueue.put(url)
    # 等待所有线程完成
    for t in threads:
        t.join()
    end = time.time()
    print('Queue多线程爬虫的总时间为:', end - start)
    print("Exiting Main Thread")

与之前的简单多线程方法不同的是,在上述代码中,我们使用workQueue=Queue. Queue(1000)建立了一
个队列的对象,然后将这个对象传入了MyThread中,即:thread= MyThread(tName, workQueue)这个 workQueue里面有什么呢?我们可以使用一个for循环来填充队列:

for url in link_list:
   workQueue. put(url)

利用 workQueue.put(url)将这1000个网页加入队列中,然后就可以在线程中使用url=.get(timeout=2)获取队列中的链接了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值