是用redis做任务队列时,要思考:

  • 用什么数据类型来做任务队列
  • 怎样才能防止重复爬取

上一篇文章已经决定使用list来做任务队列,但是去重问题没有得到解决。这里可以用set来解决思考二的问题,就是防止重复爬取的问题。

使用list当作未完成任务队列,存储还没有爬的url(或者是用户id,文章id等唯一标识)
使用set当作已完成任务队列,存储已经爬取的url
每次爬虫程序从list未完成任务队列获取任务的时候,都去set已完成任务队列里面验证一下,如果已完成队列里已经有了,就舍弃掉,如果没有,就开始爬取,并将这个url加入到已爬取的任务队列
这样做的方便之处在于:每当我往list未完成任务队列里加任务的时候,我不用考虑这个任务有没有爬过,这个任务是不是已经在未爬取任务队列了,我只需要往里加就行了,当爬虫去取的时候,让爬虫程序去做这个操作。

以下是具体代码 
算是一个生产消费把,master往队列里塞任务,parser使用get_html的返回值进行解析,然后入库。

协程爬取贴吧里发帖内容(redis做任务队列,mongo存储)

 import requests
from lxml import etree
import redis
import asyncio,aiohttp import pymongo
conn = pymongo.MongoClient('localhost',27017) db = conn.nicedb # 指定数据库名称,连接nicedb数据库,没有则自动创建
my_set = db.test_set # 使用test_set集合,没有则自动创建
# 以上两步都是延时操作,当往数据库插入第一条数据的时候,才会真正的创建数据库和集合 # decode_responses=True,记得加这个参数,不加的话取出来的数据都是bytes类型的
r = redis.StrictRedis(host = '127.0.0.1', port = 6379, db = 2,decode_responses=True)
# pool = redis.ConnectionPool(host = '127.0.0.1', port = 6379, db = 2)
# r = redis.StrictRedis(connection_pool=pool,decode_responses=True) def master(page):
url = 'https://tieba.baidu.com/f?kw=美女&ie=utf-8&pn={}'.format(page*50)
base = 'https://tieba.baidu.com'
res = requests.get(url).text
html = etree.HTML(res)
half_urls = html.xpath("//div[@class='threadlist_title pull_left j_th_tit ']/a/@href")
full_urls = [base + i for i in half_urls]
for url in full_urls:
# 从url_list列表头部塞任务,也就是url
r.lpush('url_list',url)
#print(r.llen('url_list')) async def get_html(url):
async with asyncio.Semaphore(5): # 限制并发数为5个
async with aiohttp.ClientSession() as session:
async with session.get(url) as html:
# errors='ignore',不加这个参数的话,会报错,具体错误内容见下面图片
response = await html.text(encoding='utf-8',errors='ignore')
return response
async def parse():
while True:
# 从redis的url_list列表取任务,从右边开始取
url = r.rpop('url_list')
if url == None:
break
# 判断这个任务是否已经做过了,也就是判断这个url在没在redis的history集合里
if r.sismember('history',url) == 1:
continue
response = await get_html(url)
html = etree.HTML(response)
content = html.xpath("//div[@class='left_section']/div[2]/div[1]//cc/div[1]/text()")[0].strip()
if content != '':
# 当内容不为空时,将内容存到mongo里
my_set.save({'content':content})
#print(content)
# 将爬取过的任务放到redis的history集合里,也就是已完成任务队列
r.sadd('history', url)
t1 = time.time()
# 爬取前10页
for i in range(10):
master() # async的一些步骤
loop = asyncio.get_event_loop()
tasks = [parse() for _ in range(15)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close() t2 = time.time()
print(t2-t1)
# 最后用时:32.930299043655396
# 把mongo数据库换成mysql后,用时:43.06192493438721 原文:https://blog.csdn.net/fiery_heart/article/details/82121237

用redis做简单的任务队列(二)的更多相关文章

  1. 用redis做简单的任务队列(一)

    队列本身其实是个有序的列表,而Redis是支持list的,我们可以查看Redis的官方文档 http://redis.io/commands#list,其中我们可以对这个队列的两端分别进行操作,所以其 ...

  2. 面试连环炮系列(二):你们的项目Redis做了集群部署吗

    你们的项目Redis做了集群部署吗? 我们有大量数据需要缓存,而单实例的容量毕竟是有限的,于是做了Redis集群部署. 采取的方案是什么,Codis还是Redis Cluster,为什么要选择这个方案 ...

  3. 程序员修神之路--redis做分布式锁可能不那么简单

    菜菜哥,复联四上映了,要不要一起去看看? 又想骗我电影票,对不对? 呵呵,想去看了叫我呀 看来你工作不饱和呀 哪有,这两天我刚基于redis写了一个分布式锁,很简单 不管你基于什么做分布式锁,你觉得很 ...

  4. Tomcat7基于Redis的Session共享实战二

    目前,为了使web能适应大规模的访问,需要实现应用的集群部署.集群最有效的方案就是负载均衡,而实现负载均衡用户每一个请求都有可能被分配到不固定的服务器上,这样我们首先要解决session的统一来保证无 ...

  5. 使用Redis做预定库存缓存功能

    最近在自己的工作中,把其中一个PHP项目的缓存从以前的APC缓存逐渐切换到Redis中,并且根据Redis所支持的数据结构做了库存维护功能.缓存是在业务层做的,准确讲应该是在MVC模型中Model的O ...

  6. 使用Redis做MyBatis的二级缓存

    使用Redis做MyBatis的二级缓存 通常为了减轻数据库的压力,我们会引入缓存.在Dao查询数据库之前,先去缓存中找是否有要找的数据,如果有则用缓存中的数据即可,就不用查询数据库了. 如果没有才去 ...

  7. redis 的简单命令

    以下实例讲解了如何启动 redis 客户端: 启动 redis 客户端,打开终端并输入命令 redis-cli.该命令会连接本地的 redis 服务. $redis-cli redis > re ...

  8. 使用Redis做分布式

    一 为什么使用 Redis 在项目中使用 Redis,主要考虑两个角度:性能和并发.如果只是为了分布式锁这些其他功能,还有其他中间件 Zookpeer 等代替,并非一定要使用 Redis. 性能: 如 ...

  9. Redis源码阅读(二)高可用设计——复制

    Redis源码阅读(二)高可用设计-复制 复制的概念:Redis的复制简单理解就是一个Redis服务器从另一台Redis服务器复制所有的Redis数据库数据,能保持两台Redis服务器的数据库数据一致 ...

随机推荐

  1. TeeChart入门

    此链接可以作为参考http://tech.sina.com.cn/s/2008-07-07/1612722495.shtml 需要添加引用 using Steema.TeeChart;//tchart ...

  2. [JVM] - 不就是JVM么 JVM的继续探究

    前面几章跟着作者的脚步实现了使用Go语言查看java的.class文件源码(16进制) 复习一下: 相比Java语言,Go的访问控制非常简单,只有公开和私有两种. 所有首字母大写的类型, 结构体,字段 ...

  3. ZOJ 3869 Ace of Aces

    There is a mysterious organization called Time-Space Administrative Bureau (TSAB) in the deep univer ...

  4. 软件测试&安全测试高峰论坛

    Nubia测试以及介绍 基于Cucumber的自动化测试平台 常见Web漏洞之XSS,主要HTML与JS基础.XSS的基础知识与挖掘方法.XSS的利用 自动化测试框架以及测试思路

  5. editplus5激活码

    editplus5激活码 name: Vovan code: 3AG46-JJ48E-CEACC-8E6EW-ECUAW 转自:https://blog.csdn.net/webfront/artic ...

  6. python 二叉排序树

    class BSTNode: def __init__(self, data, left=None, right=None): self.data = data self.left = left se ...

  7. Springboot 编码规范

    1.规范的意义和作用 编码规范可以最大限度的提高团队开发的合作效率 编码规范可以尽可能的减少一个软件的维护成本 , 并且几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护 编码规范可以 ...

  8. 卡内基梅隆大学软件工程研究所先后制定用于评价软件系统成熟度的模型CMM和CMMI

    SEI(美国卡内基梅隆大学软件工程研究所(Software Engineering Institute, SEI))开发的CMM模型有: 用于软件的(SW-CMM;SW代表'software即软件') ...

  9. kali linux下几个更新命令的区分

    首先更新命令有:apt-get update ,apt-get upgrade ,apt-get dist-upgrade等三个: (1)apt-get update:只更新软件包的索引源,作用:同步 ...

  10. IntelliJ IDE 开发Java GUI 入门

    j主要对java 的GUI相关知识进行简单的介绍和总结,整个博客按照创建一个java GUI的顺序进行介绍,期间穿插讲解用到的java Swing的布局.控件等相关知识.本博客所进行的讲解及工程的创建 ...