原文:https://www.jianshu.com/p/06ae2373f560

  1 import threading  # 多线程模块
2 import queue # 队列模块
3 import requests
4 from lxml import etree
5 import time
6 import random
7 import json
8
9 concurrent = 3 # 采集线程数
10 conparse = 3 # 解析线程
11
12
13 class Parse(threading.Thread): # 解析线程类
14 # 初始化属性
15 def __init__(self, number, data_list, req_thread, f):
16 super(Parse, self).__init__()
17 self.number = number # 线程编号
18 self.data_list = data_list # 数据队列
19 self.req_thread = req_thread # 请求队列,为了判断采集线程存活状态
20 self.f = f # 获取文件对象
21 self.is_parse = True # 判断是否从数据队列里提取数据
22
23
24 def run(self):
25 print('启动%d号解析线程' % self.number)
26 # 无限循环,
27 while True:
28 # 如何判断解析线程的结束条件
29 for t in self.req_thread: # 循环所有采集线程
30 if t.is_alive(): # 判断线程是否存活
31 break
32 else: # 如果循环完毕,没有执行break语句,则进入else
33 if self.data_list.qsize() == 0: # 判断数据队列是否为空
34 self.is_parse = False # 设置解析为False
35 # 判断是否继续解析
36 if self.is_parse: # 解析
37 try:
38 data = self.data_list.get(timeout=3) # 从数据队列里提取一个数据
39 except Exception as e: # 超时以后进入异常
40 data = None
41 # 如果成功拿到数据,则调用解析方法
42 if data is not None:
43 self.parse(data) # 调用解析方法
44 else:
45 break # 结束while 无限循环
46 print('退出%d号解析线程' % self.number)
47
48
49 # 页面解析函数
50 def parse(self, data):
51 html = etree.HTML(data)
52 # 获取所有段子div
53 duanzi_div = html.xpath('//div[@id="content-left"]/div')
54 for duanzi in duanzi_div:
55 # 获取昵称
56 nick = duanzi.xpath('./div//h2/text()')[0]
57 nick = nick.replace('\n', '')
58 # 获取年龄
59 age = duanzi.xpath('.//div[@class="author clearfix"]/div/text()')
60 if len(age) > 0:
61 age = age[0]
62 else:
63 age = 0
64 # 获取性别
65 gender = duanzi.xpath('.//div[@class="author clearfix"]/div/@class')
66 if len(gender) > 0:
67 if 'women' in gender[0]:
68 gender = '女'
69 else:
70 gender = '男'
71 else:
72 gender = '中'
73 # 获取段子内容
74 content = duanzi.xpath('.//div[@class="content"]/span[1]/text()')[0].strip()
75 # 获取好笑数
76 good_num = duanzi.xpath('./div//span[@class="stats-vote"]/i/text()')[0]
77 # 获取评论
78 common_num = duanzi.xpath('./div//span[@class="stats-comments"]//i/text()')[0]
79 item = {
80 'nick': nick,
81 'age': age,
82 'gender': gender,
83 'content': content,
84 'good_num': good_num,
85 'common_num': common_num,
86 }
87 self.f.write(json.dumps(item, ensure_ascii=False) + '\n')
88
89
90 class Crawl(threading.Thread): # 采集线程类
91 # 初始化
92 def __init__(self, number, req_list, data_list):
93 # 调用Thread 父类方法
94 super(Crawl, self).__init__()
95 # 初始化子类属性
96 self.number = number
97 self.req_list = req_list
98 self.data_list = data_list
99 self.headers = {
100 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36'
101 }
102 # 线程启动的时候调用
103
104 def run(self):
105 # 输出启动线程信息
106 print('启动采集线程%d号' % self.number)
107 # 如果请求队列不为空,则无限循环,从请求队列里拿请求url
108 while self.req_list.qsize() > 0:
109 # 从请求队列里提取url
110 url = self.req_list.get()
111 print('%d号线程采集:%s' % (self.number, url))
112 # 防止请求频率过快,随机设置阻塞时间
113 time.sleep(random.randint(1, 3))
114 # 发起http请求,获取响应内容,追加到数据队列里,等待解析
115 response = requests.get(url, headers=self.headers)
116 if response.status_code == 200:
117 self.data_list.put(response.text) # 向数据队列里追加
118
119
120 def main():
121 # 生成请求队列
122 req_list = queue.Queue()
123 # 生成数据队列 ,请求以后,响应内容放到数据队列里
124 data_list = queue.Queue()
125 # 创建文件对象
126 f = open('duanzi.json', 'w', encoding='utf-8')
127 # 循环生成多个请求url
128 for i in range(1, 13 + 1):
129 base_url = 'https://www.qiushibaike.com/8hr/page/%d/' % i
130 # 加入请求队列
131 req_list.put(base_url)
132 # 生成N个采集线程
133 req_thread = []
134 for i in range(concurrent):
135 t = Crawl(i + 1, req_list, data_list) # 创造线程
136 t.start()
137 req_thread.append(t)
138 # 生成N个解析线程
139 parse_thread = []
140 for i in range(conparse):
141 t = Parse(i + 1, data_list, req_thread, f) # 创造解析线程
142 t.start()
143 parse_thread.append(t)
144 for t in req_thread:
145 t.join()
146 for t in parse_thread:
147 t.join()
148 # 关闭文件对象
149 f.close()
150
151 if __name__ == '__main__':
152 main()

python3 多线程爬虫模板的更多相关文章

  1. python3多线程爬虫(第一卷)

    多进程虽然使用方便,可以充分利用CPU,但是由于个进程之间是并行且各自有自己的数据存储,所以很难进行数据间的通信,需要接入第三方模块,现在我依旧用糗事百科讲解下多线程的应用,举个例子之前用4个进程同时 ...

  2. 【python3两小时快速入门】入门笔记03:简单爬虫+多线程爬虫

    作用,之间将目标网页保存金本地 1.爬虫代码修改自网络,目前运行平稳,博主需要的是精准爬取,数据量并不大,暂未加多线程. 2.分割策略是通过查询条件进行分类,循环启动多条线程. 1.单线程简单爬虫(第 ...

  3. HTML5触屏版多线程渲染模板技术分享

    前言: 了解js编译原理的屌丝们都知道,js是单线程的,想当年各路神仙为了实现js的多线程,为了解决innerHTML输出大段HTML卡页面的顽疾,纷纷设计了诸如假冒的“多线程“实现,我自己也在写开源 ...

  4. Task 实现多线程的模板

        1.Task多线程简单模板   using System; using System.Collections.Generic; using System.Threading.Tasks;   ...

  5. Python3.x爬虫教程:爬网页、爬图片、自己主动登录

    林炳文Evankaka原创作品. 转载请注明出处http://blog.csdn.net/evankaka 摘要:本文将使用Python3.4爬网页.爬图片.自己主动登录.并对HTTP协议做了一个简单 ...

  6. python多线程爬虫设计及实现示例

    爬虫的基本步骤分为:获取,解析,存储.假设这里获取和存储为io密集型(访问网络和数据存储),解析为cpu密集型.那么在设计多线程爬虫时主要有两种方案:第一种方案是一个线程完成三个步骤,然后运行多个线程 ...

  7. Python多线程爬虫与多种数据存储方式实现(Python爬虫实战2)

    1. 多进程爬虫 对于数据量较大的爬虫,对数据的处理要求较高时,可以采用python多进程或多线程的机制完成,多进程是指分配多个CPU处理程序,同一时刻只有一个CPU在工作,多线程是指进程内部有多个类 ...

  8. 多线程爬虫Miner

    多线程爬虫Miner 需要配置项:1.URL包含关键字.2.存储方式:DB-数据库存储;FILE-文件存储.3.爬取页面最大深度.4.下载页面线程数.5.分析页面线程数.6.存储线程数. ------ ...

  9. python爬虫入门(四)利用多线程爬虫

    多线程爬虫 先回顾前面学过的一些知识 1.一个cpu一次只能执行一个任务,多个cpu同时可以执行多个任务2.一个cpu一次只能执行一个进程,其它进程处于非运行状态3.进程里包含的执行单元叫线程,一个进 ...

随机推荐

  1. 惠普机械键盘 K10GL 使用评测

    惠普机械键盘 GK100 使用评测 手感太差,不是 RGB 背光 惠普(HP) K10GL 机械键盘 有线 LED背光机械键盘 87键 混光青轴 refs https://item.jd.com/10 ...

  2. 你所不知道的 JS: null , undefined, NaN, true==1=="1",false==0=="",null== undefined

    1 1 1 === 全相等(全部相等) ==  值相等(部分相等) demo: var x=0; undefined var y=false; undefined if(x===y){ console ...

  3. Promise console.log All In One

    Promise console.log All In One 同步事件/异步事件 微任务/宏任务 js 事件循环原理 先执行 同步事件 在执行,异步事件的所有微任务队列,按照时间顺序 最后执行,异步事 ...

  4. vueJS+ES6开发移动端APP实战项目笔记

    一.什么是MVVM框架 MV*包括MVC.MVP.MVVM MVVM框架由Model.View.ViewModel构成. Model指的是数据,在前端对应的是JavaScript对象. View指的是 ...

  5. Techme INC:红光和近红外光疗法有效加速肌肉恢复,美国橄榄球队已采用

    Techme INC创始人兼董事长MADELEINE VAUGHAN表示:在运动结束后,肌肉纤维因为细微损伤造成酸痛情形,即是延迟性肌肉酸痛-DOMS.这类酸痛发生时,需要适度的恢复,避免造成肌肉拉伤 ...

  6. 【python接口自动化】- 对接各大数据库

    相信很多小伙伴在使用python进行自动化测试的时候,都会涉及到数据库数据校验的问题,在前面的随笔中就已经有讲过连接mysql的使用,今天给大家汇总一下python对接几大常用的数据库操作的方法!众所 ...

  7. MySQL 修改数据表

    修改数据表: 创建数据表 更改表明 更改字段数据类型 更改字段名称 更改字段名称和数据类型 为表添加新字段 将字段顺序改为第一位 将字段顺序改为另一个字段之后 删除字段 1 use test; 2 3 ...

  8. Elasticsearch 及其套件的安装上手

    前言 本文主要讲解Elasticsearch及其套件Kibana.Logstash的安装及启动,还讲解如何导入数据用于后续的实验. 说明:Elasticsearch是基于Java开发的,所以如果是下载 ...

  9. python常用内置方法index\extend\count\reverse\sort

    定义列表:(有2个值相同) a = ['XiaoBao','aiaoHao','biaoLiao','ciaoQing','eiaoLi','QiBao','biaoLiao'] 列表的索引: fir ...

  10. 6. vue组件详解(一)

    主要内容: 1. 组件的基本使用 2. 全局组件和局部组件 3. 父组件和子组件 4. 组件语法糖的写法 5. 组件data关联的写法 6. 父子组件的通信 组件系统是 Vue 的一个重要概念,因为它 ...