多线程糗事百科案例

案例要求参考上一个糗事百科单进程案例:http://www.cnblogs.com/miqi1992/p/8081929.html

Queue(队列对象)

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

python下多线程的思考

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

  1. 初始化:class Queue.Queue(maxsize)FIFO先进先出

  2. 包中的常用方法:

    • Queue.qszie()返回队列的大小
    • 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. import requests
  3. from lxml import etree
  4. from Queue import Queue
  5. import threading
  6. import time
  7. import json
  8. class Thread_crawl(threading.Thread):
  9. """
  10. 抓取线程类
  11. """
  12. def __init__(self, threadID, q):
  13. threading.Thread.__init__(self)
  14. self.threadID = threadID
  15. self.q = q
  16. def run(self):
  17. print("String: "+self.threadID)
  18. self.qiushi_spider()
  19. print("Exiting: "+self.threadID)
  20. def qiushi_spider(self):
  21. while True:
  22. if self.q.empty():
  23. break
  24. else:
  25. page = self.q.get()
  26. print('qiushi_spider=', self.threadID, 'page=', str(page))
  27. url = 'http://www.qiushibaike.com/8hr/page/' + str(page)+"/"
  28. headers = {
  29. 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
  30. 'Accept-Language':'zh-CN,zh;q=0.8'
  31. }
  32. #多次尝试失败结束,防止死循环
  33. timeout = 4
  34. while timeout > 0:
  35. timeout -= 1
  36. try:
  37. content = requests.get(url, headers = headers)
  38. data_queue.put(content.text)
  39. break
  40. except Exception, e:
  41. print "qiushi_spider", e
  42. if timeout < 0:
  43. print 'timeout', url
  44. class Thread_Parser(threading.Thread):
  45. """
  46. 页面解析类
  47. """
  48. def __init__(self, threadID, queue, lock, f):
  49. threading.Thread.__init__(self)
  50. self.threadID = threadID
  51. self.queue = queue
  52. self.lock = lock
  53. self.f = f
  54. def run(self):
  55. print("starting ", self.threadID)
  56. global total, exitFlag_Parser
  57. while not exitFlag_Parser:
  58. try:
  59. """
  60. 调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block, 默认为True
  61. 如果队列为空且block为True,get()就使调用线程暂停,直至有项目可用
  62. 如果队列为空且block为False,队列将引发Empty异常
  63. """
  64. item = self.queue.get(False)
  65. if not item:
  66. pass
  67. self.parse_data(item)
  68. self.queue.task_done()
  69. print("Thread_Parser=", self.threadID, 'total=', total)
  70. except:
  71. pass
  72. print "Exiting ", self.threadID
  73. def parse_data(self, item):
  74. """
  75. 解析网页函数
  76. :param item:网页内容
  77. :return
  78. """
  79. global total
  80. try:
  81. html = etree.HTML(item)
  82. result = html.xpath('//div[contains(@id,"qiushi_tag")]')
  83. for site in result:
  84. try:
  85. imgUrl = site.xpath('.//img/@src')[0]
  86. title = site.xpath('.//h2')[0].text
  87. content = site.xpath('.//div[@class="content"]/span')[0].text.strip()
  88. vote = None
  89. comments = None
  90. try:
  91. # 投票次数
  92. vote = site.xpath('.//i')[0].text
  93. # print(vote)
  94. #print site.xpath('.//*[@class="number"]')[0].text
  95. # 评论信息
  96. comments = site.xpath('.//i')[1].text
  97. except:
  98. pass
  99. result = {
  100. 'imageUrl' : imgUrl,
  101. 'title' : title,
  102. 'content' : content,
  103. 'vote' : vote,
  104. 'comments' : comments
  105. }
  106. with self.lock:
  107. self.f.write(json.dumps(result, ensure_ascii=False).encode('utf-8') + '\n')
  108. except Exception, e:
  109. print("site in result ", e)
  110. except Exception, e:
  111. print("parse_data", e)
  112. with self.lock:
  113. total += 1
  114. data_queue = Queue()
  115. exitFlag_Parser = False
  116. lock = threading.Lock()
  117. total = 0
  118. def main():
  119. output = open('qiushibaike.json', 'a')
  120. #初始化网页页码page从1-10个页面
  121. pageQueue = Queue(10)
  122. for page in range(1, 11):
  123. pageQueue.put(page)
  124. #初始化采集线程
  125. crawlthreads = []
  126. crawllist = ["crawl-1", "crawl-2", "crawl-3"]
  127. for threadID in crawllist:
  128. thread = Thread_crawl(threadID, pageQueue)
  129. thread.start()
  130. crawlthreads.append(thread)
  131. # #初始化解析线程parseList
  132. parserthreads = []
  133. parserList = ["parser-1", "parser-2", "parser-3"]
  134. #分别启动parserList
  135. for threadID in parserList:
  136. thread = Thread_Parser(threadID, data_queue, lock, output)
  137. thread.start()
  138. parserthreads.append(thread)
  139. # 等待队列情况
  140. while not pageQueue.empty():
  141. pass
  142. #等待所有线程完成
  143. for t in crawlthreads:
  144. t.join()
  145. while not data_queue.empty():
  146. pass
  147. #通知线程退出
  148. global exitFlag_Parser
  149. exitFlag_Parser = True
  150. for t in parserthreads:
  151. t.join()
  152. print 'Exiting Main Thread'
  153. with lock:
  154. output.close()
  155. if __name__ == '__main__':
  156. main()

Python爬虫(十八)_多线程糗事百科案例的更多相关文章

  1. [Python]网络爬虫(八):糗事百科的网络爬虫(v0.2)源码及解析

    转自:http://blog.csdn.net/pleasecallmewhy/article/details/8932310 项目内容: 用Python写的糗事百科的网络爬虫. 使用方法: 新建一个 ...

  2. python 多线程糗事百科案例

    案例要求参考上一个糗事百科单进程案例 Queue(队列对象) Queue是python中的标准库,可以直接import Queue引用;队列是线程间最常用的交换数据的形式 python下多线程的思考 ...

  3. 芝麻HTTP:Python爬虫实战之爬取糗事百科段子

    首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来. 友情提示 糗事百科在前一段时间进行了改版,导致之前的代码没法用了,会导致无法输出和CPU占用过高的 ...

  4. python 爬虫实战1 爬取糗事百科段子

    首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来. 本篇目标 抓取糗事百科热门段子 过滤带有图片的段子 实现每按一次回车显示一个段子的发布时间,发布人 ...

  5. Python爬虫实战之爬取糗事百科段子

    首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来. 友情提示 糗事百科在前一段时间进行了改版,导致之前的代码没法用了,会导致无法输出和CPU占用过高的 ...

  6. Python爬虫实战之爬取糗事百科段子【华为云技术分享】

    首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来. 友情提示 糗事百科在前一段时间进行了改版,导致之前的代码没法用了,会导致无法输出和CPU占用过高的 ...

  7. [python]爬虫学习(三)糗事百科

    import requestsimport osfrom bs4 import BeautifulSoupimport timepage=2url='http://www.qiushibaike.co ...

  8. python爬虫——利用BeautifulSoup4爬取糗事百科的段子

    import requests from bs4 import BeautifulSoup as bs #获取单个页面的源代码网页 def gethtml(pagenum): url = 'http: ...

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

    糗事百科实例 爬取糗事百科段子,假设页面的URL是: http://www.qiushibaike.com/8hr/page/1 要求: 使用requests获取页面信息,用XPath/re做数据提取 ...

随机推荐

  1. ajax参数解析

    url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. type: 要求为String类型的参数,请求方式(post或get)默认为get.注意其他http请求方法,例如put和 ...

  2. [置顶]【实用 .NET Core开发系列】- 导航篇

    前言 此系列从出发点来看,是 上个系列的续篇, 上个系列因为后面工作的原因,后面几篇没有写完,后来.NET Core出来之后,注意力就转移到了.NET Core上,所以再也就没有继续下去,此是原因之一 ...

  3. ubuntu小技巧(不定期更新)

    1.gedit打开windows保存的txt出现乱码 默认情况下,用ubuntu打开windows保存含有中文的txt文件时会出现乱码. 只需在终端运行以下两条命令则可解决. gsettings se ...

  4. .net core 同时实现网站管理员后台、会员、WebApi登录及权限控制

    我们在开网站信息系统时,常常有这样几个角色,如后台的管理员,前台的会员,以及我们各种应用的WebAPI 都需要进行登录操作及权限控制,那么在.net core如何进行设计呢. 首先我使用的是.net ...

  5. 如何从零开始对接第三方登录(Java版):QQ登录和微博登录

    前言 个人网站最近增加了评论功能,为了方便用户不用注册就可以评论,对接了QQ和微博这2大常用软件的一键登录,总的来说其实都挺简单的,可能会有一点小坑,但不算多,完整记录下来方便后来人快速对接. 后台设 ...

  6. 了解Python列表的一些方法

    首先定义一个名字列表,然后使用print() BIF在屏幕上显示这个列表. 接下来,使用len() BIF得出列表中有多少个数据项,然后再访问并显示第2个数据项的值: 创建了列表之后,可以使用列表方法 ...

  7. 源码剖析Django REST framework的请求生命周期

    学习Django的时候知道,在Django请求的生命周期中,请求经过WSGI和中间件到达路由,不管是FBV还是CBV都会先执行View视图函数中的dispatch方法 REST framework是基 ...

  8. WebService的基本介绍

    一.WebService的基本介绍    1.WebService是什么? WebService ---> Web Service web的服务    2.思考问题: WebService是we ...

  9. overflow-x: scroll;横向滑动详细讲解

    overflow-x: scroll;横向滑动(移动端使用详解) css3 , ie8以上 <!DOCTYPE html> <html lang="en"> ...

  10. python学习笔记 函数

    形式: def function(a,b,c=0,*args,**kw)#a,b必选参数,*args可变参数,**kw关键字参数 1.函数的返回值可以是多个参数.多个参数时,实际上返回的是一个tupl ...