GlidedSky爬虫-验证码1
題目描述
 題目鏈接:http://glidedsky.com/level/crawler-captcha-1
題目分析
??本題在每個數據頁中都加了一個滑動拼圖驗證碼,要想獲取頁面的數據,首先必須得完成拼圖。滑動拼圖驗證碼對于人類來說難度不大,但如果想要讓程序也能通過驗證,那么就必須得模擬人類的行為。識別驗證碼需要完成如下三步。
 ??(1)模擬點擊拖動按鈕
 ??(2)識別滑動缺口的位置
 ??(3)模擬拖動滑塊
 ??第(1)步操作非常簡單,我們可以使用selenium很輕松的模擬點擊某個元素的操作。第(3)步也很簡單,同樣是使用selenium套件,可以把一個元素從某個位置拖動指定的位移,以到達另一個位置。因此,整個驗證過程最困難的就是第(2)步,如何找到滑動缺口的位置。
 ??要完成第二步操作,需要用到圖像的相關處理方法。在python中可以使用opencv庫進行圖像處理,使用此庫進行缺口識別的代碼網上也有很多,本文中使用的代碼也是參考的網絡資源,對于我們只是想爬取數據而言,沒有必要對圖像處理做太深入的研究,只要是會用現有的代碼即可。
 ??現在已經解決了處理驗證碼的關鍵問題,但是在編程時,有一些細節仍然需要注意。第一點是驗證碼是在一個iframe里面,因此想要進行驗證碼的識別,必須先進入到相應的iframe里面,同理,當識別完成之后,也要再回到含有數據的iframe中。第二點是網頁中顯示的驗證碼圖片和它的實際大小不一樣,驗證碼圖片的實際寬度是680px,而網頁中顯示的寬度是341px,因此用驗證碼圖片找到缺口的位置之后,還需要按照比例進行換算,這樣得到的才是網頁中驗證碼的缺口位置。第三點是要找出滑塊的起始位置,但并不是簡單的通過left屬性的值來找,因為滑塊的大小和我們看到的大小不同,實際上要比我們看到的大。本文提供兩種找滑塊起始位置的方法,一是通過截圖工具查看滑塊左邊緣和驗證碼圖片左邊緣的距離,二是假設缺口的位置是x,滑塊初始的left屬性值是left0,滑塊拼合到缺口上的left屬性值是left1,那么滑塊的起始位置可以通過表達式x-(left1-left0)計算。第四點是題目中用的騰訊驗證碼比較弱,不會檢測滑動軌跡,一次拖動完成和分段拖動的效果是相同的。最后再提醒一點,這道題目的運行時間可能會比較長,誰也不能保證運行過程中不出意外,所以建議將獲取到的每個數據都保存到文件中,這樣萬一發生了意外導致程序中斷,下次可以直接從發生異常的頁面開始爬取。
源代碼
import cv2 import time from time import sleep from selenium import webdriver from selenium.webdriver import ActionChains from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions from selenium.webdriver.chrome.options import Options from urllib.request import urlretrieve from bs4 import BeautifulSoup from os.path import existsdef login():option = Options()option.add_argument('--headless')driver = webdriver.Chrome(options=option)driver.set_page_load_timeout(5)try:driver.get('http://glidedsky.com/login')except BaseException:passemail = driver.find_element_by_id('email')email.send_keys('') # 輸入你的賬號password = driver.find_element_by_id('password')password.send_keys('') # 輸入你的密碼login_btn = driver.find_element_by_class_name('btn-primary')driver.set_page_load_timeout(0.5)try:login_btn.click()except BaseException:passreturn driverdef parse(html, k):soup = BeautifulSoup(html, 'lxml')numbers = soup.select('.col-md-1')f = open('log.txt', 'at')f.write(str(k) + '\t')page_sum = 0for number in numbers:number = number.string.strip()f.write(number + '\t')page_sum += int(number)f.write('\n')f.close()return page_sumdef get_pos(bg_img_path, web_img_width):"""獲取驗證碼圖片中缺口的位置:param bg_img_path: 驗證碼圖片的路徑:param web_img_width: 網頁中顯示的驗證碼圖片的寬度:return: 缺口在網頁中顯示的驗證碼圖片中的位置"""image = cv2.imread(bg_img_path)blurred = cv2.GaussianBlur(image, (5, 5), 0)canny = cv2.Canny(blurred, 200, 400)contours, hierarchy = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)for i, contour in enumerate(contours):M = cv2.moments(contour)if M['m00'] == 0:cx = cy = 0else:cx, cy = M['m10'] / M['m00'], M['m01'] / M['m00']if 6000 < cv2.contourArea(contour) < 8000 and 370 < cv2.arcLength(contour, True) < 390:if cx < 400:continuex, y, w, h = cv2.boundingRect(contour) # 外接矩形# cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)# cv2.imshow('image', image)# cv2.waitKey(0)return x * (web_img_width / image.shape[1])return 180 * (web_img_width / image.shape[1])def crawler():driver = login()ans = 0if not exists('log.txt'):with open('log.txt', mode='wt'):passstart_page = 1else:with open('log.txt') as f:start_page = len(f.readlines()) + 1for k in range(start_page, 1001):driver.set_page_load_timeout(5)url = 'http://glidedsky.com/level/web/crawler-captcha-1?page=' + str(k)try:driver.get(url)except BaseException:passwhile True:# 用while True循環來等待頁面加載驗證碼的iframetry:driver.switch_to.frame('tcaptcha_iframe')except BaseException:sleep(1)else:breakwhile True:# 當一次滑動沒有通過時,則進行下一次嘗試wait = WebDriverWait(driver, timeout=10)bk_block = wait.until(expected_conditions.presence_of_element_located((By.XPATH, '//div/img[@id="slideBg"]')))web_image_width = bk_block.size['width']while True:bg_img_url = bk_block.get_attribute('src')if not bg_img_url:print('等待圖片加載中 ... ')time.sleep(2)else:breakbg_img_path = 'bg_img.png'urlretrieve(bg_img_url, bg_img_path)position_x = get_pos(bg_img_path, web_image_width) # 計算缺口位置move_dist = position_x - 39 # 缺口位置減去滑塊起始位置,即為滑塊應移動的距離drag_thumb = wait.until(expected_conditions.presence_of_element_located((By.XPATH, '//div[@class="tc-drag-thumb"]')))action = ActionChains(driver)action.click_and_hold(on_element=drag_thumb).perform()time.sleep(0.2)action.move_by_offset(move_dist, 0).perform()time.sleep(0.5)action.release(on_element=drag_thumb).perform()sleep(2)try:reload = driver.find_element_by_id('reload')except BaseException:driver.switch_to.parent_frame()ans += parse(driver.page_source, k)print(k)breakelse:# 驗證失敗,刷新一下驗證碼,重新驗證reload.click()sleep(1)print(ans)if __name__ == '__main__':crawler()總結
以上是生活随笔為你收集整理的GlidedSky爬虫-验证码1的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: COCA的使用方法
- 下一篇: nacos注册服务的时候报错server
