Selenium模擬登錄魅族
- 魅族的驗證碼采用了第三方「極驗」驗證碼平臺,破解比較復(fù)雜,故采用打碼平臺超級鷹進行識別。原理是將驗證碼圖片轉(zhuǎn)換成字節(jié)流發(fā)送給超級鷹,超級鷹會返回驗證碼所在的坐標。
- 超級鷹注冊后綁定微信會獲取1000題分供測試使用。
- 超級鷹python API
#!/usr/bin/env python
# coding:utf-8
import requests
from hashlib import md5
# 超級鷹打碼平臺
class Chaojiying(object):
def __init__(self, username, password, soft_id):
self.username = username
password = password.encode('utf8')
self.password = md5(password).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 PostPic(self, im, codetype):
"""
im: 圖片字節(jié)
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 ReportError(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()
if __name__ == '__main__':
chaojiying = Chaojiying('xxxx', 'xxxx', 'xxxx')
im = open('captch.png', 'rb').read()
print(chaojiying.PostPic(im, 9004))
-
meizu_login.py
==難點是驗證碼圖片的獲取要完整,在這里我選擇了通過URL去獲取,獲得的圖片類似于下圖:==
captcha.png
import time
import urllib.request
from io import BytesIO
from PIL import Image
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from robot.media_admin.meizu_spider.chaojiying import Chaojiying
from utils.LogUtil import LogHandler
logger = LogHandler('meizu_login')
CHAOJIYING_USERNAME = 'xxx'
CHAOJIYING_PASSWORD = 'xxx'
CHAOJIYING_SOFT_ID = '901142' #軟件ID官網(wǎng)生成
CHAOJIYING_KIND = '9004'
class MeizuLogin():
"""
主類
通過調(diào)用 chaojiying 類中的 多個方法進行圖片上傳,結(jié)果獲取
"""
def __init__(self, username, password):
self.url = "https://login.flyme.cn/sso?appuri=http%3A%2F%2Fmzdsp.meizu.com%2Flogin&useruri=&sid=&service=app&" \
"autodirct=true"
path = '自己設(shè)備上chromedriver的路徑'
self.browser = webdriver.Chrome(executable_path=path)
self.browser.maximize_window()
self.wait = WebDriverWait(self.browser, 20)
self.email = username
self.password = password
self.chaojiying = Chaojiying(CHAOJIYING_USERNAME, CHAOJIYING_PASSWORD, CHAOJIYING_SOFT_ID)
def __del__(self):
self.browser.close()
def open(self):
"""
打開網(wǎng)頁輸入用戶名密碼
:return: None
"""
self.browser.get(self.url)
email = self.wait.until(EC.presence_of_element_located((By.ID, 'account')))
password = self.wait.until(EC.presence_of_element_located((By.ID, 'password')))
email.send_keys(self.email)
password.send_keys(self.password)
def get_touclick_element(self):
"""
獲取驗證圖片對象,就是驗證碼的點擊區(qū)域
:return: 圖片對象
"""
element = self.wait.until(EC.presence_of_element_located(
(By.CLASS_NAME, 'geetest_item_img')))
return element
def get_position(self):
"""
從節(jié)點對象,獲取驗證碼位置
:return: 驗證碼位置元組
"""
element = self.get_touclick_element()
time.sleep(2)
location = element.location
size = element.size
top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size[
'width']
return (top * 2, bottom * 2, left * 2, right * 2)
def get_screenshot(self):
"""
根據(jù)驗證碼位置,獲取網(wǎng)頁截圖
:return: 截圖對象
"""
screenshot = self.browser.get_screenshot_as_png()
screenshot = Image.open(BytesIO(screenshot))
return screenshot
def get_touclick_image(self, name='captcha.png'):
"""
保存驗證碼圖片到本地
:return: 圖片對象
"""
top, bottom, left, right = self.get_position()
print('驗證碼位置', top, bottom, left, right)
screenshot = self.get_screenshot()
captcha = screenshot.crop((left, top, right, bottom))
captcha.save(name)
return captcha
def get_points(self, captcha_result):
"""
{'err_no': 0, 'err_str': 'OK', 'pic_id': '9069220022448500002', 'pic_str': '208,75|269,156', 'md5': 'a2175369130a2ca56a77573cbf5cc7dc'}
解析識別結(jié)果,就是解析超級鷹返回的數(shù)據(jù)
:param captcha_result: 識別結(jié)果
:return: 轉(zhuǎn)化后的結(jié)果
"""
groups = captcha_result.get('pic_str').split('|')
locations = [[int(number) for number in group.split(',')] for group in groups]
return locations
def touch_click_words(self, locations):
"""
點擊驗證圖片
:param locations: 點擊位置
:return: None
"""
for location in locations:
print(location)
ActionChains(self.browser).move_to_element_with_offset(self.get_touclick_element(), location[0],
location[1]).click().perform()
time.sleep(1)
def crack(self):
"""
破解入口
:return: None
"""
try:
self.open()
self.browser.find_element_by_class_name('geetest_radar_tip_content').click()
time.sleep(2)
# 獲取驗證碼圖片
image_src = str(self.browser.find_element_by_class_name('geetest_item_img').get_attribute('src'))
print(image_src)
image_src = image_src + 'png'
image = urllib.request.urlretrieve(image_src, filename='captcha.png')
im = open('captcha.png', 'rb').read()
# 識別驗證碼
result = self.chaojiying.PostPic(im, CHAOJIYING_KIND)
logger.info(result)
locations = self.get_points(result)
print(locations)
# 進行點擊圖片
self.touch_click_words(locations)
time.sleep(2)
# 點擊登陸
self.browser.find_element_by_class_name('geetest_commit_tip').click()
time.sleep(1)
submit = self.wait.until(EC.element_to_be_clickable((By.ID, 'login')))
submit.click()
time.sleep(2)
login_id = self.browser.find_element_by_xpath('//*[@id="app"]/header/div[2]/div/p[2]/small').text
print(login_id)
return login_id
except Exception as e:
# 如果失敗了超級鷹會返回分值
logger.error('登錄失敗:%s', e)
self.chaojiying.ReportError(result['pic_id'])
return None
finally:
# 退出chrome-headless 瀏覽器
self.browser.quit()
if __name__ == '__main__':
username = 'xxx'
password = 'xxx'
for i in range(3):
crack = MeizuLogin(username, password)
uid = crack.crack()
if uid is None:
continue
else:
print(uid)
break
