python之单线程和多线程访问网站

标签: python 线程
39人阅读 评论(0) 收藏 举报
分类:

——众所周知,在python爬虫中我们经常因为爬虫的速度慢而烦恼。于是就在学习中学习了一下多线程访问网站。在了解多线程的时候我们需要先了解单线程问题。我对单线程做一简单的分析。


1、单线程问题
——单线程就是我们最原始的方法,直接写出访问网站的脚本不需要任何多线程处理例如我们要访问300个网站,网站下载链接点击这里进入下载,我们现在应该已经下载到了我们所需要的300个URL文件。
下来看一下这段单线程访问网站的代码:

import requests
import time

link_list = []
with open('url.txt','r') as file:
    file_list = file.readlines()
    for eachone in file_list:
        link = eachone.split('\t')[1]
        link = link.replace('\n','')
        link_list.append(link)
    start = time.time()
    for eachone in link_list:
        try:
            r = requests.get(eachone)
            print(r.status_code,eachone)
        except Exception as e:
            print('Error',e)
    end = time.time()
    print('串行的总时间为:',end-start)

——从这段代码中我们可以清晰的看到这就仅仅是一个单线程访问的代码,我们可以看到它的运行是时间比较长。
这是单线程运行的时间


2、简单的多线程爬虫

——多线程问题,首先做的是我们要利用threading模块提供的Thread类方法来处理线程,里面有以下几个方法:

  • run():用以表现线程活动的方法;
  • start():启动线程活动;
  • join([time]):等待至线程中止,阻塞调用线程直至线程的join()方法被调用为止;
  • isAlive():返回线程是否是活动的;
  • getName():返回线程名;
  • setName():设置线程名。

写多线程问题代码的基本步骤:
1)创建新的线程;2)开启新线程;3)添加线程带线程列表里面;4)等待所有线程完成。

——在完成这个访问网站的爬虫中呢,由于网站比较多,需要开启多个线程对,这300个网站进行一个平均分配,这样才能较快的完成爬虫。
下面我们看一下代码:
代码首先我们需要定义一个公共的函数:

def link_list():
    link_list = []
    with open('url.txt','r') as file:
        file_list = file.readlines()
        for eachone in file_list:
            link = eachone.split('\t')[1]
            link = link.replace('\n','')
            link_list.append(link)
    return link_list

这个多线程的代码:

import requests
import threading
import time

link_list = link_list()
start = time.time()
class myThread(threading.Thread):
    def __init__(self,name,link_range):
        threading.Thread.__init__(self)
        self.name = name
        self.link_range = link_range
    def run(self):
        print("Starting " + self.name)
        crawler(self.name,self.link_range)
        print("Exiting " + self.name)

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

thread_list = []
#这就是对300个链接进行平均分配
link_rangs_list = [(0,60),(61,120),(121,180),(181,240),(241,300)]
#创建新线程
for i in range(1,6):
    thread = myThread("Thread-" + str(i),link_rangs_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")

简单的多线程运行的时间很明显就能看到它的运行时间有了明显的缩减,如下图运行结果所示:
简单的多线程运行结果


3、使用Queue的多线程爬虫
——我们在使用多线程爬取时会发现一个这样的问题,当线程运行完之后开始结束的时候,会变成单线程问题。所以接下来我们会利用Queue模块中提供的同步的线程安全的队列类(包括FIFO(First In First Out)队列Queue、LIFO(Last In First)队列LifoQueue和优先级队列PriorityQueue),进行处理这些URL,每个线程都是自动获取链接,直接完成所有的网页抓取活动。
看一下代码:

import requests
import threading
import time
import queue as Queue

link_list = link_list()
start = time.time()
class myThread(threading.Thread):
    def __init__(self,name,q):
        threading.Thread.__init__(self)
        self.name = name
        self.q = q
    def run(self):
        print("Starting " + self.name)
        while True:
            try:
                crawler(self.name,self.q)
            except:
                break
        print("Exiting " + self.name)

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

threadList = ["Thread-1","Thread-2","Thread-3","Thread-4","Thread-5"]
workQueue = Queue.Queue(300)
threads = []
#创建新线程
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')

这个的运行时间相对于多线程爬虫相对来说能快一点点。多线程主要是对所有的URL进行了一个平均分配,有些窗口处理的速度快,所以先处理完了,其他窗口还没有处理完,而没处理完的窗口的资源不能够到处理完的窗口上去,这样会造成资源的闲置。Queue方法相对于是前面这种方法来说所开启的线程那个有位置就给那个线程分配处理资源,所以相对来说就能快一点。

代码下载链接:点击这里

查看评论

单线程与多线程的比较

假设有100个数据要处理   下面分别采用单线程和多线程进行来对比分析  说明采用多线程的好处 单线程的代码如下 package xiancheng; import java.util.Vect...
  • zhang434
  • zhang434
  • 2013-11-20 09:24:17
  • 1187

多线程不能不知道的之单线程和多线程的比较

早期的计算硬件十分复杂,但是操作系统执行的功能确十分的简单。那个时候的操作系统在任一时间点只能执行一个任务,也就是同一时间只能执行一个程序。多个任务的执行必须得轮流执行,在系统里面进行排队等候。  ...
  • mayfla
  • mayfla
  • 2016-01-18 17:30:45
  • 877

python 单线程与多线程爬虫

帮别人写爬虫,先是单线程,太慢,改了多线程 1.单线程 import urllib import urllib.request import requests import xlwt import...
  • zyxyzz
  • zyxyzz
  • 2017-10-22 15:09:15
  • 263

python多线程(1)--单线程和多线程

关于进程和线程,学过操作系统原理的人都懂。如何使用多线程。python是支持多线程的,并且是native的线程。主要是通过thread和threading这两个模块来实现的。 python的thre...
  • lw_zhaoritian
  • lw_zhaoritian
  • 2016-07-19 18:57:31
  • 1861

python多线程与单线程之间的差距

对于python多线程与单线程之间有多少差距呢?今天用一个小例子比较一下。 说明:爬取代理ip网站ip并用代理ip访问某网站,看执行后的用时多少。 单线程版 # -*- coding: ...
  • zsd747289639
  • zsd747289639
  • 2017-02-19 18:36:42
  • 1703

python 单线程和多线程

单线程, 在好些年前的MS-DOS时代,操作系统处理问题都是单任务的,我想做听音乐和看电影两件事儿,那么一定要先排一下顺序。#coding=utf-8 import threading from ti...
  • u011510825
  • u011510825
  • 2017-02-27 16:50:14
  • 508

Python中单线程、多线程和多进程的效率对比实验

Python是运行在解释器中的语言,查找资料知道,python中有一个全局锁(GIL),在使用多进程(Thread)的情况下,不能发挥多核的优势。而使用多进程(Multiprocess),则可以发挥多...
  • u011489043
  • u011489043
  • 2017-04-03 21:22:49
  • 401

PHP是单线程的,如何应对大量的http访问?

http://bbs.csdn.net/topics/390778072
  • zunguitiancheng
  • zunguitiancheng
  • 2016-08-10 00:54:54
  • 1903

深入SQLite多线程的使用总结详解

SQLite支持3种线程模式:   单线程:这种模式下,没有进行互斥,多线程使用不安全。禁用所有的mutex锁,并发使用时会出错。当SQLite编译时加了SQLITE_THREADSAFE=0参数,...
  • liangzhao_jay
  • liangzhao_jay
  • 2015-05-11 11:29:09
  • 2027

单线程和多线程访问数据库性能比较一性能比较部分(oracle 数据库)

单线程和多线程访问数据库性能比较(oracle 数据库,C++Builder实现,odac4)说明:本文主要说明单线程和多线程访问数据库性能的性能比较,关键词在数据库(DataBase),线程(Thr...
  • runnerrunning
  • runnerrunning
  • 2006-03-02 14:49:00
  • 10412
    个人资料
    等级:
    访问量: 120
    积分: 94
    排名: 142万+
    文章存档
    资料库