python+selenium3解决126邮箱登录出现验证码问题

研究了好几天,终于解决了126邮箱登录出现的验证码问题!!!
首先需要导包:
1、下载PIL,一个强大的处理图像的库。无法使用pip小工具下载,而且官网没有对应的python3版本,不过可以使用pillow替代PIL,可以从http://www.lfd.uci.edu/~gohlke/pythonlibs/下载对应版本的pillow,然后使用pip工具安装(pip install pillow)。使用导包的时候要注意,导入的依旧是PIL,而不是pillow。
2、下载python对应的超级鹰开发文档。超级鹰是一个验证码识别平台,提供了识别接口,十分方便快捷。从官网https://www.chaojiying.com/下载,同时注册一个账号密码,获取软件ID,这在之后的代码中都会用到。
3、其他的库用pip小工具是可以直接下载的。

代码思路我是参考http://www.manongjc.com/detail/9-srwdzkavnkhigmq.html,思路大家可以看这里的,讲的很清楚。主要可能需要修改的就是验证码图片的位置和鼠标移动的位置,对应的方法是submit_cal(),get_position(),click()。

运行这个程序可能会出现验证失败的问题,应该是我的图片位置定位的不够精确,所以我用循环控制重新验证,验证成功才break。如果出现没有显示验证码或者没有点击汉字的问题,多半是因为原网页变了,需要重新确定验证码位置。

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver import ActionChains
from chaojiying import Chaojiying_Client
from PIL import Image
from io import BytesIO
import time
from selenium.common import exceptions

class Mail_BrackGeetest():

    def __init__(self,browser,USER,PASSWORD,ID):# 初始化浏览器,超级鹰账号密码和ID,
        self.browser = browser
        self.wait = WebDriverWait(self.browser, 30)
        self.chaojiying = Chaojiying_Client(USER, PASSWORD, ID)

    def open(self):
        '''
        打开网页,最大化窗口,点击密码登录
        :return: None
        '''
        self.browser.get('https://mail.126.com/')
        self.browser.maximize_window()
        self.browser.find_element_by_id("switchAccountLogin").click()

    def quit(self):
        '''
        关闭浏览器
        :return: None
        '''
        self.browser.quit()

    def submit_user(self,username,password):
        '''
        提交账号和密码
        :return: None
        '''
        time.sleep(0.5)
        self.browser.find_element_by_name("email").clear()
        self.browser.find_element_by_name("email").send_keys(username)
        time.sleep(0.5)
        self.browser.find_element_by_name("password").clear()
        self.browser.find_element_by_name("password").send_keys(password)

    def submit_login(self):
        '''
        点击登陆按钮
        :return: None
        '''
        self.browser.find_element_by_id("dologin").click()

    def submit_cal(self):
        '''
        点击验证按钮
        :return: None
        '''
        ActionChains(self.browser).move_by_offset(806,401).perform()
        #移动到验证码浮窗的左下角,这里的806,401代表像素,相对于整个页面的左上角
        #(0,0),验证码浮窗左下角的位置为(806,401),这个位置可以通过截图来确定。

    def switch_iframe(self):
        '''
        切换表单,得到登录页面
        :return:None
        '''
        time.sleep(0.5)
        login_frame = self.browser.find_element_by_css_selector('iframe[id^="x-URS-iframe"]')
        self.browser.switch_to.frame(login_frame)

    def get_screenshot(self):
        '''
        获取网页截屏
        :return: 网页截屏对象
        '''
        screenshot = self.browser.get_screenshot_as_png()
        screenshot = Image.open(BytesIO(screenshot))
        return screenshot

    def get_image(self, name):
        '''
        获取验证码图片
        :param name: 图片名称
        :return: 文字图片
        '''
        top, bottom, left, right = self.get_position()
        print('图片验证码位置', top, bottom, left, right)
        screenshot = self.get_screenshot()
        time.sleep(1)
        captcha = screenshot.crop((left, top, right, bottom))
        captcha.save(name + '.png')
        return captcha

    def get_position(self):
        '''
        :param name:
        :return:获取验证码或文字图片
        '''
        # 验证码图片顶部,顶部,左边,右边的位置(像素)。
        return 191,401, 806, 1146

    def get_word_pos(self, name):
        '''
        :param name:
        :return:
        '''
        im = open(name, 'rb').read()  # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
        item2 = self.chaojiying.PostPic(im, 9103)### 9103是验证码类型,可以从超级鹰官网查到
        print(item2)
        pic_id2 = item2['pic_id']
        pic_str2 = item2['pic_str']
        pos_list = pic_str2.split('|')
        pos_result = list()
        for pos in pos_list:
            pos_result.append(pos.split(','))
        if len(pos_list) != 3:
            print("长度错误")
            self.chaojiying.ReportError(pic_id2)
        return pos_result, pic_id2

    def click(self, word_list):
    	'''
    	依次点击超级鹰返回的三个汉字的横纵坐标,鼠标开始在验证码图片的左上角,
    	然后到达第一个汉字并点击,接着回到左上角,再点击第二个、第三个汉字。
        :param name:
        :return:
        '''
        ActionChains(self.browser).move_by_offset(0,-210).perform()
        for word in word_list:
            x = int(word[0])
            y = int(word[1])
            # nx ny作为微调用,可能之前量的像素不够准确
            nx = 0
            ny = -3
            ActionChains(self.browser).move_by_offset(x + nx, y + ny).click().perform()
            time.sleep(0.5)
            ActionChains(self.browser).move_by_offset(-x - nx, -y - ny).perform()
            time.sleep(0.5)

    def start(self):
        self.open()
        self.switch_iframe()
        # 我将账号密码储存在txt文件中,前三个账号密码是错误的,第四个是正确的,
        #因为只有三次错误才会出现验证码。账号密码通过:分隔,[:-1]对字符串进行切片,
        #来忽略最后一个换行符
        with open("./data_file/user_info.txt",'r') as user_file:
            data=user_file.readlines()
        for i in range(len(data)):
            user = data[i][:-1].split(':')
            self.submit_user(user[0],user[1])
            if i != len(data) - 1:## 第四次不直接点击登录,需要处理验证码了。
                self.submit_login()

       self.submit_cal()

        while True:
            time.sleep(2)
            self.get_image('image')
            time.sleep(2)
            pos_result, pic_id = self.get_word_pos('image.png')
            time.sleep(2)
            self.chaojiying.ReportError(pic_id)
            self.click(pos_result)
            time.sleep(1)
            ###鼠标回到验证码浮窗左下角
            ActionChains(self.browser).move_by_offset(0,210).perform()
            time.sleep(5)
            element=self.browser.find_element_by_xpath("/html/body/div[2]/div[2]/div[2]/form/div/div[5]/div/div/div[2]/div[3]/span[2]")
            print(element.text)
            if element.text=="失败过多,点此重试":
            	###鼠标点击重试,并回到验证码浮窗左下角
                ActionChains(self.browser).move_by_offset(181, -15).click().perform()
                ActionChains(self.browser).move_by_offset(-181, 15).perform()
            if element.text=="验证成功":
                break

        self.submit_login()
        self.browser.switch_to.default_content()
        time.sleep(2)
        self.browser.find_element_by_link_text('退出').click()
        self.quit()
        
if __name__ == '__main__':
    browser = webdriver.Chrome()
    brack = Mail_BrackGeetest(browser,'xxx', 'xxx', 'xxx')
    # 参数是浏览器,超级鹰账号密码和ID, 超级鹰SDK 用户中心>>软件ID 生成ID
    brack.start()

代码中用到的user_info.txt长这样。
python+selenium3解决126邮箱登录出现验证码问题_第1张图片
最后的效果是这样:

你可能感兴趣的:(selenium,python)