Jayson

老牛亦解韶光贵,不等扬鞭自奋蹄。

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

通过winIO32绕过密码控件,实现自动登录

环境:
vmware上安装windows 32位系统:windows xp / windows 7
selenium版本: 3.11.0
IEDriverServer版本: win32_3.9.0, 放在C:\Program Files\Internet Explorer目录下
python版本: 2.7.14

实现思路:
1.由于密码控件无法用html元素定位,所以首先计算出密码控件的坐标位置;
2.模拟鼠标点击获取密码输入框焦点,再使用winIO32实现模拟键盘输入密码;
3.登录名使用selenium填写    
4.图片验证码获取到位置后截图,调用打码服务,然后使用selenium填写识别后的验证码;   
5.通过selenium获取到登录按钮,点击登录,最后返回登录成功的cookie。  
python实现代码:
使用pip安装以下模块:
flask
flask-script
pillow
pyautogui
requests
selenium

启动服务,地址:127.0.0.1:80

开发环境启动方式:
python login_service.py runserver -h 127.0.0.1 -p 80

生产环境启动方式:
uwsgi --socket 0.0.0.0:80 --protocol=http --wsgi-file myflaskapp.py --callable app --processes 4 --threads 2 --stats 0.0.0.0:9191
# -*- coding: UTF-8 -*-
# login_service.py 登录请求入口
from flask import Flask
from flask.ext.script import Manager
import selenium_service

app = Flask(__name__)
manager = Manager(app)


@app.route('/login/<username>/<password>')
def login(username, password):
	print('request is coming, params:%s, %s' % (username, password))
	ret = {}

	#这边参数要转字符串格式,否则驱动在模拟键盘输入密码时会有问题
	ret = selenium_service.login(str(username), str(password))
	return ret


@app.route('/')
def hello():
	return 'hello world'
	

if __name__ == '__main__':
	manager.run()
# -*- coding: UTF-8 -*-
# selenium_service.py 调用selenium登录
import os
import time
import json
from selenium.common.exceptions import UnexpectedAlertPresentException
import parse_img
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from PIL import Image
import pyautogui
import ctypes_util
import sys

reload(sys)
sys.setdefaultencoding('utf-8')

timestamp = str(int(round(time.time() * 1000)))
iedriver1 = 'C:/Program Files/Internet Explorer/IEDriverServer.exe'
os.environ['webdriver.ie.driver'] = iedriver1
img_name = timestamp + '.png'
new_img_name = 'new_' + img_name
browser = None	

def home():
    lct = None
    try:
		global browser
		browser = webdriver.Ie(iedriver1)
		browser.get('https://www.xxxx.com/login/loginreg.jsp')
    except UnexpectedAlertPresentException as e:
        print('unexpected alert present when visit the website.')

def refresh():
	#点击刷新图片验证码
	browser.find_element_by_class_name('yzm_a').click()
	
def switchToCurrentWindow():
	h = browser.current_window_handle
	browser.switch_to.window(h)
	
def getImg():
	element = browser.find_element_by_class_name('yzm_img')
	#switchToCurrentWindow()
	browser.get_screenshot_as_file(img_name)
	im = Image.open(img_name)
	left = element.location['x']
	top = element.location['y']
	right = element.location['x'] + element.size['width']
	bottom = element.location['y'] + element.size['height']
	region = im.crop((left, top, right, bottom))
	# 保存图片验证码
	region.save(new_img_name)
	# 调用打码服务识别图片验证码
	code = parse_img.parseImage(new_img_name)
	removeImg(img_name)
	removeImg(new_img_name)
	print('parse img return code:' + code)
	return code

def input(username, password, code):
	browser.maximize_window()
	x1 = 210
	y1 = 350
	# 点击获取密码输入框焦点
	pyautogui.click(x1,y1)
	# 调用winIo驱动输入密码
	try:
		ctypes_util.typestr(password)
	except Exception as e:
		print(e)
	# 输入用户名和图片验证码
	browser.find_element_by_id('_@IMGRC@_').send_keys(code)
	browser.find_element_by_id('loginname').send_keys(username)
	#点击登录按钮
	browser.find_element_by_class_name('btn2').click()
	

def login(username, password):
	try:
		home()
		code = getImg()
		if len(code.strip()) != 6 or code == 'ERROR':
			refresh()
			code = getImg()
		input(username, password, code)
		browser.implicitly_wait(0.5)
	except Exception as e:
		print(e)
	#登录结果检查
	#status: -1表示验证码错误,0表示登录名或密码错误,1表示登录成功,-2表示未知错误
	status = 0
	result = ''
	errMsg = ''
	_msg_ = ''
	lgnInfo = ''
	pwdInfo = ''
	
	try:
		lgnInfo = browser.find_element_by_id('loginNameInfo').text
		pwdInfo = browser.find_element_by_id('passwordInfo').text
		print('loginNameInfo:%s, passwordInfo:%s' %(lgnInfo, pwdInfo))
	except:
		print('loginNameInfo or passwordInfo not exist!')
		
	try:
		errMsg = browser.find_element_by_id('_error_field_').text
	except:
		print('errMsg not exist!')
	
	try:
		_msg_ = browser.find_element_by_id('_@MSG@_').text
	except:
		print('_msg_ not exist!')
		
	print('errorMsg:' + errMsg)
	print('_msg_:' + _msg_)
	
	msg = errMsg if errMsg != '' else _msg_	
	inputInfo = lgnInfo if lgnInfo != '' else pwdInfo
	print('msg=' + msg)
	if len(msg.strip()) > 0:
		if '验证码输入错误' in msg:
			status = -1
		elif '登录名或密码错误' in msg:
			status = 0
		else:
		    status = -2
	elif len(inputInfo.strip()) > 0:
		status = -3
		msg = '登录名或密码输入错误,请重试!'
	else:
		status = 1
		msg = '登录成功'
		result = ';'.join([item['name'] + '=' + item['value'] for item in browser.get_cookies()])
	#关闭browser
	browser.quit()
	#组装返回报文
	ret = {}
	ret['result'] = result
	ret['status'] = status
	ret['message'] = msg
	return json.dumps(ret, ensure_ascii=False)
		
def removeImg(path):
    if os.path.exists(path):
        os.remove(path)


if __name__ == '__main__':
	result = login('sel2364', 'sel2364')
	print(result)
# -*- coding: UTF-8 -*-
# ctypes_util.py 调用dll中的函数,模拟键盘输入
from ctypes import *
import platform

def typestr(s):
	if platform.system() == 'Windows':
		libc = cdll.LoadLibrary('testdll_driver.dll')
		libc.output(s)
		

if __name__ == '__main__':
    typestr('aaabbb')
# -*- coding: UTF-8 -*-
# parse_img.py 调用打码服务
import requests
import json

url = "http://xxx.xxxx.com/captcha/parse"
# fo = open("code.jpg", "rb")

headers={
    "appkey":"******",
    "source":"******"
}

def parseImage(file):
    fo = open(file, "rb")
    body = fo.read()
    resp = requests.post(url, body, headers=headers)
    #print(resp.content)
    jsonobj = json.loads(resp.content)
    return jsonobj['code']

if __name__ == '__main__':
    code = parseImage("code.jpg")
    print("code=" + code);
posted on 2018-04-19 09:41  jaysoncho  阅读(646)  评论(0编辑  收藏  举报