多线程糗事百科案例

Queue(队列对象)

Queue是python中的标准库,可以直接import Queue引用;队列是线程间最常用的交换数据的形式

python下多线程的思考

对于资源,加锁是个重要的环节。因为python原生的list,dict等,都是not thread safe的。而Queue,是线程安全的,因此在满足使用条件下,建议使用队列

  1. 初始化: class Queue.Queue(maxsize) FIFO 先进先出
  2. 包中的常用方法:
    • Queue.qsize() 返回队列的大小
    • Queue.empty() 如果队列为空,返回True,反之False
    • Queue.full() 如果队列满了,返回True,反之False
    • Queue.full 与 maxsize 大小对应
    • Queue.get([block[, timeout]])获取队列,timeout等待时间
  3. 创建一个“队列”对象
    • import Queue
    • myqueue = Queue.Queue(maxsize = 10)
  4. 将一个值放入队列中
    • myqueue.put(10)
  5. 将一个值从队列中取出
    • myqueue.get()
  1 # -*- coding:utf-8 -*-
  2
  3 # 使用了线程库
  4 import threading
  5 # 队列
  6 from Queue import Queue
  7 # 解析库
  8 from lxml import etree
  9 # 请求处理
 10 import requests
 11 # json处理
 12 import json
 13 import time
 14
 15 class ThreadCrawl(threading.Thread):
 16     def __init__(self, threadName, pageQueue, dataQueue):
 17         #threading.Thread.__init__(self)
 18         # 调用父类初始化方法
 19         super(ThreadCrawl, self).__init__()
 20         # 线程名
 21         self.threadName = threadName
 22         # 页码队列
 23         self.pageQueue = pageQueue
 24         # 数据队列
 25         self.dataQueue = dataQueue
 26         # 请求报头
 27         self.headers = {"User-Agent" : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"}
 28
 29     def run(self):
 30         print "启动 " + self.threadName
 31         while not CRAWL_EXIT:
 32             try:
 33                 # 取出一个数字,先进先出
 34                 # 可选参数block,默认值为True
 35                 #1. 如果对列为空,block为True的话,不会结束,会进入阻塞状态,直到队列有新的数据
 36                 #2. 如果队列为空,block为False的话,就弹出一个Queue.empty()异常,
 37                 page = self.pageQueue.get(False)
 38                 url = "http://www.qiushibaike.com/8hr/page/" + str(page) +"/"
 39                 #print url
 40                 content = requests.get(url, headers = self.headers).text
 41                 time.sleep(1)
 42                 self.dataQueue.put(content)
 43                 #print len(content)
 44             except:
 45                 pass
 46         print "结束 " + self.threadName
 47
 48 class ThreadParse(threading.Thread):
 49     def __init__(self, threadName, dataQueue, filename, lock):
 50         super(ThreadParse, self).__init__()
 51         # 线程名
 52         self.threadName = threadName
 53         # 数据队列
 54         self.dataQueue = dataQueue
 55         # 保存解析后数据的文件名
 56         self.filename = filename
 57         # 锁
 58         self.lock = lock
 59
 60     def run(self):
 61         print "启动" + self.threadName
 62         while not PARSE_EXIT:
 63             try:
 64                 html = self.dataQueue.get(False)
 65                 self.parse(html)
 66             except:
 67                 pass
 68         print "退出" + self.threadName
 69
 70     def parse(self, html):
 71         # 解析为HTML DOM
 72         html = etree.HTML(html)
 73
 74         node_list = html.xpath(‘//div[contains(@id, "qiushi_tag")]‘)
 75
 76         for node in node_list:
 77             # xpath返回的列表,这个列表就这一个参数,用索引方式取出来,用户名
 78             username = node.xpath(‘.//img/@alt‘)[0]
 79             # 图片连接
 80             image = node.xpath(‘.//div[@class="thumb"]//@src‘)#[0]
 81             # 取出标签下的内容,段子内容
 82             content = node.xpath(‘.//div[@class="content"]/span‘)[0].text
 83             # 取出标签里包含的内容,点赞
 84             zan = node.xpath(‘.//i‘)[0].text
 85             # 评论
 86             comments = node.xpath(‘.//i‘)[1].text
 87
 88             items = {
 89                 "username" : username,
 90                 "image" : image,
 91                 "content" : content,
 92                 "zan" : zan,
 93                 "comments" : comments
 94             }
 95
 96             # with 后面有两个必须执行的操作:__enter__ 和 _exit__
 97             # 不管里面的操作结果如何,都会执行打开、关闭
 98             # 打开锁、处理内容、释放锁
 99             with self.lock:
100                 # 写入存储的解析后的数据
101                 self.filename.write(json.dumps(items, ensure_ascii = False).encode("utf-8") + "\n")
102
103 CRAWL_EXIT = False
104 PARSE_EXIT = False
105
106
107 def main():
108     # 页码的队列,表示20个页面
109     pageQueue = Queue(20)
110     # 放入1~10的数字,先进先出
111     for i in range(1, 21):
112         pageQueue.put(i)
113
114     # 采集结果(每页的HTML源码)的数据队列,参数为空表示不限制
115     dataQueue = Queue()
116
117     filename = open("duanzi.json", "a")
118     # 创建锁
119     lock = threading.Lock()
120
121     # 三个采集线程的名字
122     crawlList = ["采集线程1号", "采集线程2号", "采集线程3号"]
123     # 存储三个采集线程的列表集合
124     threadcrawl = []
125     for threadName in crawlList:
126         thread = ThreadCrawl(threadName, pageQueue, dataQueue)
127         thread.start()
128         threadcrawl.append(thread)
129
130
131     # 三个解析线程的名字
132     parseList = ["解析线程1号","解析线程2号","解析线程3号"]
133     # 存储三个解析线程
134     threadparse = []
135     for threadName in parseList:
136         thread = ThreadParse(threadName, dataQueue, filename, lock)
137         thread.start()
138         threadparse.append(thread)
139
140     # 等待pageQueue队列为空,也就是等待之前的操作执行完毕
141     while not pageQueue.empty():
142         pass
143
144     # 如果pageQueue为空,采集线程退出循环
145     global CRAWL_EXIT
146     CRAWL_EXIT = True
147
148     print "pageQueue为空"
149
150     for thread in threadcrawl:
151         thread.join()
152         print "1"
153
154     while not dataQueue.empty():
155         pass
156
157     global PARSE_EXIT
158     PARSE_EXIT = True
159
160     for thread in threadparse:
161         thread.join()
162         print "2"
163
164     with lock:
165         # 关闭文件
166         filename.close()
167     print "谢谢使用!"
168
169 if __name__ == "__main__":
170     main()

原文地址:https://www.cnblogs.com/wanglinjie/p/9196851.html

时间: 2024-10-09 06:44:32

多线程糗事百科案例的相关文章

Python爬虫(十八)_多线程糗事百科案例

多线程糗事百科案例 案例要求参考上一个糗事百科单进程案例:http://www.cnblogs.com/miqi1992/p/8081929.html Queue(队列对象) Queue是python中的标准库,可以直接import Queue引用:队列时线程间最常用的交互数据的形式. python下多线程的思考 对于资源,加锁是个重要的环节.因为python原生的list,dict等,都是not thread safe的.而Queue,是线程安全的,因此在满足使用条件下,建议使用队列 初始化:

python 多线程糗事百科案例

案例要求参考上一个糗事百科单进程案例 Queue(队列对象) Queue是python中的标准库,可以直接import Queue引用;队列是线程间最常用的交换数据的形式 python下多线程的思考 对于资源,加锁是个重要的环节.因为python原生的list,dict等,都是not thread safe的.而Queue,是线程安全的,因此在满足使用条件下,建议使用队列 初始化: class Queue.Queue(maxsize) FIFO 先进先出 包中的常用方法: Queue.qsize

Python爬虫(十七)_糗事百科案例

糗事百科实例 爬取糗事百科段子,假设页面的URL是: http://www.qiushibaike.com/8hr/page/1 要求: 使用requests获取页面信息,用XPath/re做数据提取 获取每个帖子里的用户头像连接.用户姓名.段子内容.点赞次数和评论次数 保存到json文件内 参考代码 #-*- coding:utf-8 -*- import requests from lxml import etree page = 1 url = 'http://www.qiushibaik

多线程爬取糗事百科热门段子 (改写前天的博客)

利用多线程爬取,除了先前用到的几个模块之外,还需用到threading模块和queue模块: 为每一件事情开启一个线程:构造url_list.发送请求.提取数据.保存数据 __init__方法添加三个实例属性队列分别存放:url.响应内容.处理后的数据 改写原先每一个方法里的代码,需要的东西直接从队列中取出,此时方法都无需多余参数了 每当从一个队列取出数据,记得执行task_done()方法,使计数减一 run()方法里把yaozhixing的事情都开启一个线程,比较慢的事情,比如网络请求,可以

糗事百科爬虫案例

爬取糗事百科的热门的所有段子的作者.标题.内容链接.好笑数.评论数 # coding=utf-8 from lxml import etree import requests import json class QiubaiSpider: def __init__(self): self.url_temp="https://www.qiushibaike.com/8hr/page/{}/" self.header={"User-Agent": "Mozil

【python】抄写大神的糗事百科代码

照着静觅大神的博客学习,原文在这:http://cuiqingcai.com/990.html 划重点: 1. str.strip() strip函数会把字符串的前后多余的空白字符去掉 2. response.read().decode('utf-8','ignore')  要加'ignore'忽略非法字符,不然总是报解码错误 3. python 3.x 中  raw_input 改成 input 了 4. 代码最好用notepad++先写 格式清晰一点 容易发现错 尤其是缩进和中文标点的错误

PHP爬取糗事百科首页糗事

突然想获取一些网上的数据来玩玩,因为有SAE的MySql数据库,让它在那呆着没有什么卵用!于是就开始用PHP编写一个爬取糗事百科首页糗事的小程序,数据都保存在MySql中,岂不是很好玩! 说干就干!首先确定思路 获取HTML源码--->解析HTML--->保存到数据库 没有什么难的 1.创建PHP文件"getDataToDB.php", 2.获取指定URL的HTML源码 这里我用的是curl函数,详细内容参见PHP手册 代码为 <span style="fo

糗事百科python爬虫

# -*- coding: utf-8 -*- #coding=utf-8 import urllib import urllib2 import re import thread import time class QSBK: def __init__(self): self.pageIndex=1 self.user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' self.header={'User-Agent':self.

python 糗事百科实例

爬取糗事百科段子,假设页面的URL是 http://www.qiushibaike.com/8hr/page/1 要求: 使用requests获取页面信息,用XPath / re 做数据提取 获取每个帖子里的用户头像链接.用户姓名.段子内容.点赞次数和评论次数 保存到 json 文件内 参考代码 #qiushibaike.py #import urllib #import re #import chardet import requests from lxml import etree page