天天看點

滑動極限驗證碼破解1,打開浏覽器,并輸入查詢内容2,執行js,生成帶缺口和不帶缺口的驗證碼圖檔3,拿到滑動驗證碼需要移動的距離4,生成滑動軌迹5,拖動滑塊到缺口處6,傳回html

滑動驗證最新版破解

  • 1,打開浏覽器,并輸入查詢内容
  • 2,執行js,生成帶缺口和不帶缺口的驗證碼圖檔
  • 3,拿到滑動驗證碼需要移動的距離
  • 4,生成滑動軌迹
  • 5,拖動滑塊到缺口處
  • 6,傳回html
    • 結束語:

1,打開浏覽器,并輸入查詢内容

class CrackGeetest():

    def __init__(self, url, proxy, word, searchId, bowtonID):

        self.url = url
        self.word = word  #  搜尋關鍵詞
        self.proxy = proxy  # 加上代理IP
        chrome_options = Options()
        chrome_options.add_argument('--headless')
        chrome_options.add_argument('--no-sandbox')
        chrome_options.add_argument('--proxy-server=%s' % self.proxy)
        # self.browser = webdriver.Chrome(chrome_options=chrome_options, executable_path='D:\\chromedriver')
        self.browser = webdriver.Chrome(chrome_options=chrome_options)
        self.wait = WebDriverWait(self.browser, 80)
        self.browser.set_page_load_timeout(40)
        self.searchId = searchId # 搜尋框的ID,用于定位
        self.bowtonID = bowtonID # 點選按鈕的ID,用于定位
        self.threshold = 60  # 驗證碼圖檔對比中RGB的內插補點,可調
        self.left = 50  # 驗證碼圖檔的對比中的起始坐标,即拖動子產品的右邊線位置
        self.deviation = 7  # 誤內插補點,這個值是多次測試得出的經驗值
        self.page_count = []

    def open(self):
        """
        打開浏覽器,并輸入查詢内容
        """
        self.browser.maximize_window()
        self.browser.get(self.url)
        if '無法通路此網站' in self.browser.page_source or '未連接配接到網際網路' in self.browser.page_source or '該網頁無法正常運作' in self.browser.page_source:  # 判斷是否正常打開網頁
            self.browser.quit()
        keyword = self.wait.until(EC.presence_of_element_located((By.ID, self.searchId)))
        bowton = self.wait.until(EC.presence_of_element_located((By.ID, self.bowtonID)))
        try:
            keyword.send_keys(self.word)  # 發送關鍵詞
        except:
            keyword.send_keys(self.word)
        try:
            bowton.send_keys(Keys.ENTER) # 此處有坑!!!可能打開的視窗大小不同,導緻網頁上的元素重疊在一起,不能進行點選,是以直接進行Enter鍵進入
        except:
            bowton.send_keys(Keys.ENTER)
           

2,執行js,生成帶缺口和不帶缺口的驗證碼圖檔

def get_image(self):
        """
        擷取驗證碼圖檔
        :return: 驗證碼圖檔對象
        """
        times = random.uniform(3, 5)
        times = round(times, 2)
        time.sleep(times)
        bg_js = 'return document.getElementsByClassName("geetest_canvas_bg geetest_absolute")[0].toDataURL("image/png");'  # 帶缺口驗證碼圖檔js
        fullbg_js = 'return document.getElementsByClassName("geetest_canvas_fullbg geetest_fade geetest_absolute")[0].toDataURL("image/png");'  # 完整驗證碼圖檔js
        #  執行 JS 代碼并拿到圖檔 base64 資料
        bg_info = self.browser.execute_script(bg_js)  # 執行js檔案得到帶圖檔資訊的圖檔資料
        bg_base64 = bg_info.split(',')[1]  # 拿到base64編碼的圖檔資訊
        bg_bytes = base64.b64decode(bg_base64)  # 轉為bytes類型
        bg_image = Image.open(BytesIO(bg_bytes)) # image讀取圖檔資訊
        fullbg_info = self.browser.execute_script(fullbg_js)  # 執行js檔案得到帶圖檔資訊的圖檔資料
        fullbg_base64 = fullbg_info.split(',')[1]  # 拿到base64編碼的圖檔資訊
        fullbg_bytes = base64.b64decode(fullbg_base64)  # 轉為bytes類型
        fullbg_image = Image.open(BytesIO(fullbg_bytes)) # image讀取圖檔資訊
        return bg_image,fullbg_image
           

3,拿到滑動驗證碼需要移動的距離

def get_distance(self,image1,image2):
        """
        拿到滑動驗證碼需要移動的距離
        :param image1: 沒有缺口的圖檔對象
        :param image2: 帶缺口的圖檔對象
        :return: 需要移動的距離
        """
        i = 0
        for i in range(self.left, image1.size[0]):
            for j in range(image1.size[1]):
                rgb1 = image1.load()[i, j]
                rgb2 = image2.load()[i, j]
                res1 = abs(rgb1[0] - rgb2[0])
                res2 = abs(rgb1[1] - rgb2[1])
                res3 = abs(rgb1[2] - rgb2[2])
                if not (res1 < self.threshold and res2 < self.threshold and res3 < self.threshold):
                    distance = i -self.deviation
                    return distance
        logging.debug('未識别出驗證碼中的不同位置,或圖檔定位出現異常')
        return i  # 如果沒有識别出不同位置,則象征性的滑動,以重新整理下一張驗證碼
           

4,生成滑動軌迹

這個軌迹是研究蠻久才出來的,因為極限驗證會通過使用者滑動軌迹的大資料,經過機器學習,來判定軌迹是機器滑動和人為滑動,之前網上先加速運動,再減速,什麼區間震蕩軌迹,剛開始還行,後面成功率就會越來越低,我的這個滑動軌迹至今還蠻穩定

def get_track(self,distance):
        """
        :param distance:
        :return: 滑動軌迹
        """
        track = []
        current = 0
        mid = int(distance * round(random.uniform(0.6, 0.7), 2))
        jiansu = distance - mid  # 需要減速的距離
        # 計算間隔
        t = 0.2
        # 初速度
        v = 0
        while current < distance:
            if current < mid:
                # 設定加速度動态變化
                # Chrome 浏覽器的加速度
                ap = random.uniform(3, 5)
                times = round(ap, 2)
                a = times
                # 初速度v0
                v0 = v
                v = v0 + a * t
                move = v0 * t + 1 / 2 * a * t * t + 0.5
                # 目前位移
                current += move
                # 加入軌迹
                track.append(round(move))
            else:
                a = -1 * (v * v) / (2 * jiansu)  #減速的速度
                v0 = v
                v = v0 + a * t
                if distance > 120:
                    move = v0 * t + 1 / 2 * a * t * t  - 1.5  # 1.5,1,0.5都是噪聲,因為剛開始的減速距離挺大,為了盡量是最後的軌迹能夠到1,就加了一些噪聲
                elif distance <= 120 and distance >= 60:
                    move = v0 * t + 1 / 2 * a * t * t - 1
                else:
                    move = v0 * t + 1 / 2 * a * t * t - 0.5
                if move < 1:   # 減速運動如果後面move會越來越小,如果不讓小于1的固定為1的話,有時候會進死循環
                    move = 1
                current += move
                track.append(round(move))
        return track
           

5,拖動滑塊到缺口處

def move_to_gap(self, slider, track):
        """
        拖動滑塊到缺口處
        :param slider: 滑塊
        :param track: 軌迹
        :return:
        """
        ActionChains(self.browser).click_and_hold(slider).perform()
        for x in track:
            ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()
        time.sleep(0.5)
        ActionChains(self.browser).release().perform()
           

6,傳回html

def check_html(self, html):   # 檢測一些html,如果成功,就可以傳回html,不成功,就可以重試
        if 'geetest_success_radar_tip_content' in html:
            return True
        else:
            return False
           

結束語:

第一次寫部落格,學藝不精,往各位同仁不要見笑,希望能和各位多多交流,學無止境!!!上面隻寫了主要步驟,另外還有翻頁,重試等沒展示。在此申明,此部落格隻用于學習交流,不得進行非法用途!