iT邦幫忙

2021 iThome 鐵人賽

DAY 10
0
自我挑戰組

資料分析及AI深度學習-簡單基礎實作系列 第 10

DAY10:驗證碼辨識(三)

今天要用昨天訓練好的模型來試試看能否順利從我們的目標網站取得資訊!

我們要先用selenium來處理網站的下拉式選單。

第一個是發證日期的年月日,我們可以觀察到年的部分要抓取的話,例如109年就直接輸入109就可以抓取到了。

月和日的部分也是。


接下來發證地點這裡我們就要先給它編號了。
例如北縣,我們就必須給他10001的值。

place_dict = {
    "10001":"北縣","10002":"宜縣",
    "10003":"桃縣","10004":"竹縣",
    "10005":"苗縣","10006":"中縣",
    "10007":"彰縣","10008":"投縣",
    "10009":"雲縣","10010":"嘉縣",
    "10011":"南縣","10012":"高縣",
    "10013":"屏縣","10014":"東縣",
    "10015":"花縣","10016":"澎縣",
    "10017":"基市","10018":"竹市",
    "10020":"嘉市","09007":"連江",
    "09020":"金門","63000":"北市",
    "64000":"高市","65000":"新北市",
    "66000":"中市","67000":"南市",
    "68000":"桃市"
}

而領補換類別也是,我們需要給他編號才能抓取的到。

reason_dict = {
    "1":"初發",
    "2":"補發",
    "3":"換發",
}

# 我們在輸入資料的時候,還是會打北縣,換發等等,所以這裡我把key和value值對調一下,才能成功輸入對應的編號
place_key = {v : k for k ,v in place_dict.items()}
reason_key = {v : k for k ,v in reason_dict.items()}

我們一樣在背景執行。

chrome_options = Options()
chrome_options.add_argument("--headless")
driver = webdriver.Chrome(options=chrome_options)
driver.get("https://www.ris.gov.tw/apply-idCard/app/idcard/IDCardReissue/main")

這個程式用來處理我們的身分證資訊。

def person_information(ID,year,month,date,place,reason):
    # 輸入身分證字號
    userid = driver.find_element_by_xpath("//input[@id='idnum94']").clear()
    userid = driver.find_element_by_xpath("//input[@id='idnum94']")
    userid.send_keys(ID)

    # 選年
    select = Select(driver.find_element_by_name("applyTWY"))
    select.select_by_value(year)

    # 選月
    select = Select(driver.find_element_by_name("applyMM"))
    select.select_by_value(month)

    # 選日
    select = Select(driver.find_element_by_name("applyDD"))
    select.select_by_value(date)

    # 選發證地點
    select = Select(driver.find_element_by_name("siteId"))
    select.select_by_value(place_key[place])

    # 選領補換發類別
    select = Select(driver.find_element_by_name("applyReason"))
    select.select_by_value(reason_key[reason])

填選完之後我們要輸入驗證碼,所以我們必須先抓到當下頁面的驗證碼圖片。作法一樣,我們先全屏截圖之後,擷取圖片的位置,不用落地,直接取得。

def captcha_pic(filepath_input):
    scroll_width = driver.execute_script('return document.body.parentNode.scrollWidth')
    scroll_height = driver.execute_script('return document.body.parentNode.scrollHeight')
    driver.set_window_size(scroll_width, scroll_height)

    driver.save_screenshot(filepath_input)
    # 網頁中圖片驗證碼的位置
    element = driver.find_element_by_xpath('//*[@id="captchaImage_captcha-refresh"]')
    left = element.location['x']
    right = element.location['x'] + element.size['width']
    top = element.location['y']
    bottom = element.location['y'] + element.size['height']
    img = Image.open(filepath_input)
    img = img.crop((left, top, right, bottom))
    img = img.convert("RGB")

    return img

我們還會需要讀取模型。

def model_for_captcha(model_path):
    model = models.densenet201(num_classes=180)
    model.load_state_dict(torch.load(model_path))
    return model

再來就是將剛剛抓取的圖片丟入模型預測是甚麼字啦~~

def captcha_answer(img,model):

    transforms = Compose([ToTensor()])
    img = transforms(img)
    model.eval()
    img = img.view(1, 3, 100, 240)

    output = model(img)

    output = output.view(-1, 36)

    output = nn.functional.softmax(output, dim=1)

    output = torch.argmax(output, dim=1)

    output = output.view(-1, 5)[0]

    pred = ''.join([alphabet[i] for i in output.cpu().numpy()])

    return pred , output

最後我們將全部整合在一起,我們會用到while迴圈,因為萬一預測的驗證碼是錯的,我們必須重新自動再跑一次,直到正確為止。

# 執行while迴圈,直到成功填寫正確驗證碼
def work_all(ID,year,month,date,place,reason,filepath_input,model_path,filepath_output):
    while True:

        person_information(ID,year,month,date,place,reason)
        img = captcha_pic(filepath_input)
        model = model_for_captcha(model_path)
        pred , output = captcha_answer(img,model)
        print("==========================================")
        print('pred: ' + ''.join([alphabet[i] for i in output.cpu().numpy()]))

        # 清除驗證碼空格,並輸入驗證碼
        captcha = driver.find_element_by_xpath("//input[@id='captchaInput_captcha-refresh']").clear()
        captcha = driver.find_element_by_xpath("//input[@id='captchaInput_captcha-refresh']")
        captcha.send_keys(pred)


        # 點選送出
        submit = driver.find_element_by_xpath("//button[@class = 'btn btn-primary query']")
        submit.click()
        time.sleep(5)
        try:
            # 驗證碼輸入錯誤
            driver.find_element_by_xpath("//div[@class='error-message']")
            print("驗證碼輸入錯誤,重新填寫驗證碼")
            print("==========================================")
            continue


        except:
            user_info = {}
            userID = driver.find_element_by_xpath("//*[@id='resultBlock']/div[2]/div[2]/div[1]/div[2]/table/tbody/tr[1]/td/strong").text
            pub_date = driver.find_element_by_xpath("//*[@id='resultBlock']/div[2]/div[2]/div[1]/div[2]/table/tbody/tr[2]/td/strong").text
            pub_place = driver.find_element_by_xpath("//*[@id='resultBlock']/div[2]/div[2]/div[1]/div[2]/table/tbody/tr[3]/td/strong").text
            pub_reason = driver.find_element_by_xpath("//*[@id='resultBlock']/div[2]/div[2]/div[1]/div[2]/table/tbody/tr[4]/td/strong").text
            final_answer = driver.find_element_by_xpath("//*[@id='resultBlock']/div[2]/div[2]/div[1]/div[2]/div[2]/div").text
            # 送出的截圖
            scroll_width = driver.execute_script('return document.body.parentNode.scrollWidth')
            scroll_height = driver.execute_script('return document.body.parentNode.scrollHeight')
            driver.set_window_size(scroll_width, scroll_height)
            # driver.save_screenshot(filepath_output)
            final_base64 = driver.get_screenshot_as_base64()
            user_info["身分證字號"] = userID
            user_info["發證日期"] = pub_date
            user_info["發證地點"] = pub_place
            user_info["領補換類別"] = pub_reason
            user_info["是否為最新資料"] = final_answer
            user_info["最終截圖base64碼"] = final_base64

            print("驗證碼輸入正確,已儲存圖片")
            print("==========================================")
            break
    return user_info

給定各個參數之後,執行結果發現準確度其實滿好的,試了大概20次,全部都一次就得到我們要得結果了~

# 這些參數就輸入你們的身分證資訊,加上自己定義你們要存的位置和你們的模型
ID = 
year = 
month = 
date = 
place = 
reason = 
filepath_input = 
model_path = 
filepath_output = 


user_info = work_all(ID,year,month,date,place,reason,filepath_input,model_path,filepath_output)
pprint.pprint(user_info)

這是我們填完資訊之後,尚未填入驗證碼的畫面。

而我們的模型預測也正確。

最後也成功得到我們要的資訊啦~


  • 今日小結

驗證碼辨識可以說是在學圖像辨識時,最簡單也最好蒐集圖片的一個練習。剛好公司有用到,就來分享給大家,如有寫的不好的地方,歡迎鞭打我XDDD。


上一篇
DAY9: 驗證碼辨識(二)
下一篇
DAY11:機器學習模型_筆記分享
系列文
資料分析及AI深度學習-簡單基礎實作30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言