研究了好几天,终于解决了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()