多线程爬虫

先回顾前面学过的一些知识

1.一个cpu一次只能执行一个任务,多个cpu同时可以执行多个任务
2.一个cpu一次只能执行一个进程,其它进程处于非运行状态
3.进程里包含的执行单元叫线程,一个进程可以包含多个线程
4.一个进程的内存空间是共享的,每个进程里的线程都可以使用这个共享空间
5.一个线程在使用这个共享空间的时候,其它的线程必须等待(阻塞状态)
6.互斥锁作用就是防止多个线程同时使用这块内存空间,先使用的线程会将空间上锁,其它的线程处于等待状态。等锁开了才能进
7.进程:表示程序的一次执行
8.线程:CPU运算的基本调度单位
9.GIL(全局锁):python里的执行通行证,而且只有一个。拿到通行证的线程就可以进入CPU执行任务。没有GIL的线程就不能执行任务
10.python的多线程适用于大量密集的I/O处理
11.python的多进程适用于大量的密集并行计算

多线程爬取糗事百科

#!/usr/bin/env python
# -*- coding:utf-8 -*- # 使用了线程库
import threading
# 队列
from Queue import Queue
# 解析库
from lxml import etree
# 请求处理
import requests
# json处理
import json
import time class ThreadCrawl(threading.Thread):
def __init__(self, threadName, pageQueue, dataQueue):
#threading.Thread.__init__(self)
# 调用父类初始化方法
super(ThreadCrawl, self).__init__()
# 线程名
self.threadName = threadName
# 页码队列
self.pageQueue = pageQueue
# 数据队列
self.dataQueue = dataQueue
# 请求报头
self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'} def run(self):
print "启动 " + self.threadName
while not CRAWL_EXIT:
try:
# 取出一个数字,先进先出
# 可选参数block,默认值为True
#1. 如果对列为空,block为True的话,不会结束,会进入阻塞状态,直到队列有新的数据
#2. 如果队列为空,block为False的话,就弹出一个Queue.empty()异常,
page = self.pageQueue.get(False)
url = "http://www.qiushibaike.com/8hr/page/" + str(page) +"/"
#print url
content = requests.get(url, headers = self.headers).text
time.sleep(1)
self.dataQueue.put(content)
#print len(content)
except:
pass
print "结束 " + self.threadName class ThreadParse(threading.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):
print "启动" + self.threadName
while not PARSE_EXIT:
try:
html = self.dataQueue.get(False)
self.parse(html)
except:
pass
print "退出" + self.threadName def parse(self, html):
# 解析为HTML DOM
html = etree.HTML(html) node_list = html.xpath('//div[contains(@id, "qiushi_tag")]') for node in node_list:
# xpath返回的列表,这个列表就这一个参数,用索引方式取出来,用户名
username = node.xpath('./div/a/@title')[0]
# 图片连接
image = node.xpath('.//div[@class="thumb"]//@src')#[0]
# 取出标签下的内容,段子内容
content = node.xpath('.//div[@class="content"]/span')[0].text
# 取出标签里包含的内容,点赞
zan = node.xpath('.//i')[0].text
# 评论
comments = node.xpath('.//i')[1].text items = {
"username" : username,
"image" : image,
"content" : content,
"zan" : zan,
"comments" : comments
} # with 后面有两个必须执行的操作:__enter__ 和 _exit__
# 不管里面的操作结果如何,都会执行打开、关闭
# 打开锁、处理内容、释放锁
with self.lock:
# 写入存储的解析后的数据
self.filename.write(json.dumps(items, 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() filename = open("duanzi.json", "a")
# 创建锁
lock = threading.Lock() # 三个采集线程的名字
crawlList = ["采集线程1号", "采集线程2号", "采集线程3号"]
# 存储三个采集线程的列表集合
threadcrawl = []
for threadName in crawlList:
thread = ThreadCrawl(threadName, pageQueue, dataQueue)
thread.start()
threadcrawl.append(thread) # 三个解析线程的名字
parseList = ["解析线程1号","解析线程2号","解析线程3号"]
# 存储三个解析线程
threadparse = []
for threadName in parseList:
thread = ThreadParse(threadName, dataQueue, filename, lock)
thread.start()
threadparse.append(thread) # 等待pageQueue队列为空,也就是等待之前的操作执行完毕
while not pageQueue.empty():
pass # 如果pageQueue为空,采集线程退出循环
global CRAWL_EXIT
CRAWL_EXIT = True print "pageQueue为空" for thread in threadcrawl:
thread.join()
print "" while not dataQueue.empty():
pass global PARSE_EXIT
PARSE_EXIT = True for thread in threadparse:
thread.join()
print "" with lock:
# 关闭文件
filename.close()
print "谢谢使用!" if __name__ == "__main__":
main()

python爬虫入门(四)利用多线程爬虫的更多相关文章

  1. Python爬虫入门四之Urllib库的高级用法

    1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性. 首先,打开我们的浏览 ...

  2. 转 Python爬虫入门四之Urllib库的高级用法

    静觅 » Python爬虫入门四之Urllib库的高级用法 1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我 ...

  3. 爬虫入门四 re

    title: 爬虫入门四 re date: 2020-03-14 16:49:00 categories: python tags: crawler 正则表达式与re库 1 正则表达式简介 编译原理学 ...

  4. 【爬虫入门手记03】爬虫解析利器beautifulSoup模块的基本应用

    [爬虫入门手记03]爬虫解析利器beautifulSoup模块的基本应用 1.引言 网络爬虫最终的目的就是过滤选取网络信息,因此最重要的就是解析器了,其性能的优劣直接决定这网络爬虫的速度和效率.Bea ...

  5. RobotFramework + Python 自动化入门 四 (Web进阶)

    在<RobotFramwork + Python 自动化入门 一>中,完成了一个Robot环境搭建及测试脚本的创建和执行. 在<RobotFramwork + Python 自动化入 ...

  6. python爬虫入门四:BeautifulSoup库(转)

    正则表达式可以从html代码中提取我们想要的数据信息,它比较繁琐复杂,编写的时候效率不高,但我们又最好是能够学会使用正则表达式. 我在网络上发现了一篇关于写得很好的教程,如果需要使用正则表达式的话,参 ...

  7. 4.Python爬虫入门四之Urllib库的高级用法

    1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性. 首先,打开我们的浏览 ...

  8. Python爬虫入门教程 50-100 Python3爬虫爬取VIP视频-Python爬虫6操作

    爬虫背景 原计划继续写一下关于手机APP的爬虫,结果发现夜神模拟器总是卡死,比较懒,不想找原因了,哈哈,所以接着写后面的博客了,从50篇开始要写几篇python爬虫的骚操作,也就是用Python3通过 ...

  9. Python爬虫入门教程 53-100 Python3爬虫获取三亚天气做旅游参照

    爬取背景 这套课程虽然叫爬虫入门类课程,但是里面涉及到的点是非常多,十分检验你的基础掌握的牢固程度,代码中的很多地方都是可以细细品味的. 为什么要写这么一个小东东呢,因为我生活在大河北,那雾霾醇厚的很 ...

随机推荐

  1. Python学习笔记 - ifelifelse-forin-while

    if elif else #!/usr/bin/env python3 # -*- coding: utf-8 -*- age = 20 if age >= 18: print('your ag ...

  2. 【Android 应用开发】Android开发 使用 adb logcat 显示 Android 日志

    作者 : 万境绝尘  转载请著名出处 eclipse 自带的 LogCat 工具太垃圾了, 开始用 adb logcat 在终端查看日志; 1. 解析 adb logcat 的帮助信息 在命令行中输入 ...

  3. (NO.00001)iOS游戏SpeedBoy Lite成形记(十六)

    接上篇,我们实现菜单窗口的弹出和关闭功能,首先在打开GameScene.m,添加必要的实例变量: __weak PopupLayer *_popupLayer; 再添加2个新方法: -(void)re ...

  4. Leetcode_154_Find Minimum in Rotated Sorted Array

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/43416613 Suppose a sorted array ...

  5. 【面试笔试算法】Program 4 : Best Compression Algorithms(网易游戏笔试题)

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 易信是由网易和电信联合开发的一款即时通讯软件.除了语音聊天,免费电话等新功能以外,传统的文字信息聊天功能也得以保留,因此每 ...

  6. Learning ROS for Robotics Programming Second Edition学习笔记(四) indigo devices

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  7. 网站开发进阶(十一)如何将一个jsp页面嵌套在另一个页面中

    如何将一个jsp页面嵌套在另一个页面中 这个在做网页中常要用到,有些通用的内容可集中放在一个页面文件中,其它要用到这些内容的页面只需要包含(引用)这个通用文件即可.这样便于维护,如果有很多网页,当通用 ...

  8. Github 错误合集:Failed connect to github.com:8080 || Failed connect to github.com:443; No error

    文/skay 地址:http://blog.csdn.net/sk719887916/article/details/40541199 开发中遇到github无法pull和push代码问题,原来git ...

  9. day08_Servlet学习笔记

     ============================================================ 一.什么是Servlet?(非常非常重要) servlet 是运行在 Web ...

  10. Spring Cloud入门教程-Ribbon实现客户端负载均衡

    简介 我们继续以之前博客的代码为基础,增加Ribbon组件来提供客户端负载均衡.负载均衡是实现高并发.高性能.可伸缩服务的重要组成部分,它可以把请求分散到一个集群中不同的服务器中,以减轻每个服务器的负 ...