打碼平台介紹
一般使用超級鷹或打碼兔的打碼平台。
超級鷹介紹
打開http://www.chaojiying.com/contact.html注冊用戶,生成軟件ID
查看打碼類型
使用方法
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) # 上傳圖片
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')
把需要識別的圖片和提示一起上傳 返回坐標
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]
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

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')

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__)))
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'))

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()
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()
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()