<del id="d4fwx"><form id="d4fwx"></form></del>
      <del id="d4fwx"><form id="d4fwx"></form></del><del id="d4fwx"><form id="d4fwx"></form></del>

            <code id="d4fwx"><abbr id="d4fwx"></abbr></code>
          • 使用Redis實現(xiàn)UA池的方案

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

            創(chuàng)新互聯(lián)公司從2013年成立,先為巍山等服務(wù)建站,巍山等地企業(yè),進行企業(yè)商務(wù)咨詢服務(wù)。為巍山企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

            背景

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

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

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

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

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

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

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

            具體實現(xiàn)方案

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

            UA

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

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

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

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

            •  因為需要導(dǎo)入的 UA 數(shù)據(jù)集合一般不會太大,考慮先把這個集合的數(shù)據(jù)隨機打散,如果使用 Java 開發(fā)可以直接使用 Collections#shuffle() 洗牌算法,當(dāng)然也可以自行實現(xiàn)這個數(shù)據(jù)隨機分布的算法, 這一步對于一些被模擬方會嚴格檢驗 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));
                });
              }
            }

            某次運行結(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è)計難度并不大,需要注意幾個要點:

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

            總結(jié)

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

            網(wǎng)頁題目:使用Redis實現(xiàn)UA池的方案
            網(wǎng)站URL:http://www.jbt999.com/article0/jsdgio.html

            成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、外貿(mào)網(wǎng)站建設(shè)關(guān)鍵詞優(yōu)化、靜態(tài)網(wǎng)站網(wǎng)站收錄、ChatGPT

            廣告

            聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:[email protected]。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

            成都做網(wǎng)站

              <del id="d4fwx"><form id="d4fwx"></form></del>
              <del id="d4fwx"><form id="d4fwx"></form></del><del id="d4fwx"><form id="d4fwx"></form></del>

                    <code id="d4fwx"><abbr id="d4fwx"></abbr></code>
                  • 一级黄色录相片 | 黄色Ⅴ片一 | 国产精品自产拍高潮在线观看 | 污污成人免费网站 | 国内视频精品在线 |