最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Redis實現(xiàn)UA池的方案

 更新時間:2019年11月14日 09:09:43   作者:middleware  
這篇文章主要介紹了使用Redis實現(xiàn)UA池的方案,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下

最近忙于業(yè)務(wù)開發(fā)、交接和游戲,加上碰上了不定時出現(xiàn)的猶豫期和困惑期,荒廢學(xué)業(yè)了一段時間。天冷了,要重新拾起開始下階段的學(xué)習(xí)了。之前接觸到的一些數(shù)據(jù)搜索項目,涉及到請求模擬,基于反爬需要使用隨機(jī)的 User Agent ,于是使用 Redis 實現(xiàn)了一個十分簡易的 UA 池。

背景

最近的一個需求,有模擬請求的邏輯,要求每次請求的請求頭中的 User Agent 要滿足下面幾點(diǎn):

  • 每次獲取的 User Agent 是隨機(jī)的。
  • 每次獲取的 User Agent (短時間內(nèi))不能重復(fù)。
  • 每次獲取的 User Agent 必須帶有主流的操作系統(tǒng)信息(可以是 Uinux 、 Windows 、 IOS 和安卓等等)。

這里三點(diǎn)都可以從 UA 數(shù)據(jù)的來源解決,實際上我們應(yīng)該關(guān)注具體的實現(xiàn)方案。簡單分析一下,流程如下:

在設(shè)計 UA 池的時候,它的數(shù)據(jù)結(jié)構(gòu)和環(huán)形隊列十分類似:

上圖中,假設(shè)不同顏色的 UA 是完全不同的 UA ,它們通過洗牌算法打散放進(jìn)去環(huán)形隊列中,實際上每次取出一個 UA 之后,只需要把游標(biāo) cursor 前進(jìn)或者后退一格即可(甚至可以把游標(biāo)設(shè)置到隊列中的任意元素)。最終的實現(xiàn)就是:需要通過中間件實現(xiàn)分布式隊列(只是隊列,不是消息隊列)。

具體實現(xiàn)方案

毫無疑問需要一個分布式數(shù)據(jù)庫類型的中間件才能存放已經(jīng)準(zhǔn)備好的 UA ,第一印象就感覺 Redis 會比較合適。接下來需要選用 Redis 的數(shù)據(jù)類型,主要考慮幾個方面:

UA

支持這幾個方面的 Redis 數(shù)據(jù)類型就是 List ,不過注意 List 本身不能去重,去重的工作可以用代碼邏輯實現(xiàn)。然后可以想象客戶端獲取 UA 的流程大致如下:

結(jié)合前面的分析,編碼過程有如下幾步:

準(zhǔn)備好需要導(dǎo)入的 UA 數(shù)據(jù),可以從數(shù)據(jù)源讀取,也可以直接文件讀取。

  •  因為需要導(dǎo)入的 UA 數(shù)據(jù)集合一般不會太大,考慮先把這個集合的數(shù)據(jù)隨機(jī)打散,如果使用 Java 開發(fā)可以直接使用 Collections#shuffle() 洗牌算法,當(dāng)然也可以自行實現(xiàn)這個數(shù)據(jù)隨機(jī)分布的算法, 這一步對于一些被模擬方會嚴(yán)格檢驗 UA 合法性的場景是必須的 。
  • 導(dǎo)入 UA 數(shù)據(jù)到 Redis 列表中。
  • 編寫 RPOP + LPUSHLua 腳本,實現(xiàn)分布式循環(huán)隊列。

編碼和測試示例

引入 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

這個腳本十分簡單,但是已經(jīng)實現(xiàn)了循環(huán)隊列的功能。剩下來的測試代碼如下:

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();
    // 模擬構(gòu)建UA池的原始數(shù)據(jù),假設(shè)有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數(shù)據(jù),數(shù)據(jù)量多的時候可以考慮分批寫入防止長時間阻塞Redis服務(wù)
    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));
    });
  }
}

某次運(yùn)行結(jié)果如下:

第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

可見洗牌算法的效果不差,數(shù)據(jù)相對分散。

小結(jié)

其實 UA 池的設(shè)計難度并不大,需要注意幾個要點(diǎn):

  • 一般主流的移動設(shè)備或者桌面設(shè)備的系統(tǒng)版本不會太多,所以來源 UA 數(shù)據(jù)不會太多,最簡單的實現(xiàn)可以使用文件存放,一次讀取直接寫入 Redis 中。
  • 注意需要隨機(jī)打散 UA 數(shù)據(jù),避免同一個設(shè)備系統(tǒng)類型的 UA 數(shù)據(jù)過于密集,這樣可以避免觸發(fā)模擬某些請求時候的風(fēng)控規(guī)則。
  • 需要熟悉 Lua 的語法,畢竟 Redis 的原子指令一定離不開 Lua 腳本。

總結(jié)

以上所述是小編給大家介紹的使用Redis實現(xiàn)UA池的方案,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!

相關(guān)文章

  • Redis 搭建哨兵集群的操作步驟

    Redis 搭建哨兵集群的操作步驟

    在 主從架構(gòu)Redis搭建主從集群 中,一個slave節(jié)點(diǎn)掛了無影響,但是master節(jié)點(diǎn)掛了,就無法進(jìn)行寫操作了,影響高可用,Redis 提供了哨兵(Sentinel)機(jī)制來實現(xiàn)主從集群的自動故障恢復(fù),本文給大家介紹了Redis 搭建哨兵集群的操作步驟,需要的朋友可以參考下
    2023-08-08
  • Redis慢日志的實現(xiàn)示例

    Redis慢日志的實現(xiàn)示例

    慢查詢?nèi)罩臼荝edis提供的一個用于觀察系統(tǒng)性能的功能,本文主要介紹了Redis慢日志的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-04-04
  • Redis02 使用Redis數(shù)據(jù)庫(String類型)全面解析

    Redis02 使用Redis數(shù)據(jù)庫(String類型)全面解析

    這篇文章主要介紹了Redis02 使用Redis數(shù)據(jù)庫(String類型)全面解析的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-07-07
  • Redis實現(xiàn)接口防抖的示例代碼

    Redis實現(xiàn)接口防抖的示例代碼

    本文介紹了一種通過AOP、自定義注解和Redis實現(xiàn)的接口防抖技術(shù),這種方法能有效避免因網(wǎng)絡(luò)波動等原因短時間內(nèi)發(fā)送多個請求導(dǎo)致的數(shù)據(jù)重復(fù)添加問題,感興趣的可以了解一下
    2024-10-10
  • 基于Redis?zSet實現(xiàn)滑動窗口對短信進(jìn)行防刷限流的問題

    基于Redis?zSet實現(xiàn)滑動窗口對短信進(jìn)行防刷限流的問題

    這篇文章主要介紹了基于Redis?zSet實現(xiàn)滑動窗口對短信進(jìn)行防刷限流,主要針對目前線上短信被腳本惡意盜刷的情況,用Redis實現(xiàn)滑動窗口限流,本文通過實例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2022-02-02
  • 深入了解Redis的看門狗機(jī)制

    深入了解Redis的看門狗機(jī)制

    Redis鎖的延期機(jī)制,通常被稱為看門狗機(jī)制,本文就拉介紹一下Redis的看門狗機(jī)制,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • 如何利用Redis?List實現(xiàn)Java數(shù)據(jù)庫分頁快速查詢

    如何利用Redis?List實現(xiàn)Java數(shù)據(jù)庫分頁快速查詢

    這篇文章主要給大家介紹了關(guān)于如何利用Redis?List實現(xiàn)Java數(shù)據(jù)庫分頁快速查詢的相關(guān)資料,Redis是一個高效的內(nèi)存數(shù)據(jù)庫,它支持包括String、List、Set、SortedSet和Hash等數(shù)據(jù)類型的存儲,需要的朋友可以參考下
    2024-02-02
  • Redis源碼解析:集群手動故障轉(zhuǎn)移、從節(jié)點(diǎn)遷移詳解

    Redis源碼解析:集群手動故障轉(zhuǎn)移、從節(jié)點(diǎn)遷移詳解

    這篇文章主要介紹了Redis源碼解析:集群手動故障轉(zhuǎn)移、從節(jié)點(diǎn)遷移的相關(guān)內(nèi)容,涉及通過集群定時器函數(shù)clusterCron實現(xiàn)從節(jié)點(diǎn)遷移等知識,具有一定參考價值,需要的朋友可以了解。
    2017-10-10
  • Redis?抽獎大轉(zhuǎn)盤的實戰(zhàn)示例

    Redis?抽獎大轉(zhuǎn)盤的實戰(zhàn)示例

    本文主要介紹了Redis?抽獎大轉(zhuǎn)盤的實戰(zhàn)示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Win10配置redis服務(wù)實現(xiàn)過程詳解

    Win10配置redis服務(wù)實現(xiàn)過程詳解

    這篇文章主要介紹了Win10配置redis服務(wù)實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07

最新評論

太白县| 新建县| 沙田区| 台江县| 永修县| 宁夏| 贵溪市| 皮山县| 太湖县| 博白县| 盈江县| 九龙城区| 房产| 大冶市| 江津市| 陇西县| 微博| 民和| 晋中市| 蒲城县| 扶风县| 武陟县| 蛟河市| 通州市| 女性| 靖边县| 五指山市| 梁平县| 新绛县| 东方市| 淮安市| 株洲县| 隆化县| 绥江县| 新巴尔虎左旗| 洪泽县| 浦北县| 漳州市| 留坝县| 康保县| 龙南县|