Python爬虫:单线程、多线程、多进程

news2024/12/24 16:47:22

在这里插入图片描述

前言

在使用爬虫爬取数据的时候,当需要爬取的数据量比较大,且急需很快获取到数据的时候,可以考虑将单线程的爬虫写成多线程的爬虫。下面来学习一些它的基础知识和代码编写方法。

一、进程和线程

进程可以理解为是正在运行的程序的实例。进程是拥有资源的独立单位,而线程不是独立的单位。由于每一次调度进程的开销比较大,为此才引入的线程。一个进程可以拥有多个线程,一个进程中可以同时存在多个线程,这些线程共享该进程的资源,线程的切换消耗是很小的。因此在操作系统中引入进程的目的是更好地使多道程序并发执行,提高资源利用率和系统吞吐量;而引入线程的目的则是减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能。
下面用简单的例子进行描述,打开本地计算机的”任务管理器”如图1所示,这些正在运行的程序叫作进程。如果将一个进程比喻成一个工作,指定10个人来做这份工作,这10个人就是10个线程。因此,在一定的范围内,多线程效率比单线程效率更高。
在这里插入图片描述
图1.任务管理器

二、Python中的多线程与单线程

在我们平时学习的过程中,使用的主要是单线程爬虫。一般来说,如果爬取的资源不是特别大,使用单线程即可。在Python中,默认情况下是单线程的,简单理解为:代码是按顺序依次运行的,比如先运行第一行代码,再运行第二行,依次类推。在前面章节所学习知识中,都是以单线程的形式实践的。
举个例子,批量下载某网站的图片,由于下载图片是一个耗时的操作,如果依然采用单线程的方式下载,那么效率就会特别低,意味着需要消耗更多的时间等待下载。为了节约时间,这时候我们就可以考虑使用多线程的方式来下载图片。
threading模块是Python中专门用来做多线程编程的模块,它对thread进行了封装,使用更加方便。例如需要对写代码和玩游戏两个事件使用多线程进行,案例代码如下。

import threading
import time
# 定义第一个
def coding():
    for x in range(3):
        print('%s正在写代码\n' % x)
        time.sleep(1)
# 定义第二个
def playing():
    for x in range(3):
        print('%s正在玩游戏\n' % x)
        time.sleep(1)
# 如果使用多线程执行
def multi_thread():
    start = time.time()
    #  Thread创建第一个线程,target参数为函数命
    t1 = threading.Thread(target=coding)
    t1.start()  # 启动线程
    # 创建第二个线程
    t2 = threading.Thread(target=playing)
    t2.start()
    # join是确保thread子线程执行完毕后才能执行下一个线程
    t1.join()
    t2.join()
    end = time.time()
    running_time = end - start  
    print('总共运行时间 : %.5f 秒' % running_time)
# 执行
if __name__ == '__main__':
    multi_thread()  # 执行单线程

运行结果如图2所示:
图2.多线程运行结果
图2.多线程运行结果
那么执行单线程会消耗多少时间,案例代码如下所示。

import time
# 定义第一个
def coding():
    for x in range(3):
        print('%s正在写代码\n' % x)
        time.sleep(1)
# 定义第二个
def playing():
    start = time.time()
    for x in range(3):
        print('%s正在玩游戏\n' % x)
        time.sleep(1)
    end = time.time()
    running_time = end - start
    print('总共运行时间 : %.5f 秒' % running_time)
def single_thread():
    coding()
    playing()
# 执行
if __name__ == '__main__':
    single_thread()  # 执行单线程

运行结果如图3所示:
在这里插入图片描述
图3.单线程运行结果
经过以上多线程和单线程的运行结果,可以看出多线程中写代码和玩游戏是一起执行的,单线程中则是先写代码再玩游戏。从时间上来说,可能只有细微的差距,当执行工作量很大的时候,便会发现多线程消耗的时间会更少,从这个案例中我们也可以知道,当所需要执行的任务并不多的时候,只需要编写单线程即可。

三、单线程改为多线程

以某直播的图片爬取为例,案例代码如下:

import requests
from lxml import etree
import time
import os

dirpath = '图片/'
if not os.path.exists(dirpath):
    os.mkdir(dirpath)  # 创建文件夹

header = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36'
}
def get_photo():
    url = 'https://www.huya.com/g/4079/'  # 目标网站
    response = requests.get(url=url, headers=header)  # 发送请求
    data = etree.HTML(response.text)  # 转化为html格式
    return data

def jiexi():
    data = get_photo()
    image_url = data.xpath('//a//img//@data-original')
    image_name = data.xpath('//a//img[@class="pic"]//@alt')
    for ur, name in zip(image_url, image_name):
        url = ur.replace('?imageview/4/0/w/338/h/190/blur/1', '')
        title = name + '.jpg'
        response = requests.get(url=url, headers=header)  # 在此发送新的请求
        with open(dirpath + title, 'wb') as f:
            f.write(response.content)
        print("下载成功" + name)
        time.sleep(2)

if __name__ == '__main__':
        jiexi()

如果需要修改为多线程爬虫,只需要修改主函数即可,例如创建4个线程进行爬取,案例代码如下所示:

if __name__ == "__main__":
    threads = []
    start = time.time()
    # 创建四个进程
    for i in range(1, 5):
        thread = threading.Thread(target=jiexi(), args=(i,))
        threads.append(thread)
        thread.start()
    for thread in threads:
        thread.join()
    end = time.time()
    running_time = end - start
    print('总共消耗时间 : %.5f 秒' % running_time)
    print("全部完成!")  # 主程序

四、图书推荐

在这里插入图片描述

本书介绍了Python3网络爬虫的常见技术。首先介绍了网页的基础知识,然后介绍了urllib、Requests请求库以及XPath、Beautiful Soup等解析库,接着介绍了selenium对动态网站的爬取和Scrapy爬虫框架,最后介绍了Linux基础,便于读者自主部署编写好的爬虫脚本。
本书主要面向对网络爬虫感兴趣的初学者。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/877114.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL索引总结

MySQL索引总结 1.索引的概念、作用与使用场景 本质上就是减少读写磁盘的次数。 索引是一种特殊的文件,包含这对数据表中所有记录的引用指针,可以对表中的一列或多列创建索引,并指定索引的类型,每种类型都有对应数据结构实现。 …

大数据必回之LSM树

LSM树(Log-Structured-Merge-Tree)并不像B、红黑树一样是一颗严格的树状数据结构,它其实是一种存储结构,像HBase、RocksDB这些NoSQL存储都是采用LSM树。它是一种分层、有序、面向磁盘的数据结构,核心思想是顺序写性能远…

Leetcode链表篇 Day3

.24. 两两交换链表中的节点 - 力扣(LeetCode) 1.构建虚拟结点 2.两两一组,前继结点一定在两两的前面 3.保存结点1和结点3 19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode) 1.双指针:快慢指针 两个指针的差…

初步认识OSI/TCP/IP一(第三十八课)

1 初始OSI模型 OSI参考模型(Open Systems Interconnection Reference Model)是一个由国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)联合制定的网络通信协议规范,它将网络通信分为七个不…

React antd tree树组件 - 父子节点没有自动关联情况下 - 显示半选、全选状态以及实现父子节点互动

实现的效果图如下: 如Ant Design Vue 中所示,并没有提供获取半选节点的方法,当设置checked和checkStrictly时,父子节点也不再自动关联了 前提:从后端可以获取的数据分别是完整的树型数据、所有选中的节点数据&#…

在pycharm中对使用脚本文件运行的程序进行调试

在github中下载的许多项目都可以使用给出的脚本文件运行,本文介绍如果在pycharm中对使用脚本文件运行的程序进行调试的方法。 1.点击 edit configurations 2.选择要debug的py文件,并且填写参数 3.点击运行旁边的debug按钮

odoo16 tree视图没有导出按钮

odoo16 tree视图没有导出按钮 做了一个odoo应用,很奇怪,同样的角色,不同的用户,有些有导出按钮,有些没有,一直没搞清楚为啥, 今天刚好有时间,好好研究一下. 1 先按浏览器F12,导出按钮对应的html: <button type"button" class"btn btn-secondary fa fa-dow…

理解持续测试,才算理解DevOps

软件产品的成功与否&#xff0c;在很大程度上取决于对市场需求的及时把控&#xff0c;采用DevOps可以加快产品交付速度&#xff0c;改善用户体验&#xff0c;从而有助于保持领先于竞争对手的优势。 作为敏捷开发方法论的一种扩展&#xff0c;DevOps强调开发、测试和运维不同团队…

使用BP插件captcha-killer识别图片验证码绕过系统验证码机制

使用BP插件captcha-killer绕过验证码 前置条件 1、下载安装插件 burp2020前使用&#xff1a;https://github.com/c0ny1/captcha-killer/tree/0.1.2 burp2020后使用&#xff1a;https://github.com/Ta0ing/captcha-killer-java8 2、导入插件 分为三个部分&#xff1a;上面为验…

【Sklearn】基于朴素贝叶斯算法的数据分类预测(Excel可直接替换数据)

【Sklearn】基于朴素贝叶斯算法的数据分类预测&#xff08;Excel可直接替换数据&#xff09; 1.模型原理2.模型参数3.文件结构4.Excel数据5.下载地址6.完整代码7.运行结果 1.模型原理 模型原理&#xff1a; 朴素贝叶斯分类是基于贝叶斯定理的一种分类方法。它假设特征之间相互…

【一定要会】为ChatGPT插上翅膀的5个常用插件!

自从ChatGPT接入插件功能后&#xff0c;便不再受限于预训练数据中的知识&#xff0c;第三方开发者也可以基于ChatGPT增强自家应用程序的功能。自此 ChatGPT更像是一个开放的平台甚至是生态了。 截止的今年的7月20日&#xff0c;ChatGPT已经接入了700多个插件&#xff08;当然&…

智能驾驶系列报告之一:智能驾驶 ChatGPT时刻有望来临

原创 | 文 BFT机器人 L3 功能加速落地&#xff0c;政策标准有望明确 L2 发展日益成熟&#xff0c;L3 功能加速落地。根据市场监管总局发布的《汽车驾驶自动化分级》与 SAE发布的自动驾驶分级标准&#xff0c;自动驾驶主要分为 6 个级别&#xff08;0 级到 5 级&#xff0c;L0 …

五、linux系统下创建新目录的mkdir命令

mkdir命令 在Linux系统中&#xff0c;如果想要创建一个新目录&#xff0c;即文件夹&#xff0c;可以使用mkdir命令&#xff1a; 1、语法&#xff1a;mkdir [-p](可以不存在) Linux路径(必须存在) 2、基础操作&#xff1a;mkdir 目录名 &#xff08;1&#xff09;方法一&…

pytest数据驱动(最简单)

目录 第一种&#xff1a;通过yaml文件获取数据&#xff08;一维列表&#xff09; 第二种&#xff1a;通过yaml文件获取数据&#xff08;二维列表&#xff09; 第三种&#xff1a;通过yaml文件获取数据&#xff08;pytest.fixture&#xff09; 资料获取方法 第一种&#xff…

【Vue-Router】别名

后台返回来的路径名不合理&#xff0c;但多个项目在使用中了&#xff0c;不方便改时可以使用别名。可以有多个或一个。 First.vue <template><h1>First Seciton</h1> </template>Second.vue&#xff0c;Third.vue代码同理 UserSettings.vue <tem…

【需求输出】流程图输出

文章目录 1、什么是流程图2、绘制流程图的工具和基本要素3、流程图的分类和应用场景4、如何根据具体场景输出流程图 1、什么是流程图 2、绘制流程图的工具和基本要素 3、流程图的分类和应用场景 4、如何根据具体场景输出流程图

ARTS 挑战打卡的第9天 --- 如何知道一个数是否为2的若干次幂(Algorithm)

前言 &#xff08;1&#xff09;今天看到一个有意思的问题&#xff0c;如何判断一个数字是否为2的若干次幂。这个问题并不难&#xff0c;但是对于我们的C语言功底还是有一点点的考验的。 &#xff08;2&#xff09;希望各位可以先自行思考&#xff0c;实在想不出来再看后面的讲…

WPF 本地化的最佳做法

WPF 本地化的最佳做法 资源文件英文资源文件 en-US.xaml中文资源文件 zh-CN.xaml 资源使用App.xaml主界面布局cs代码 App.config辅助类语言切换操作类资源 binding 解析类 实现效果 应用程序本地化有很多种方式&#xff0c;选择合适的才是最好的。这里只讨论一种方式&#xff0…

Sencha Ext.NET Crack,构建Blazing快速应用

Sencha Ext.NET Crack,构建Blazing快速应用 Sencha Ext.NET是一个高级的ASP.NET核心组件框架&#xff0c;它包含了强大的跨浏览器Sencha Ext JS库。通过140多个预构建和专业测试的UI组件实现企业级性能和生产效率。Sencha Ext.NET使用尖端的Web技术创建功能强大的Web应用程序&a…

【Spring专题】Bean的生命周期流程图

目录 前言阅读指引 流程图一、之前推测的简单流程图&#xff08;一点点参考&#xff09;*二、Bean生命周期流程图&#xff08;根据Spring源码自结&#xff09;*三、阶段源码流程图&#xff08;不断更新&#xff09; 前言 我向来不主张【通过源码】理解业务&#xff0c;因为每个…