原文: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. 内网域渗透之MS14-068复现(CVE-2014-6324)

    在做域渗透测试时,当我们拿到了一个普通域成员的账号后,想继续对该域进行渗透,拿到域控服务器权限.如果域控服务器存在MS14_068漏洞,并且未打补丁,那么我们就可以利用MS14_068快速获得域控服务 ...

  2. Linux 驱动框架---驱动中的并发

    并发指多个执行单元被同时.并行的执行,而并发执行的单元对共享资源的访问就容易导致竟态.并发产生的情况分为抢占和并行(多核)和硬抢占(中断).Linux为解决这一问题增加了一系列的接口来解决并发导致的竟 ...

  3. Windows 10 Emoji shortcuts

    Windows 10 Emoji shortcuts Windows 10 Emoji 快捷方式 https://support.microsoft.com/en-us/windows/windows ...

  4. Apple Watch Series 6 屏幕误触放大后无法还原问题和解决方案

    Apple Watch Series 6 屏幕误触放大后无法还原问题和解决方案 shit Apple,只能放大,不能缩小! 解决方案 关闭缩放功能 https://support.apple.com/ ...

  5. how to read the 10th line of a text using shell script

    how to read the 10th line of a text using shell script shell script / bash script question https://l ...

  6. Sketch & UI & PS

    Sketch & UI & PS app ui https://sketchapp.com/learn https://www.sketch.com/docs/ https://ske ...

  7. Taro Advanced

    Taro Advanced aro 代码与小程序代码混写 https://nervjs.github.io/taro/docs/hybrid.html https://github.com/NervJ ...

  8. 宝塔部署Nestjs

    1. 在宝塔上下载pm2 2. 打包你的服务端代码 "npm run build && cp ./package.json ./dist/" 3. 在宝塔文件&qu ...

  9. js add Struct to ArrayBuffer

    使用struct-buffer为ArrayBuffer添加结构体 $ npm i struct-buffer 1. 创建结构体 import { DWORD, string_t, StructBuff ...

  10. Python 与 excel的简单应用

    1.pip openpyxl库: pip install openpyxl -i http://pypi.douban.com/simple --trust-host pypi.douban.com ...