用redis做简单的任务队列(二)
是用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做简单的任务队列(二)的更多相关文章
- 用redis做简单的任务队列(一)
队列本身其实是个有序的列表,而Redis是支持list的,我们可以查看Redis的官方文档 http://redis.io/commands#list,其中我们可以对这个队列的两端分别进行操作,所以其 ...
- 面试连环炮系列(二):你们的项目Redis做了集群部署吗
你们的项目Redis做了集群部署吗? 我们有大量数据需要缓存,而单实例的容量毕竟是有限的,于是做了Redis集群部署. 采取的方案是什么,Codis还是Redis Cluster,为什么要选择这个方案 ...
- 程序员修神之路--redis做分布式锁可能不那么简单
菜菜哥,复联四上映了,要不要一起去看看? 又想骗我电影票,对不对? 呵呵,想去看了叫我呀 看来你工作不饱和呀 哪有,这两天我刚基于redis写了一个分布式锁,很简单 不管你基于什么做分布式锁,你觉得很 ...
- Tomcat7基于Redis的Session共享实战二
目前,为了使web能适应大规模的访问,需要实现应用的集群部署.集群最有效的方案就是负载均衡,而实现负载均衡用户每一个请求都有可能被分配到不固定的服务器上,这样我们首先要解决session的统一来保证无 ...
- 使用Redis做预定库存缓存功能
最近在自己的工作中,把其中一个PHP项目的缓存从以前的APC缓存逐渐切换到Redis中,并且根据Redis所支持的数据结构做了库存维护功能.缓存是在业务层做的,准确讲应该是在MVC模型中Model的O ...
- 使用Redis做MyBatis的二级缓存
使用Redis做MyBatis的二级缓存 通常为了减轻数据库的压力,我们会引入缓存.在Dao查询数据库之前,先去缓存中找是否有要找的数据,如果有则用缓存中的数据即可,就不用查询数据库了. 如果没有才去 ...
- redis 的简单命令
以下实例讲解了如何启动 redis 客户端: 启动 redis 客户端,打开终端并输入命令 redis-cli.该命令会连接本地的 redis 服务. $redis-cli redis > re ...
- 使用Redis做分布式
一 为什么使用 Redis 在项目中使用 Redis,主要考虑两个角度:性能和并发.如果只是为了分布式锁这些其他功能,还有其他中间件 Zookpeer 等代替,并非一定要使用 Redis. 性能: 如 ...
- Redis源码阅读(二)高可用设计——复制
Redis源码阅读(二)高可用设计-复制 复制的概念:Redis的复制简单理解就是一个Redis服务器从另一台Redis服务器复制所有的Redis数据库数据,能保持两台Redis服务器的数据库数据一致 ...
随机推荐
- HDU3085(双向BFS+曼哈顿距离)题解
Nightmare Ⅱ Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- poj 2449 Remmarguts' Date 求第k短路 Astar算法
=.=好菜 #include <iostream> #include <cstdio> #include <string.h> #include <cstri ...
- Unity3D学习笔记(十七):IK动画、粒子系统和塔防
新动画系统: 反向动力学动画(IK功能): 魔兽世界(头部动画),神秘海域(手部动画),人类一败涂地(手部动画) 如何启用(调整) 1.必须是新动画系统Animator 设置头.手.肘的目标点 2.动 ...
- Unity3D学习笔记(十一):布料和协程
延迟函数:动态资源加载:T:Resources.Load<T>(string path);Assets - Resources,Resources是一个资源管理的工具类,预制体放在Reso ...
- The way to Go(5): 文件名、关键字与标识符
Reference: Github: Go Github: The way to Go 文件名 1.后缀名:.go 2.小写字母 3._分割名称 4.不包含空格或其他特殊字符 标识符 有效的标识符必须 ...
- 从零开始的四轴飞行器-开篇flag
在这里立下flag,我要理解学会四轴飞行器的控制方法.
- POJ 2728 Desert King(最优比率生成树 01分数规划)
http://poj.org/problem?id=2728 题意: 在这么一个图中求一棵生成树,这棵树的单位长度的花费最小是多少? 思路: 最优比率生成树,也就是01分数规划,二分答案即可,题目很简 ...
- BZOJ 1003: [ZJOI2006]物流运输(spfa+dp)
http://www.lydsy.com/JudgeOnline/problem.php?id=1003 题意: 思路: 首先用spfa计算一下任意两天之内的最短路,dis[a][b]表示的就是在第a ...
- 读jQuery源码有感
读之前的预备工作: 1.基础的js知识,以及html和css知识,和正则表达式知识.可以参考妙味课堂的基础js,html和css大纲. 2.JavaScript核心指南的知识http://www.cn ...
- JObject 用法 、JProperty 用法、JArray 用法 Linq 转 Json
1.使用LINQ to JSON前,需要引用Newtonsoft.Json的dll和using Newtonsoft.Json.Linq的命名空间.LINQ to JSON主要使用到JObject, ...