题记:作为测试工程师经常需要解决测试数据来源的问题,解决思路无非是三种:(1)直接从生产环境拷贝真实数据 (2)从互联网上爬取数据 (3)自己用脚本或者工具造数据。前段时间,为了获取更多的测试数据,笔者就做了一个从互联网上爬取数据的爬虫程序,虽然功能上基本满足项目的需求,但是爬取的效率还是不太高。作为一个精益求精的测试工程师,决定研究一下多线程在爬虫领域的应用,以提高爬虫的效率。

一、为什么需要多线程

凡事知其然也要知其所以然。在了解多线程的相关知识之前,我们先来看看为什么需要多线程。打个比方吧,你要搬家了,单线程就类似于请了一个搬家工人,他一个人负责打包、搬运、开车、卸货等一系列操作流程,这个工作效率可想而知是很慢的;而多线程就相当于请了四个搬家工人,甲打包完交给已搬运到车上,然后丙开车送往目的地,最后由丁来卸货。

由此可见多线程的好处就是高效、可以充分利用资源,坏处就是各个线程之间要相互协调,否则容易乱套(类似于一个和尚挑水喝、两个和尚抬水喝、三个和尚没水喝的窘境)。所以为了提高爬虫效率,我们在使用多线程时要格外注意多线程的管理问题。

二、多线程的基本知识

进程:由程序,数据集,进程控制块三部分组成,它是程序在数据集上的一次运行过程。如果同一段程序在某个数据集上运行了两次,那就是开启了两个进程。进程是资源管理的基本单位。在操作系统中,每个进程有一个地址空间,而且默认就有一个控制进程。

线程:是进程的一个实体,是CPU调度和分派的基本单位,也是最小的执行单位。它的出现降低了上下文切换的消耗,提高了系统的并发性,并克服了一个进程只能干一件事的缺陷。线程由进程来管理,多个线程共享父进程的资源空间。

进程和线程的关系:

一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

资源分配给进程,同一进程的所有线程共享该进程的所有资源。

CPU分给线程,即真正在CPU上运行的是线程。

线程的工作方式:

如下图所示,串行指线程一个个地在CPU上执行;并行是在多个CPU上运行多个线程;而并发是一种“伪并行”,一个CPU同一时刻只能执行一个任务,把CPU的时间分片,一个线程只占用一个很短的时间片,然后各个线程轮流,由于时间片很短所以在用户看来所有线程都是“同时”的。并发也是大多数单CPU多线程的实际运行方式。

进程的工作状态:

一个进程有三种状态:运行、阻塞、就绪。三种状态之间的转换关系如下图所示:运行态的进程可能由于等待输入而主动进入阻塞状态,也可能由于调度程序选择其他进程而被动进入就绪状态(一般是分给它的CPU时间到了);阻塞状态的进程由于等到了有效的输入而进入就绪状态;就绪状态的进程因为调度程序再次选择了它而再次进入运行状态。

三、多线程通信实例

还是回到爬虫的问题上来,我们知道爬取博客文章的时候都是先爬取列表页,然后根据列表页的爬取结果再来爬取文章详情内容。而且列表页的爬取速度肯定要比详情页的爬取速度快。

这样的话,我们可以设计线程A负责爬取文章列表页,线程B、线程C、线程D负责爬取文章详情。A将列表URL结果放到一个类似全局变量的结构里,线程B、C、D从这个结构里取结果。

在PYTHON中,有两个支持多线程的模块:threading模块--负责线程的创建、开启等操作;queque模块--负责维护那个类似于全局变量的结构。这里还要补充一点:也许有同学会问直接用一个全局变量不就可以了么?干嘛非要用queue?因为全局变量并不是线程安全的,比如说全局变量里(列表类型)只有一个url了,线程B判断了一下全局变量非空,在还没有取出该url之前,cpu把时间片给了线程C,线程C将最后一个url取走了,这时cpu时间片又轮到了B,B就会因为在一个空的列表里取数据而报错。而queue模块实现了多生产者、多消费者队列,在放值取值时是线程安全的。

废话不多说了,直接上代码给大伙看看:

import threading #导入threading模块

from queue import Queue #导入queue模块

import time #导入time模块

#爬取文章详情页

defget_detail_html(detail_url_list, id):whileTrue:

url= detail_url_list.get() #Queue队列的get方法用于从队列中提取元素

time.sleep(2) #延时2s,模拟网络请求和爬取文章详情的过程

print("thread {id}: get {url} detail finished".format(id=id,url=url)) #打印线程id和被爬取了文章内容的url

#爬取文章列表页

defget_detail_url(queue):for i in range(10000):

time.sleep(1) #延时1s,模拟比爬取文章详情要快

queue.put("http://testedu.com/{id}".format(id=i))#Queue队列的put方法用于向Queue队列中放置元素,由于Queue是先进先出队列,所以先被Put的URL也就会被先get出来。

print("get detail url {id} end".format(id=i))#打印出得到了哪些文章的url

#主函数

if __name__ == "__main__":

detail_url_queue= Queue(maxsize=1000) #用Queue构造一个大小为1000的线程安全的先进先出队列

#先创造四个线程

thread = threading.Thread(target=get_detail_url, args=(detail_url_queue,)) #A线程负责抓取列表url

html_thread=[]for i in range(3):

thread2= threading.Thread(target=get_detail_html, args=(detail_url_queue,i))

html_thread.append(thread2)#B C D 线程抓取文章详情

start_time =time.time()#启动四个线程

thread.start()for i in range(3):

html_thread[i].start()#等待所有线程结束,thread.join()函数代表子线程完成之前,其父进程一直处于阻塞状态。

thread.join()for i in range(3):

html_thread[i].join()print("last time: {} s".format(time.time()-start_time))#等ABCD四个线程都结束后,在主进程中计算总爬取时间。

运行结果:

后记:从运行结果可以看出各个线程之间井然有序地工作着,没有出现任何报错和告警的情况。可见使用Queue队列实现多线程间的通信比直接使用全局变量要安全很多。而且使用多线程比不使用多线程的话,爬取时间上也要少很多,在提高了爬虫效率的同时也兼顾了线程的安全,可以说在爬取测试数据的过程中是非常实用的一种方式。希望小伙伴们能够GET到哦!

转自:https://mp.weixin.qq.com/s/LsRNxAVJywKwEXxo8WuwLw

---------------------------------------------------------------------------------

关注微信公众号即可在手机上查阅,并可接收更多测试分享~

python多线程爬虫实例-Python多线程在爬虫中的应用相关推荐

  1. python多线程爬虫实例-Python爬虫开发【第1篇】【多线程爬虫及案例】

    糗事百科爬虫实例: 需求: 使用requests获取页面信息,用XPath / re 做数据提取 获取每个帖子里的用户头像链接.用户姓名.段子内容.点赞次数和评论次数 保存到 json 文件内 #qi ...

  2. python多线程爬虫实例-Python实现多线程爬虫

    编辑推荐: 本文主要介绍对Python多线程爬虫实战的整体的思路,希望对大家有帮助. 本文来知乎,由火龙果软件Alice编辑,推荐. 最近在写爬虫程序爬取亚马逊上的评论信息,因此也自学了很多爬虫相关的 ...

  3. python多线程爬虫实例-Python3多线程爬虫实例讲解代码

    多线程概述 多线程使得程序内部可以分出多个线程来做多件事情,充分利用CPU空闲时间,提升处理效率.python提供了两个模块来实现多线程thread 和threading ,thread 有一些缺点, ...

  4. python多线程爬虫实例-Python多线程爬虫简单示例

    python是支持多线程的,主要是通过thread和threading这两个模块来实现的.thread模块是比较底层的模块,threading模块是对thread做了一些包装的,可以更加方便的使用. ...

  5. python多线程爬虫实例-python支持多线程的爬虫实例

    python是支持多线程的, 主要是通过thread和threading这两个模块来实现的,本文主要给大家分享python实现多线程网页爬虫 一般来说,使用线程有两种模式, 一种是创建线程要执行的函数 ...

  6. python多线程爬虫实例-python多线程爬虫实例讲解

    Python作为一门强大的脚本语言,我们经常使用python来写爬虫程序,简单的爬虫会写,可是用python写多线程网页爬虫,应该如何写呢?一般来说,使用线程有两种模式,一种是创建线程要执行的函数,把 ...

  7. python爬虫实例之——多线程爬取小说

    之前写过一篇爬取小说的博客,但是单线程爬取速度太慢了,之前爬取一部小说花了700多秒,1秒两章的速度有点让人难以接受. 所以弄了个多线程的爬虫. 这次的思路和之前的不一样,之前是一章一章的爬,每爬一章 ...

  8. python爬虫实例网易云-Python3爬虫实例之网易云音乐爬虫

    本篇文章给大家带来的内容是Python3爬虫实例之网易云音乐爬虫.有一定的参考价值,有需要的朋友可以参考一下,希望对你们有所帮助. 此次的目标是爬取网易云音乐上指定歌曲所有评论并生成词云 具体步骤: ...

  9. python 爬虫实例-python爬虫实例,一小时上手爬取淘宝评论(附代码)

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 1 明确目的 通过访问天猫的网站,先搜索对应的商品,然后爬取它的评论数据. ...

最新文章

  1. android中完全退出当前应用程序的四种方法
  2. IS-IS 的 DIS (伪节点) 及 DIS 和 OSPF中DR 的区别
  3. html combobox select控件设置默认选项
  4. JSP简单练习-一个简单的计数器
  5. linux下php的安装路径,Linux下Apache、PHP、MySQL默认安装路径
  6. PHP获取表单值--同时获取下拉框的Value和Text值
  7. fedora 14 64位安装 flash player
  8. 微信公众号-接口配置信息url和tokken
  9. 3.Event Loop
  10. 鸿蒙系统翻车了,鸿蒙“翻车”? 网友发现鸿蒙系统居然是安卓9.0
  11. Chrome中播放时视频编码为.h264和音频编码为acc,采样率为48000,双通道的视频文件时音画不同步
  12. android qq隐藏功能,90﹪的人都不知道QQ这些隐藏的功能!
  13. 万万没想到,“红孩儿” 竟然做了程序员,还是 CTO!
  14. 帮我写一段描写时间过得很快,但是自己又很不想时间过得那么快的小作文
  15. Java基础小项目shopping
  16. Hadoop 命令操作大全
  17. 笔记本 原因代码: 0x500ff 关机类型: 关闭电源_图吧垃圾佬关于笔记本电池更换的几项建议...
  18. win2003 64位 企业版 (win 2003_r2_enterprise_x64.iso)下载地址
  19. 软件测试——单元测试/集成测试/系统测试/验收测试
  20. (winform)PDF文档或视频文件在线阅读或观看工具

热门文章

  1. 训练深度学习网络时候,出现Nan是什么原因,怎么才能避免?——我自己是因为data有nan的坏数据,clear下解决...
  2. nginx 负载均衡的4种方式
  3. Django xadmin 后台自定义action 动作
  4. html a标签锚点跳转的简单应用
  5. 会话管理之session技术
  6. Android开发技术周报 Issue#20
  7. PHP代码加密 -- php_strip_whitespace函数,去掉源代码所有注释和空格并显示在一行...
  8. 从一生的角度看程序员的学习和发展
  9. 哈希表的详细介绍 -转载
  10. tomcat的服务器配置详解