Python——使用代碼平台進行識別驗證碼


打碼平台介紹

一般使用超級鷹或打碼兔的打碼平台。

超級鷹介紹

打開http://www.chaojiying.com/contact.html注冊用戶,生成軟件ID

下載python的demo文件

查看打碼類型

 

使用方法

from chaojiying import Chaojiying

CHAOJIYING_USERNAME = 'xxxxxx' # 賬號
CHAOJIYING_PASSWORD = '123456' # 密碼
CHAOJIYING_SOFT_ID = 894611 # 生成的唯一key
CHAOJIYING_KIND = 9004 # 題型

cjy = Chaojiying(CHAOJIYING_USERNAME, CHAOJIYING_PASSWORD, CHAOJIYING_SOFT_ID) # 創建實例
result = cjy.post_pic(bytes_array.getvalue(), CHAOJIYING_KIND) # 上傳圖片

邏輯實現

1.獲取需要識別的圖片

在獲取需要的識別的圖片時,一般需要講圖片以及文字提示。通過selenium的截圖方法,獲取到所需的信息。

 

self.browser.save_screenshot('aa.png') # 先把整個屏幕截圖
element = self.browser.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[2]/div[3]/div/div[2]/div[3]/div/div') # 獲取圖片所在的div

left = element.location['x']
top = element.location['y'] - 100
right = element.location['x'] + element.size['width']
bottom = element.location['y'] + element.size['height']

im = Image.open('aa.png')
captcha = im.crop((left, top, right, bottom)) # 根據div的長寬在整個屏幕上面截圖
captcha.save('captcha.png')

2.識別需要點擊的坐標

 把需要識別的圖片和提示一起上傳 返回坐標

result = self.chaojiying.post_pic(bytes_array.getvalue(), CHAOJIYING_KIND) # 提交圖片進行驗證
groups = result.get('pic_str').split('|') # 對返回的數據進行解析 獲取x坐標和y坐標
locations = [[int(number) for number in group.split(',')] for group in groups]

3.根據坐標順序依次頁面進行點擊

根據x和y坐標依次點擊圖片當中的文字self.get_touclick_element() 獲取圖片的位置

move_to_element_with_offset 將鼠標移動到距某個元素多少距離的位置

for location in locations:
  ActionChains(self.browser).move_to_element_with_offset(self.get_touclick_element(), location[0],location[1]).click().perform()
  time.sleep(1)

識別案例

 

 

conf 目錄

[DEFAULT]
CODE_USERNAME = xxxxxxxxx
CODE_PASSWORD = 1111111
CODE_SOFT_ID = 894611
CODE_KIND = 9004
TRACK_TICKET_USERNAME = uuuuuu
TRACK_TICKET_PASSWORD = ya1111

[OTHER]
image=1
check_config.ini
import logging
import os
from logging import handlers

# 日志格式
c_format = '[%(asctime)s] [%(levelname)s] [%(filename)s:%(lineno)d] [%(message)s]'
f_format = '[%(asctime)s]-[%(levelname)s]-[%(filename)s:%(lineno)d]-[%(message)s]'
# log文件目錄
logfile_dir = r'%s\log'%os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
log_name = 'scrapy.log'

# 文件絕對路徑
logfile_path = os.path.join(logfile_dir, log_name)


def get_mylogger(name):
    """
    get log
    :param name: 
    :return: 
    """
    logger = logging.getLogger(name)
    logger.setLevel('DEBUG')

    console_handler = logging.StreamHandler()
    console_handler.setLevel('INFO')

    file_handler = logging.FileHandler(logfile_path)
    file_handler.setLevel('WARNING')

    file_size_handler = handlers.RotatingFileHandler(logfile_path, maxBytes=5 * 1024*1024, backupCount=5)
    file_time_handler = handlers.TimedRotatingFileHandler(logfile_path,when="W0",backupCount=5)

    logger.addHandler(console_handler)
    logger.addHandler(file_handler)

    file_format = logging.Formatter(fmt=f_format)
    console_format = logging.Formatter(fmt=c_format, datefmt='%Y-%m-%d %H:%M:%S ')

    console_handler.setFormatter(console_format)
    file_handler.setFormatter(file_format)

    return logger

if __name__ == '__main__':
    log = get_mylogger('test')
my_logset.py
import os
config_path = r'%s\%s' %(os.path.dirname(os.path.abspath(__file__)),'check_config.ini')
image_path =  r'%s\image' %os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
settings.py

lib目錄

#!/usr/local/bin/python3
# -*- coding: utf-8 -*-
import configparser
import os



class Read_Ini(object):

    def __init__(self,config_file):
        self.config = configparser.ConfigParser()
        self.config.read(filenames=config_file)



    def get_value(self, name,section='DEFAULT'):
        """
         得到section下的屬性name的值
        :param section: 
        :param name: 
        :return: 
        """
        return  self.config.get(section,name)

    def get_section_dict(self,section='DEFAULT'):
        """
         得到section下所有屬性值
        :param section: 
        :return: 
        """
        return self.config.options(section)

if __name__ == '__main__':
    path = r'%s\conf\%s' % (os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'check_config.ini')
    print(path)
    a = Read_Ini(path)
    print(a.get_value('CODE_USERNAME'))
read_ini.py
import requests
from hashlib import md5


class Chaojiying(object):

    def __init__(self, username, password, soft_id):
        self.username = username
        self.password = md5(password.encode('utf-8')).hexdigest()
        self.soft_id = soft_id
        self.base_params = {
            'user': self.username,
            'pass2': self.password,
            'softid': self.soft_id,
        }
        self.headers = {
            'Connection': 'Keep-Alive',
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }


    def post_pic(self, im, codetype):
        """
        im: 圖片字節
        codetype: 題目類型 參考 http://www.chaojiying.com/price.html
        """
        params = {
            'codetype': codetype,
        }
        params.update(self.base_params)
        files = {'userfile': ('ccc.jpg', im)}
        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
        return r.json()

    def report_error(self, im_id):
        """
        im_id:報錯題目的圖片ID
        """
        params = {
            'id': im_id,
        }
        params.update(self.base_params)
        r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
        return r.json()
chaojiying.py

core目錄

#!/usr/local/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2018/4/22 20:16
# @Author  : hyang
# @File    : demo.py
# @Software:

import time
from io import BytesIO
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait # 等待元素加載的
from selenium.webdriver.common.action_chains import ActionChains  #拖拽
from selenium.webdriver.support import expected_conditions as EC
# from selenium.common.exceptions import TimeoutException, NoSuchElementException
from selenium.webdriver.common.by import By
from PIL import Image
from lib import chaojiying
from lib import read_ini
from conf import settings
from conf import my_logset as mylog
from collections import namedtuple
import os




class Check_Code_Click_Demo(object):

    def __init__(self):
        self.url = 'https://kyfw.12306.cn/otn/login/init'
        self.driver = webdriver.Chrome()
        self.wait = WebDriverWait(self.driver,10)
        # print(settings.config_path)
        self.config = read_ini.Read_Ini(settings.config_path)
        self.logger = mylog.get_mylogger('demo')
        '''
        使用超級鷹打碼平台-用戶名,密碼,軟件ID
        '''
        self.chaojiying = chaojiying.Chaojiying(self.config.get_value('CODE_USERNAME'), self.config.get_value('CODE_PASSWORD'), self.config.get_value('CODE_SOFT_ID'))

    def __del__(self):
        self.driver.close() # 當對象銷毀后,執行關閉

    def open_url(self):
        '''
        打開網頁,最大化,操作滾動條
        :return:
        '''
        self.driver.get(self.url)
        time.sleep(1)
        self.driver.maximize_window()  # 最大化
        # self.driver.set_window_size(1920, 1080)  # 分辨率 1920*1080
        self.logger.info('打開url,輸入用戶名,密碼')
        self.driver.find_element_by_id('username').send_keys(self.config.get_value('TRACK_TICKET_USERNAME'))
        time.sleep(0.5)
        self.driver.find_element_by_id('password').send_keys(self.config.get_value('TRACK_TICKET_PASSWORD'))
        time.sleep(0.5)
        # js = 'var q=document.documentElement.scrollTop=280'  # 操作滾動條
        # self.driver.execute_script(js)


    # 區域截圖(對指定的區域/元素截圖)
    def element_screenshot(self,element):
        # 截取全屏圖片
        self.driver.save_screenshot(os.path.join(settings.image_path,'full.png'))
        # 獲取element的頂點坐標
        x_point = element.location['x']
        y_point = element.location['y']
        # 獲取element的寬、高
        element_width = x_point + element.size['width']
        element_height = y_point + element.size['height']
        points = namedtuple('points',['x','y','width','height'])
        p = points(x_point,y_point,element_width,element_height)
        pl = (p.x, p.y, p.width, p.height)
        self.logger.info('得到驗證碼位置%s' %str(pl))
        # 開始截取指定區域
        picture = Image.open(os.path.join(settings.image_path,'full.png'))

        ''''' 
        crop()--  一個顯式的參數:一個4元組 
          Image.crop(box=None):圖像返回一個矩形區域,box是一個四元組 限定所述左,上,右,和下像素坐標 
          參數:box--裁剪矩形,作為(左,上,右,下)-tuple;返回類型:Image;返回:一個Image對象 
          所以你應該重寫它: 
          #        ^    4-tuple    ^ 
        '''
        picture = picture.crop((pl))
        picture.save(os.path.join(settings.image_path,'fullcrop.png'))

        return picture

    def get_touclick_image(self):
        """
        得到要點擊的圖像
        :return:
        """
        element = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.touclick-img-par.touclick-bgimg')))
        return element

    def get_image(self,name='captcha.png',num = 100):
        """
         得到要識別的圖片
        :param name:
        :param num:
        :return:
        """
        image_element = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.touclick-img-par.touclick-bgimg')))
        captcha = self.element_screenshot(image_element)
        self.logger.info('得到要識別的圖片')
        return captcha

    def get_click_words(self, location):
        """
         根據返回坐標的位置,點擊圖像中識別字的坐標
        :param location:
        :return:
        """
        for loc in location:
            im_element = self.get_touclick_image()
            # print(im_element.location['x'], im_element.location['y'], im_element.size)
            #print('loc=',loc)
            # 將鼠標移動到距某個元素多少距離的位置點擊
            ActionChains(self.driver).move_to_element_with_offset(im_element,loc[0],
                                                                  loc[1]).click().perform()
            self.driver.save_screenshot(os.path.join(settings.image_path,'check.png'))
            time.sleep(0.5)


    def get_points(self,res):
        """
         解析坐標的位置
        :param res:
        :return:
        """
        groups = res.get('pic_str').split('|')  # 解析返回的坐標
        location = [[int(num) for num in group.split(',')] for
 group in groups]

        return location


    def login(self):
        time.sleep(1)
        login_element = self.driver.find_element_by_id('loginSub')
        self.logger.info('開始點擊登錄')
        login_element.click()


    def main(self):
        image = self.get_image()
        #time.sleep(10)
        byte_array = BytesIO()
        image.save(byte_array, format('png'))  # 把圖片轉換為二進制格式保存到內存中
        try:
            # 獲取圖像二進制數據,把數據提交到打碼平台
            res = self.chaojiying.post_pic(byte_array.getvalue(), self.config.get_value('CODE_KIND'))  
            self.logger.info('得到打碼平台%s' % res)
            # 解析坐標
            location = self.get_points(res)
            if location:
                self.logger.info('得到識別的坐標%s'%location)
                self.get_click_words(location)
                self.login()
                time.sleep(6)

                self.driver.switch_to.window(self.driver.window_handles[-1])
                self.logger.info('url:%s' %self.driver.current_url)
                #[url:https://kyfw.12306.cn/otn/index/initMy12306]

                if 'initMy' in self.driver.current_url:
                    self.logger.info('用戶登錄成功')
                    self.driver.save_screenshot(os.path.join(settings.image_path,'full_login.png'))
                else:
                    check_error = self.driver.find_element_by_id('error_msgmypasscode1')
                    check_style = check_error.get_attribute('style')
                    print('style=', check_style)
                    if 'none' in check_style:
                        self.logger.info('驗證成功')
                        # self.driver.save_screenshot('True.png')
                    else:
                        self.logger.error('驗證失敗!!!')
                        self.main()
        except Exception as e:
            self.logger.error('返回異常!!!%s'% e)

if __name__ == '__main__':
    c = Check_Code_Click_Demo()
    c.open_url()
    c.main()
demo.py

 

bin目錄

import sys,os

BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)  # 加入環境變量

from core import demo
from conf import my_log_settings

if __name__ == '__main__':
    # my_log_settings.load_my_logging_cfg(__name__)
    de = demo.Check_Code_Click_Demo()
    de.open_url()
    de.main()
start.py

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM