'''
一个线程在使用这个共享的时候,其他线程必须等待他结束
通过"锁"实现,作用就是防止多个线程使用这片内存空间
进程:程序的一次执行
线程:cpu运算的基本调度单位
多线程:大量密集I/O处理,在等待响应的时候,其他线程去工作
多进程:大量的密集并行计算
scrapy:异步网络框架(很多协程在处理)
页码队列--线程取页码爬取(采集线程--网络IO)--数据队列(得到的响应)--线程解析网页(解析线程磁盘IO)--解析后的数据存储
'''
# 请求
import requests
# 队列
from multiprocessing import Queue
# 线程
from threading import Thread
import threading
# 解析
from lxml import etree
# 存储
import json
import time class ThreadCrawl(Thread):
def __init__(self, threadName, pageQueue, dataQueue):
# 调用父类的初始化方法
super(ThreadCrawl, self).__init__()
self.threadName = threadName
self.pageQueue = pageQueue
self.dataQueue = dataQueue
self.headers = {"User-Agent":"Mozilla/5.0(Windows NT 10.0;WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36"} # thread.start()会执行run方法
def run(self):
print("启动"+self.threadName)
while not CRAWL_EXIT:
try:
# 从页码队列取出一个数字,
# 可选参数block(默认Ture)
# 1.队列为空,block为Ture,会进入阻塞状态,直到有新的值进入队列
# 2.如果队列为空.block为False,会弹出Queue.empty()出错
page = self.pageQueue.get(False)
url = "https://www.qiushibaike.com/text/page/" + str(page) + "/"
content = requests.get(url,headers=self.headers).text
#调用数据队列,将源码放进去
self.dataQueue.put(content)
except:
pass
print("结束"+self.threadName) class ThreadParse(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):
while not PARSE_EXIT:
try:
html = self.dataQueue.get(False)
self.parse(html)
except:
pass def parse(self,html):
html = etree.HTML(html)
print(html) # with 后面有两个必须执行的操作:__enter__ 和 _exit__
# 不管里面的操作结果如何,都会执行打开、关闭
# 打开锁、处理内容、释放锁
with self.lock:
# 写入存储的解析后的数据
self.filename.write(json.dumps(html, 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() # 创建锁
lock = threading.Lock() # 采集线程名字
crawlList = ["采集线程1号", "采集线程2号", "采集线程3号"] # 存储采集线程
thread_crawl = []
for threadName in crawlList:
# 写一个
thread = ThreadCrawl(threadName, pageQueue, dataQueue)
thread.start()
thread_crawl.append(thread) filename = open("duanzi.json","a")
#解析线程名字
parseList = ["解析线程1号","解析线程2号","解析线程3号"]
threadparse = []
for threadName in parseList:
thread = ThreadParse(threadName,dataQueue,filename,lock)
thread.start()
threadparse.append(thread) #如果队列不为空,一直在这等待
while not pageQueue.empty():
pass
#如果队列为空,CRAWL_EXIT = True 退出
global CRAWL_EXIT
CRAWL_EXIT = True #加阻塞,线程做完才能运行主线程
for thread in thread_crawl:
thread.join()
print(thread) while not dataQueue.empty():
pass global PARSE_EXIT
PARSE_EXIT = True for thread in threadparse:
thread.join()
print(thread) with lock:
# 关闭文件
filename.close()
print("谢谢使用") if __name__ == '__main__':
main()

  

<随便写> 多线程的例子的更多相关文章

  1. python两段多线程的例子

    记录瞬间 =====================其一===================== # coding:UTF-8 import os import threading from tim ...

  2. C#多线程简单例子讲解

    C#多线程简单例子讲解 标签: 多线程c#threadobjectcallbacktimer 分类: C#(7) 转载网址:http://www.knowsky.com/540518.html .NE ...

  3. Peer模式的多线程程序例子

    Peer模式的多线程程序例子 程序的模型大概是这样的.有一个master(),用来分发任务.有N个多线程的slave用来处理任务. 主程序里可以这样调用: 可以看出,上面这段程序还是依赖于Proces ...

  4. Jquery 随便写些知识点

    针对jQuery随便写些觉得还挺实用的一些东西,也没系统的去理一番,只是想到哪写到哪,写的不完全也请多见谅. jQuery和其他javascript库产生$符号冲突了?$符号想必用jQuery的人都不 ...

  5. 用thinkphp写的一个例子:抓取网站的内容并且保存到本地

    我需要写这么一个例子,到电子课本网下载一本电子书. 电子课本网的电子书,是把书的每一页当成一个图片,然后一本书就是有很多张图片,我需要批量的进行下载图片操作. 下面是代码部分: public func ...

  6. 【转】忙里偷闲写的小例子---读取android根目录下的文件或文件夹

    原文网址:http://www.cnblogs.com/wenjiang/p/3140055.html 最近几天真的是各种意义上的忙,忙着考试,还要忙着课程设计,手上又有外包的项目,另一边学校的项目还 ...

  7. python多线程简单例子

    python多线程简单例子 作者:vpoet mail:vpoet_sir@163.com import thread def childthread(threadid): print "I ...

  8. 忙里偷闲写的小例子---读取android根目录下的文件或文件夹

    最近几天真的是各种意义上的忙,忙着考试,还要忙着课程设计,手上又有外包的项目,另一边学校的项目还要搞,自己的东西还在文档阶段,真的是让人想死啊!! 近半个月来,C#这方面的编码比较多,android和 ...

  9. 再议perl写多线程端口扫描器

    再议perl写多线程端口扫描器 http://blog.csdn.net/sx1989827/article/details/4642179 perl写端口多线程扫描器 http://blog.csd ...

随机推荐

  1. redis集群报错:(error) MOVED 5798 127.0.0.1:7001

    原因 这种情况一般是因为启动redis-cli时没有设置集群模式所导致. 解决方案 启动时使用-c参数来启动集群模式,命令如下: redis-cli -c -p 7000 测试 127.0.0.1:7 ...

  2. C/C++ 表达式

    == ; std::cout << b<< std::endl; EX

  3. bzoj1002题解

    [题意分析] 给你一张特殊的,被称为“轮状基”的无向图,求其生成树个数. [解题思路] 引理: 基尔霍夫矩阵: 基尔霍夫矩阵=度数矩阵-邻接矩阵(邻接矩阵权=两点连边数) Matrix-Tree定理: ...

  4. NX二次开发-UFUN按类型遍历名字获取Tag函数UF_OBJ_cycle_by_name_and_type

    NX9+VS2012 #include <uf.h> #include <uf_draw.h> #include <uf_obj.h> #include <u ...

  5. 谈谈E语言

    基于中国文化底蕴的编程语言,  绝对不是E语言那个样子. 基于中文的编程,必将是计算机届的一次原子爆炸!

  6. due to a StackOverflowError. Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies. The class hierarchy being processed was [org.jaxen.util.AncestorAxisIt

    七月 31, 2019 4:39:01 下午 org.apache.catalina.startup.VersionLoggerListener log信息: Server version: Apac ...

  7. 2019 牛客多校第一场 E ABBA

    题目链接:https://ac.nowcoder.com/acm/contest/881/E 题目大意 问有多少个由 (n + m) 个 ‘A’ 和 (n + m) 个 ‘B’,组成的字符串能被分割成 ...

  8. 如何在Spring Boot 中动态设定与执行定时任务

    本篇文章的目的是记录并实现在Spring Boot中,动态设定与执行定时任务. 我的开发项目是 Maven 项目,所以首先需要在 pom.xml 文件中加入相关的依赖.依赖代码如下所示: <de ...

  9. MyBatis中使用RowBounds对查询结果集进行分页

    MyBatis可以使用RowBounds逐页加载表数据.RowBounds对象可以使用offset和limit参数来构建.参数offset表示开始位置,而limit表示要取的记录的数目 映射文件: & ...

  10. ThreadPoolTaskExecutor的配置使用

    版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/ft305977550/article/de ...