天天看點

Python爬蟲入門教程 58-100 python爬蟲進階技術之驗證碼篇4-極驗證識别技術之一

驗證碼類型

今天要搞定的驗證碼屬于現在使用非常多的驗證碼的一種類型---極驗證滑動驗證碼,關于這個驗證碼的詳細說明查閱他的官網,

https://www.geetest.com/

把驗證碼做到這個地步,必須點贊了。

Python爬蟲入門教程 58-100 python爬蟲進階技術之驗證碼篇4-極驗證識别技術之一

官網最新效果

官方DEMO最新的效果如下,按照驗證碼的更新頻率,基本部落格看完,驗證碼也更新了,不過套路依舊是相同的,反爬隻能增加爬蟲編寫的成本,并不能完全杜絕爬蟲。

Python爬蟲入門教程 58-100 python爬蟲進階技術之驗證碼篇4-極驗證識别技術之一

這類驗證碼,正常解決辦法,模拟人為操作,圖像比對,查找缺口,移動覆寫缺口。

找個用極驗證的網站

今天看新聞,随意找了一下,虎嗅使用的是直接拖拽,沒有用最新的點選+拖拽方式,可以直接看一下如何操作。

Python爬蟲入門教程 58-100 python爬蟲進階技術之驗證碼篇4-極驗證識别技術之一

這種驗證碼除了打碼平台以外,直接selenium搞起

拼接驗證碼圖檔

當你在谷歌浏覽器使用F12進行查找元素的時候,随意的去缺口圖檔上面點選一下,在控制台DOM結構中出現如下代碼,有前端經驗的童鞋知道,這個使用的是背景局部顯示技術,是可以通過這個拼接成一個。

Python爬蟲入門教程 58-100 python爬蟲進階技術之驗證碼篇4-極驗證識别技術之一

注意兩個地方:

  1. https://static.geetest.com/pictures/gt/8bc4cb7fa/8bc4cb7fa.webp 圖檔位址
  2. background-position:後面的坐标
    Python爬蟲入門教程 58-100 python爬蟲進階技術之驗證碼篇4-極驗證識别技術之一

查閱圖檔之後,發現是一張碎掉的圖檔,你要做的第一步是将這個圖檔進行還原,我們通過selenium進行實作。這個地方需要先備注一下圖檔的尺寸,後面用size =

312x116

Python爬蟲入門教程 58-100 python爬蟲進階技術之驗證碼篇4-極驗證識别技術之一
Python爬蟲入門教程 58-100 python爬蟲進階技術之驗證碼篇4-極驗證識别技術之一

編寫自動化代碼

使用selenium執行的操作,模拟人的點選行為即可

最初,我們導入一些selenium的基本子產品與方法

import time
import re

from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
           

基本子產品的作用如下

webdriver 核心驅動

selenium.common.exceptions 異常類 TimeoutException 逾時異常

selenium.webdriver.common.by 按照什麼方式進行元素的查找 例如 By.ID,By.ClassName,By.XPATH

selenium.webdriver.support.wait 等待頁面加載某些元素

from selenium.webdriver.support import expected_conditions 場景判斷用的,一般和上面的等待加載元素一起使用

selenium.webdriver.common.action_chains 滑鼠執行的動作鍊

主方法測試入口

if __name__ == '__main__':
    h = Geek_Huxiu()
    h.run()           

構造方法,實作對部分參數的初始化操作

def __init__(self):
        self.driver = webdriver.Chrome()  
        self.driver.set_window_size(1366,768)           

webdriver.Chrome() 啟動谷歌浏覽器,這個地方需要你提前配置好chromedriver.exe

set_window_size(1366,768) 初始化浏覽器大小

核心run方法

def run(self):
        self.driver.get("https://www.huxiu.com/")  # 打開浏覽器
    
        WebDriverWait(self.driver,10).until(EC.element_to_be_clickable((By.XPATH,'//*[@class="js-register"]')))

        reg_element = self.driver.find_element_by_xpath('//*[@class="js-register"]')
        reg_element.click()

        WebDriverWait(self.driver,10).until(EC.element_to_be_clickable((By.XPATH,'//div[@class="gt_slider_knob gt_show"]')))

        # 模拟拖動
        self.analog_drag()           

WebDriverWait 方法

說明

driver: 傳入WebDriver執行個體,即我們上例中的driver
timeout: 逾時時間,等待的最長時間(同時要考慮隐性等待時間)
poll_frequency: 調用until或until_not中的方法的間隔時間,預設是0.5秒
ignored_exceptions: 忽略的異常,如果在調用until或until_not的過程中抛出這個元組中的異常, 則不中斷代碼,繼續等待;
如果抛出的是這個元組外的異常,則中斷代碼,抛出異常。預設隻有NoSuchElementException。
           

基本使用方法

WebDriverWait(driver, 逾時時長, 調用頻率, 忽略異常).until(可執行方法, 逾時時傳回的資訊)
           

模拟拖動方法

def analog_drag(self):
        # 滑鼠移動到拖動按鈕,顯示出拖動圖檔
        element = self.driver.find_element_by_xpath('//div[@class="gt_slider_knob gt_show"]')
        ActionChains(self.driver).move_to_element(element).perform()
        time.sleep(3)


        # 重新整理一下極驗證圖檔
        element = self.driver.find_element_by_xpath('//a[@class="gt_refresh_button"]')
        element.click()
        time.sleep(1)

        # 擷取圖檔位址和位置坐标清單
        cut_image_url,cut_location = self.get_image_url('//div[@class="gt_cut_bg_slice"]')

        print(cut_image_url)
        print(cut_location)
           

行為鍊

ActionChains(self.driver).move_to_element(element).perform()

模拟人移動滑鼠到指定DOM元素

圖檔處理方法

def get_image_url(self,xpath):
        link = re.compile('background-image: url\("(.*?)"\); background-position: (.*?)px (.*?)px;')
        elements = self.driver.find_elements_by_xpath(xpath)
        image_url = None

        location = list()

        for element in elements:
            style = element.get_attribute('style')
            groups = link.search(style)

            url = groups[1]
            x_pos = groups[2]
            y_pos = groups[3]
            location.append((int(x_pos), int(y_pos)))
            if not image_url:
                image_url = url
        return image_url, location
           

使用正規表達式進行比對的時候,需要将所有的DIV比對出來 ,采用

find_elements_by_xpath

方法,尤其注意

elements

WebElement 具備一些常用的方法和屬性

  • size:傳回元素尺寸
  • text :傳回元素文本
  • get_attribute(name):獲得屬性值
  • is_dispalyed() :該元素是否使用者可見

初步運作結果

Python爬蟲入門教程 58-100 python爬蟲進階技術之驗證碼篇4-極驗證識别技術之一

拼接圖

看下圖,注意一些基本元素,拼接的圖檔由N個小矩形構成,分為上下兩個部分,小矩形的寬度和高度為10x58

核心由上下兩部分構成,每部分都是26個小矩形

Python爬蟲入門教程 58-100 python爬蟲進階技術之驗證碼篇4-極驗證識别技術之一

因為,整體寬度為2610 = 260px ,整體高度為582=116px

但是,還記得部落格開始的時候,你記錄的那個寬度和高度麼?

312x116

高度一緻,但是寬度出現偏差

312-260 = 52px

52個像素去除以26個矩形,發現每個矩形差2px,這兩個像素也就是下面我們拼接圖檔的重點了

def splicing_image(self,image_url,location):
        res = requests.get(image_url)
        file = BytesIO(res.content)
        img = Image.open(file)
        image_upper = []
        image_down = []
        for pos in location:
            if pos[1] == 0:
                # y值為0的坐标  屬于圖檔上半部分,高度58
                image_upper.append(img.crop((abs(pos[0]), 0, abs(pos[0]) + 10, 58)))
            else:
                # y值為58的坐标 屬于圖檔上半部分,高度58
                image_down.append(img.crop((abs(pos[0]), 58, abs(pos[0]) + 10, img.height)))
        # 畫布的x軸偏移量
        x_offset = 0 
        # 建立一張畫布
        new_img = Image.new("RGB", (260, img.height))
        for img in image_upper:
            new_img.paste(img, (x_offset, 58))
            x_offset += img.width

        x_offset = 0
        for img in image_down:
            new_img.paste(img, (x_offset, 0))
            x_offset += img.width

        return new_img           
  • requests.get(image_url) 下載下傳圖檔到本地
  • BytesIO(res.content) 将位元組轉換成二進制檔案流
  • Image.open(file) 擷取圖檔
  • img.crop 裁切圖檔 left, upper, right, lower
  • Image.new("RGB", (260, img.height)) 建立一個空白的圖檔,将圖檔序列中的元素,依次的拼接到裡面

最終實作效果

Python爬蟲入門教程 58-100 python爬蟲進階技術之驗證碼篇4-極驗證識别技術之一

圖檔存儲到本地

# 将圖檔存儲到本地
        cut_image.save("cut.jpg")
        full_image.save("full.jpg")           

好了,今天部落格就先把圖檔處理到位,明天着手拼接部分。

繼續閱讀