这篇文章主要介绍了使用Redis实现UA池的方案,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

最近忙于业务开发、交接和游戏,加上碰上了不定时出现的犹豫期和困惑期,荒废学业了一段时间。天冷了,要重新拾起开始下阶段的学习了。之前接触到的一些数据搜索项目,涉及到请求模拟,基于反爬需要使用随机的 User Agent ,于是使用 Redis 实现了一个十分简易的 UA 池。

背景

最近的一个需求,有模拟请求的逻辑,要求每次请求的请求头中的 User Agent下面几点:

    每次获取的 User Agent 是随机的。 每次获取的 User Agent (短时间内)不能重复。 每次获取的 User Agent 必须带有主流的操作系统信息(可以是 UinuxWindowsIOS 和安卓等等)。

这里三点都可以从 UA 数据的来源解决,实际上我们应该关注具体的实现方案。简单分析一下,流程如下:

在设计 UA 池的时候,它的数据结构和环形队列十分类似:

上图中,假设不同颜色的 UA 是完全不同的 UA ,它们通过洗牌算法打散放进去环形队列中,实际上每次取出一个 UA 之后,只需要把游标 cursor 前进或者后退一格即可(甚至可以把游标设置到队列中的任意元素)。最终的实现就是:需要通过中间件实现分布式队列(只是队列,不是消息队列)。

具体实现方案

毫无疑问需要一个分布式数据库类型的中间件才能存放已经准备好的 UA ,第一印象就感觉 Redis 会比较合适。接下来需要选用 Redis 的数据类型,主要考虑几个方面:

UA

支持这几个方面的 Redis 数据类型就是 List ,不过注意 List 本身不能去重,去重的工作可以用代码逻辑实现。然后可以想象客户端获取 UA 的流程大致如下:

结合前面的分析,编码过程有如下几步:

准备好需要导入的 UA 数据,可以从数据源读取,也可以直接文件读取。

     因为需要导入的 UA 数据集合一般不会太大,考虑先把这个集合的数据随机打散,如果使用 Java 开发可以直接使用 Collections#shuffle() 洗牌算法,当然也可以自行实现这个数据随机分布的算法, 这一步对于一些被模拟方会严格检验 UA 合法性的是必须的 。 导入 UA 数据到 Redis 列表中。 编写 RPOP + LPUSHLua 脚本,实现分布式循环队列。

编码和测试示例

引入 Redis 的高级客户端 Lettuce 依赖:

<dependency>
  <groupId>io.lettuce</groupId>
  <artifactId>lettuce-core</artifactId>
  <version>5.2.1.RELEASE</version>
</dependency>

编写 RPOP + LPUSHLua 脚本, Lua 脚本名字暂称为 L_RPOP_LPUSH.lua ,放在 resources/scripts/lua 目录下:

local key = KEYS[1]
local value = redis.call('RPOP', key)
redis.call('LPUSH', key, value)
return value

这个脚本十分简单,但是已经实现了循环队列的功能。剩下来的测试代码如下:

public class UaPoolTest {

  private static RedisCommands<String, String> COMMANDS;

  private static AtomicReference<String> LUA_SHA = new AtomicReference<>();
  private static final String KEY = "UA_POOL";

  @BeforeClass
  public static void beforeClass() throws Exception {
    // 初始化Redis客户端
    RedisURI uri = RedisURI.builder().withHost("localhost").withPort(6379).build();
    RedisClient redisClient = RedisClient.create(uri);
    StatefulRedisConnection<String, String> connect = redisClient.connect();
    COMMANDS = connect.sync();
    // 模拟构建UA池的原始数据,假设有10个UA,分别是UA-0 ... UA-9
    List<String> uaList = Lists.newArrayList();
    IntStream.range(0, 10).forEach(e -> uaList.add(String.format("UA-%d", e)));
    // 洗牌
    Collections.shuffle(uaList);
    // 加载Lua脚本
    ClassPathResource resource = new ClassPathResource("/scripts/lua/L_RPOP_LPUSH.lua");
    String content = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
    String sha = COMMANDS.scriptLoad(content);
    LUA_SHA.compareAndSet(null, sha);
    // Redis队列中写入UA数据,数据量多的时候可以考虑分批写入防止长时间阻塞Redis服务
    COMMANDS.lpush(KEY, uaList.toArray(new String[0]));
  }

  @AfterClass
  public static void afterClass() throws Exception {
    COMMANDS.del(KEY);
  }

  @Test
  public void testUaPool() {
    IntStream.range(1, 21).forEach(e -> {
      String result = COMMANDS.evalsha(LUA_SHA.get(), ScriptOutputType.VALUE, KEY);
      System.out.println(String.format("第%d次获取到的UA是:%s", e, result));
    });
  }
}

某次运行结果如下:

第1次获取到的UA是:UA-0
第2次获取到的UA是:UA-8
第3次获取到的UA是:UA-2
第4次获取到的UA是:UA-4
第5次获取到的UA是:UA-7
第6次获取到的UA是:UA-5
第7次获取到的UA是:UA-1
第8次获取到的UA是:UA-3
第9次获取到的UA是:UA-6
第10次获取到的UA是:UA-9
第11次获取到的UA是:UA-0
第12次获取到的UA是:UA-8
第13次获取到的UA是:UA-2
第14次获取到的UA是:UA-4
第15次获取到的UA是:UA-7
第16次获取到的UA是:UA-5
第17次获取到的UA是:UA-1
第18次获取到的UA是:UA-3
第19次获取到的UA是:UA-6
第20次获取到的UA是:UA-9

可见洗牌算法的效果不差,数据相对分散。

小结

其实 UA 池的设计难度并不大,需要注意几个要点:

    一般主流的移动设备或者桌面设备的系统版本不会太多,所以来源 UA 数据不会太多,最简单的实现可以使用文件存放,一次读取直接写入 Redis 中。 注意需要随机打散 UA 数据,避免同一个设备系统类型的 UA 数据过于密集,这样可以避免触发模拟某些请求时候的风控规则。 需要熟悉 Lua 的语法,毕竟 Redis 的原子指令一定离不开 Lua 脚本。

总结

以上所述是小编给大家介绍的使用Redis实现UA池的方案,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对爱安网网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

最新资讯
陈·扎克伯格基金会受牵连 担心慈善工作受Facebook影响

陈·扎克伯格基金会受

马克·扎克伯格(Mark Zuckerberg)现在不仅要面对Faceboo
定期称重就能减肥?体重计不会辜负你

定期称重就能减肥?体重

根据国际行为营养学和运动学关于称重与体重管理的一篇
新型猪流感病毒会引发大流行吗?3专家释疑

新型猪流感病毒会引发

这种流感病毒真有传言的那么厉害?该病毒已经在猪群中间
在一只肥皂泡上,他们首次看见光线的分支

在一只肥皂泡上,他们首

最新一期《自然》杂志的封面文章中,以色列理工学院的研
如果人类旅居月球,这个细节得先弄清楚

如果人类旅居月球,这个

地球磁尾的摇摆是太阳风和地球磁层相互作用产生的现象
分水岭时刻:科技四巨头CEO首次国会集体作证 各个击破or抱团取胜

分水岭时刻:科技四巨

未来几周,当亚马逊CEO杰夫•贝佐斯、苹果CEO蒂姆·库克
最新文章
从一个小需求感受Redis的独特魅力(需求设计)

从一个小需求感受Redi

Redis在实际应用中使用的非常广泛,本篇文章就从一个简
详解redis desktop manager安装及连接方式

详解redis desktop ma

这篇文章主要介绍了redis desktop manager安装及连接
Redis集群下过期key监听的实现代码

Redis集群下过期key监

这篇文章主要介绍了Redis集群下过期key监听的实现代码
Redis集群增加节点与删除节点的方法详解

Redis集群增加节点与

这篇文章主要给大家介绍了关于Redis集群增加节点与删
Linux 下redis5.0.0安装教程详解

Linux 下redis5.0.0安

这篇文章主要介绍了Linux 下redis5.0.0安装教程,本文图
Redis 实现“附近的人”功能

Redis 实现“附近的人

Redis基于geohash和有序集合提供了地理位置相关功能。