是用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. Maven可用setting.xml

    最简单的可用阿里镜像配置 <?xml version="1.0" encoding="UTF-8"?> <settings> <l ...

  2. mysql链接 显示 error: 'Access denied for user 'root'@'localhost' (using password: NO)'

    解决方案 https://stackoverflow.com/questions/2995054/access-denied-for-user-rootlocalhost-using-password ...

  3. [BZOJ1122][POI2008]账本BBB 单调队列+后缀和

    Description 一个长度为n的记账单,+表示存¥1,-表示取¥1.现在发现记账单有问题.一开始本来已经存了¥p,并且知道最后账户上还有¥q.你要把记账单修改正确,使得 1:账户永远不会出现负数 ...

  4. 常用字符与ASCII代码对照表

    常用字符与ASCII代码对照表 为了便于查询,以下列出ASCII码表:第128-255号为扩展字符(不常用) ASCII码 键盘 ASCII 码 键盘 ASCII 码 键盘 ASCII 码 键盘 27 ...

  5. linux 系统管理的10个小技巧

    1.恢复屏幕 尝试输入:#cat /bin/cat 输入的屏幕内容非常凌乱,那么该怎么做? 输入:#reset 那么屏幕恢复正常了,比关闭再次登录好多了,特别是经过至少5台机器和SSH2才能到达 2. ...

  6. Python CSV Reader/Writer 例子--转载

    CSV(comma-separated values) 是跨多种形式导入导出数据的标准格式,比如 MySQL.Excel. 它以纯文本存储数和文本.文件的每一行就代表一条数据,每条记录包含了由逗号分隔 ...

  7. codeforces 766E Mahmoud and a xor trip

    题目链接:http://codeforces.com/problemset/problem/766/E 大意,给出一个$n$个点的树,每个点都有一个权值,令$Disx$为$u$到$v$路径上的异或和求 ...

  8. Linux环境下的定时任务(转载)

    今天做了个数据库的备份脚本,顺便系统得学习一下Linux下定时执行脚本的设置.Linux下的定时执行主要是使用crontab文件中加入定制计划来执行,设置比Windows稍微复杂一些(因为没有图形界面 ...

  9. 转载:理解RESTful架构

    http://www.ruanyifeng.com/blog/2011/09/restful.html 越来越多的人开始意识到,网站即软件,而且是一种新型的软件. 这种"互联网软件" ...

  10. 删除node_modules

    // 删除node_modules $ rm -rf node_modules