python爬虫入门(四)利用多线程爬虫
多线程爬虫
先回顾前面学过的一些知识
1.一个cpu一次只能执行一个任务,多个cpu同时可以执行多个任务
2.一个cpu一次只能执行一个进程,其它进程处于非运行状态
3.进程里包含的执行单元叫线程,一个进程可以包含多个线程
4.一个进程的内存空间是共享的,每个进程里的线程都可以使用这个共享空间
5.一个线程在使用这个共享空间的时候,其它的线程必须等待(阻塞状态)
6.互斥锁作用就是防止多个线程同时使用这块内存空间,先使用的线程会将空间上锁,其它的线程处于等待状态。等锁开了才能进
7.进程:表示程序的一次执行
8.线程:CPU运算的基本调度单位
9.GIL(全局锁):python里的执行通行证,而且只有一个。拿到通行证的线程就可以进入CPU执行任务。没有GIL的线程就不能执行任务
10.python的多线程适用于大量密集的I/O处理
11.python的多进程适用于大量的密集并行计算
多线程爬取糗事百科
#!/usr/bin/env python
# -*- coding:utf-8 -*- # 使用了线程库
import threading
# 队列
from Queue import Queue
# 解析库
from lxml import etree
# 请求处理
import requests
# json处理
import json
import time class ThreadCrawl(threading.Thread):
def __init__(self, threadName, pageQueue, dataQueue):
#threading.Thread.__init__(self)
# 调用父类初始化方法
super(ThreadCrawl, self).__init__()
# 线程名
self.threadName = threadName
# 页码队列
self.pageQueue = pageQueue
# 数据队列
self.dataQueue = dataQueue
# 请求报头
self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'} def run(self):
print "启动 " + self.threadName
while not CRAWL_EXIT:
try:
# 取出一个数字,先进先出
# 可选参数block,默认值为True
#1. 如果对列为空,block为True的话,不会结束,会进入阻塞状态,直到队列有新的数据
#2. 如果队列为空,block为False的话,就弹出一个Queue.empty()异常,
page = self.pageQueue.get(False)
url = "http://www.qiushibaike.com/8hr/page/" + str(page) +"/"
#print url
content = requests.get(url, headers = self.headers).text
time.sleep(1)
self.dataQueue.put(content)
#print len(content)
except:
pass
print "结束 " + self.threadName class ThreadParse(threading.Thread):
def __init__(self, threadName, dataQueue, filename, lock):
super(ThreadParse, self).__init__()
# 线程名
self.threadName = threadName
# 数据队列
self.dataQueue = dataQueue
# 保存解析后数据的文件名
self.filename = filename
# 锁
self.lock = lock def run(self):
print "启动" + self.threadName
while not PARSE_EXIT:
try:
html = self.dataQueue.get(False)
self.parse(html)
except:
pass
print "退出" + self.threadName def parse(self, html):
# 解析为HTML DOM
html = etree.HTML(html) node_list = html.xpath('//div[contains(@id, "qiushi_tag")]') for node in node_list:
# xpath返回的列表,这个列表就这一个参数,用索引方式取出来,用户名
username = node.xpath('./div/a/@title')[0]
# 图片连接
image = node.xpath('.//div[@class="thumb"]//@src')#[0]
# 取出标签下的内容,段子内容
content = node.xpath('.//div[@class="content"]/span')[0].text
# 取出标签里包含的内容,点赞
zan = node.xpath('.//i')[0].text
# 评论
comments = node.xpath('.//i')[1].text items = {
"username" : username,
"image" : image,
"content" : content,
"zan" : zan,
"comments" : comments
} # with 后面有两个必须执行的操作:__enter__ 和 _exit__
# 不管里面的操作结果如何,都会执行打开、关闭
# 打开锁、处理内容、释放锁
with self.lock:
# 写入存储的解析后的数据
self.filename.write(json.dumps(items, ensure_ascii = False).encode("utf-8") + "\n") CRAWL_EXIT = False
PARSE_EXIT = False def main():
# 页码的队列,表示20个页面
pageQueue = Queue(20)
# 放入1~10的数字,先进先出
for i in range(1, 21):
pageQueue.put(i) # 采集结果(每页的HTML源码)的数据队列,参数为空表示不限制
dataQueue = Queue() filename = open("duanzi.json", "a")
# 创建锁
lock = threading.Lock() # 三个采集线程的名字
crawlList = ["采集线程1号", "采集线程2号", "采集线程3号"]
# 存储三个采集线程的列表集合
threadcrawl = []
for threadName in crawlList:
thread = ThreadCrawl(threadName, pageQueue, dataQueue)
thread.start()
threadcrawl.append(thread) # 三个解析线程的名字
parseList = ["解析线程1号","解析线程2号","解析线程3号"]
# 存储三个解析线程
threadparse = []
for threadName in parseList:
thread = ThreadParse(threadName, dataQueue, filename, lock)
thread.start()
threadparse.append(thread) # 等待pageQueue队列为空,也就是等待之前的操作执行完毕
while not pageQueue.empty():
pass # 如果pageQueue为空,采集线程退出循环
global CRAWL_EXIT
CRAWL_EXIT = True print "pageQueue为空" for thread in threadcrawl:
thread.join()
print "" while not dataQueue.empty():
pass global PARSE_EXIT
PARSE_EXIT = True for thread in threadparse:
thread.join()
print "" with lock:
# 关闭文件
filename.close()
print "谢谢使用!" if __name__ == "__main__":
main()
python爬虫入门(四)利用多线程爬虫的更多相关文章
- Python爬虫入门四之Urllib库的高级用法
1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性. 首先,打开我们的浏览 ...
- 转 Python爬虫入门四之Urllib库的高级用法
静觅 » Python爬虫入门四之Urllib库的高级用法 1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我 ...
- 爬虫入门四 re
title: 爬虫入门四 re date: 2020-03-14 16:49:00 categories: python tags: crawler 正则表达式与re库 1 正则表达式简介 编译原理学 ...
- 【爬虫入门手记03】爬虫解析利器beautifulSoup模块的基本应用
[爬虫入门手记03]爬虫解析利器beautifulSoup模块的基本应用 1.引言 网络爬虫最终的目的就是过滤选取网络信息,因此最重要的就是解析器了,其性能的优劣直接决定这网络爬虫的速度和效率.Bea ...
- RobotFramework + Python 自动化入门 四 (Web进阶)
在<RobotFramwork + Python 自动化入门 一>中,完成了一个Robot环境搭建及测试脚本的创建和执行. 在<RobotFramwork + Python 自动化入 ...
- python爬虫入门四:BeautifulSoup库(转)
正则表达式可以从html代码中提取我们想要的数据信息,它比较繁琐复杂,编写的时候效率不高,但我们又最好是能够学会使用正则表达式. 我在网络上发现了一篇关于写得很好的教程,如果需要使用正则表达式的话,参 ...
- 4.Python爬虫入门四之Urllib库的高级用法
1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性. 首先,打开我们的浏览 ...
- Python爬虫入门教程 50-100 Python3爬虫爬取VIP视频-Python爬虫6操作
爬虫背景 原计划继续写一下关于手机APP的爬虫,结果发现夜神模拟器总是卡死,比较懒,不想找原因了,哈哈,所以接着写后面的博客了,从50篇开始要写几篇python爬虫的骚操作,也就是用Python3通过 ...
- Python爬虫入门教程 53-100 Python3爬虫获取三亚天气做旅游参照
爬取背景 这套课程虽然叫爬虫入门类课程,但是里面涉及到的点是非常多,十分检验你的基础掌握的牢固程度,代码中的很多地方都是可以细细品味的. 为什么要写这么一个小东东呢,因为我生活在大河北,那雾霾醇厚的很 ...
随机推荐
- 【uWSGI】 实战之操作经验
以下是uWSGI版本为2.0以上,uwsgi的启动可以把参数加载命令行中,也可以是配置文件 .ini, .xml, .yaml 配置文件中,个人用的比较多得是 .ini 文件.下面总结下自己操作和使用 ...
- maven中去掉单元测试的配置
如果是在命令行中去掉测试,可以在命令行中输入:mvn install -Dmaven.test.skip=true 在pom.xml <plugins> <plugin& ...
- Leetcode_70_Climbing Stairs
本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/41851705 You are climbing a sta ...
- Css技术入门笔记01
在学习html的时候,html中的标签都具备了特定功能,或者含义,以及相应的样式效果.可是在有些时候我们可能仅仅希望使用 html标签把要显示的数据封装起来,而不需要任何的样式效果.这时就需要单独的标 ...
- [查阅]MSIL Instruction Set
Base Instructions Instruction Description Stack Transition 1 add add two values, returning a new v ...
- 《java入门第一季》之面向对象this关键字
/* 起名字要做到见名知意. this:是当前类的对象引用.简单的记,它就代表当前类的一个对象. 注意:谁调用这个方法,在该方法内部的this就代表谁. this的场景: 解决局部变量隐藏成员变量 * ...
- J2EE进阶(一)随堂笔记
进公司搞研发,基本上用的都是J2EE框架.若想在公司混个不错的地位,首先技术上必须过关.由于需求所致,自己学习了J2EE一段时间,主要是Struts2,MyBatis(Hibernate的前身),远远 ...
- Android Activity的四种经典传值方法
文/ http://blog.csdn.net/sk719887916/article/details/41723613 skay 开发中遇到多个activity的传值问题 相邻两个之间的传值 或者 ...
- 实战项目开发细节:C语言分离一个16进制数取出相应的位1或0
最近在公司开发一个关于钢琴的PCBA项目,项目大概是这样的,完成各种功能的测试,准备去工厂量产的时候可以通过软件快速甄别硬件是否短路,断路等问题. 其中,甄别好坏的方法是通过比如按键,或者其它的操作然 ...
- InvocationTargetException异常解析
InvocationTargetException异常由Method.invoke(obj, args...)方法抛出.) { throw new ZeroException("参数不能小于 ...