Python破解验证码实现登录的几个方法
import io
import warnings
import easyocr
from PIL import Image
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
warnings.filterwarnings('ignore')
browser = webdriver.Chrome()
browser.set_window_size(1280, 800)
browser.get('http://mail.1000phone.com/')
# 隐式等待
browser.implicitly_wait(10)
panel_iframe = browser.find_element_by_css_selector('.login_panel_iframe')
x1, y1 = panel_iframe.location['x'], panel_iframe.location['y']
# Chrome对象的switch_to属性的frame方法,可以从页面切换到iframe中
browser.switch_to.frame(panel_iframe)
login_iframe = browser.find_element_by_css_selector('#ding-login-iframe')
x2, y2 = login_iframe.location['x'], login_iframe.location['y']
browser.switch_to.frame(login_iframe)
username_input = browser.find_element_by_css_selector('#username')
# 模拟用户输入
username_input.send_keys('邮箱.com')
password_input = browser.find_element_by_css_selector('#password')
password_input.send_keys('密码')
# 显示等待
wait = WebDriverWait(browser, 10)
wait.until(expected_conditions.element_to_be_clickable((By.CSS_SELECTOR, '#login_checkcode_ico')))
captcha_img = browser.find_element_by_css_selector('#login_checkcode_ico')
# WebElement对象的size属性代表元素宽度和高度,location属性代表元素在窗口中的位置
size, location = captcha_img.size, captcha_img.location
x3, y3, width, height = location['x'], location['y'], size['width'], size['height']
# 截取整个浏览器窗口的图片获得图片的二进制数据 ---> bytes
image_data = browser.get_screenshot_as_png()
# bytes(只读字节串) ---> BytesIO(可写字节串)---> import io
# str(只读字符串) ---> StringIO(可写字符串)---> import io
browser_image = Image.open(io.BytesIO(image_data))
# browser_image.show()
# 从截图上剪裁出验证码的图片
x, y = x1 + x2 + x3, y1 + y2 + y3
# macOS系统的写法
checkcode_image = browser_image.crop((x * 2, y * 2, (x + width) * 2, (y + height) * 2)) # type: Image.Image
checkcode_image.save('resources/code.png')
# 通过easyocr做光学文字识别
reader = easyocr.Reader(['en'], gpu=False)
code = reader.readtext('resources/code.png', detail=0)[0]
print(f'OCR识别结果: {code}')
# 将识别出的验证码输入文本框
checkcode_input = browser.find_element_by_css_selector('#login_checkcode')
checkcode_input.send_keys(code)
login_button = browser.find_element_by_css_selector('#login_submit_btn')
# 模拟用户点击
login_button.click()
破解验证码实现邮箱自动登录的另一种方法
import io
import warnings
from PIL import Image
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from chaojiying import ChaojiyingClient
warnings.filterwarnings('ignore')
browser = webdriver.Chrome()
browser.set_window_size(1280, 960)
browser.get('http://mail.1000phone.com/')
# 隐式等待
browser.implicitly_wait(10)
panel_iframe = browser.find_element_by_css_selector('.login_panel_iframe')
x1, y1 = panel_iframe.location['x'], panel_iframe.location['y']
# Chrome对象的switch_to属性的frame方法,可以从页面切换到iframe中
browser.switch_to.frame(panel_iframe)
login_iframe = browser.find_element_by_css_selector('#ding-login-iframe')
x2, y2 = login_iframe.location['x'], login_iframe.location['y']
browser.switch_to.frame(login_iframe)
username_input = browser.find_element_by_css_selector('#username')
# 模拟用户输入
username_input.send_keys('luohao@1000phone.com')
password_input = browser.find_element_by_css_selector('#password')
password_input.send_keys('Abc123!!')
# 显示等待
wait = WebDriverWait(browser, 10)
wait.until(expected_conditions.element_to_be_clickable((By.CSS_SELECTOR, '#login_checkcode_ico')))
captcha_img = browser.find_element_by_css_selector('#login_checkcode_ico')
# WebElement对象的size属性代表元素宽度和高度,location属性代表元素在窗口中的位置
size, location = captcha_img.size, captcha_img.location
x3, y3, width, height = location['x'], location['y'], size['width'], size['height']
# 截取整个浏览器窗口的图片获得图片的二进制数据
image_data = browser.get_screenshot_as_png()
browser_image = Image.open(io.BytesIO(image_data))
# 从截图上剪裁出验证码的图片
x, y = x1 + x2 + x3, y1 + y2 + y3
# macOS系统的写法
checkcode_image = browser_image.crop((x * 2, y * 2, (x + width) * 2, (y + height) * 2)) # type: Image.Image
checkcode_image.save('resources/code.png')
# 通过打码平台识别验证码
chaojiying = ChaojiyingClient('jackfrued', '1Qaz2Wsx', '900260')
with open('resources/code.png', 'rb') as file:
code_img_data = file.read()
result_dict = chaojiying.post_pic(code_img_data, 1902)
# print(result_dict)
code = result_dict['pic_str']
print(f'打码结果: {code}')
# 将识别出的验证码输入文本框
checkcode_input = browser.find_element_by_css_selector('#login_checkcode')
checkcode_input.send_keys(code)
login_button = browser.find_element_by_css_selector('#login_submit_btn')
# 模拟用户点击
login_button.click()
多进程和线程池的作用
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import ProcessPoolExecutor
# 判断列表中的数是不是质数(计算密集型任务)
PRIMES = [
1116281,
1297337,
104395303,
472882027,
533000389,
817504243,
982451653,
112272535095293,
112582705942171,
112272535095293,
115280095190773,
115797848077099,
1099726899285419,
1099726899285421
] * 5
def is_prime(num):
"""判断素数"""
for i in range(2, int(num ** 0.5) + 1):
if num % i == 0:
return False
return num > 1
def main():
"""主函数"""
# # 使用多线程的方式执行
# with ThreadPoolExecutor(max_workers=4) as pool:
# for number, result in zip(PRIMES, pool.map(is_prime, PRIMES)):
# print(f'{number} is prime: {result}')
# 使用多进程的方式执行
with ProcessPoolExecutor(max_workers=4) as pool:
for number, result in zip(PRIMES, pool.map(is_prime, PRIMES)):
print(f'{number} is prime: {result}')
if __name__ == '__main__':
main()
编写多线程代码的三种方式
import time
from threading import Thread
def output(content):
while True:
print(content, end='', flush=True)
time.sleep(0.1)
# 多线程-Thread
Thread(target=output, args=('Ping', )).start()
Thread(target=output, args=('Pong', )).start()
output('Hello')
自定义线程类
import time
from threading import Thread
class OutputThread(Thread):
"""自定义线程类"""
def __init__(self, content):
self.content = content
super().__init__()
def run(self):
while True:
print(self.content, end='', flush=True)
time.sleep(0.1)
OutputThread('Ping').start()
OutputThread('Pong').start()
线程池方法
import time
from concurrent.futures import ThreadPoolExecutor
def output(content):
while True:
print(content, end='', flush=True)
time.sleep(0.1)
with ThreadPoolExecutor(max_workers=16) as pool:
pool.submit(output, 'Ping')
pool.submit(output, 'Pong')
生成器
# 创建生成器的字面量语法(生成器表达式)
# 调用fib函数会得到生成器对象
def fib(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
yield a
# 另一种生成器
def fib(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
yield a
gen_obj = fib(20)
print(next(gen_obj))
print(next(gen_obj))
print(next(gen_obj))
print(next(gen_obj))
print(next(gen_obj))
print(next(gen_obj))
for num in gen_obj:
print(num, end=' ')
设计一个函数,给跳一跳游戏设计,传入的是一个列表
def calc_score():
total, center_point = 0, 2
while True:
item = yield total
if item:
total += center_point
center_point += 2
else:
total += 1
center_point = 2
# main函数负责提供布尔值,生长器负责产出成绩
def main():
luohao = [True, False, False, True, True, True, False, True]
gen_obj = calc_score()
# 通过给生成器对象发一个None,就实现了对生成器的预激活,生成器变成协程(可 以跟其他代码协作)
# 对生成器进行预激活 ---> 生成器升级为协程
gen_obj.send(None)
for value in luohao:
print(gen_obj.send(value))
if __name__ == '__main__':
main()
贝塞尔曲线-验证码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4SviCUnI-1629808483351)(C:\Users\朝阳0118\AppData\Roaming\Typora\typora-user-images\image-20210824202648088.png)]
会随机生成不同的验证码这只是其中一个
import os
import random
import string
from io import BytesIO
from PIL import Image
from PIL import ImageFilter
from PIL.ImageDraw import Draw
from PIL.ImageFont import truetype
class Bezier:
"""贝塞尔曲线"""
def __init__(self):
self.tsequence = tuple([t / 20.0 for t in range(21)])
self.beziers = {}
def make_bezier(self, n):
"""绘制贝塞尔曲线"""
try:
return self.beziers[n]
except KeyError:
combinations = pascal_row(n - 1)
result = []
for t in self.tsequence:
tpowers = (t ** i for i in range(n))
upowers = ((1 - t) ** i for i in range(n - 1, -1, -1))
coefs = [c * a * b for c, a, b in zip(combinations,
tpowers, upowers)]
result.append(coefs)
self.beziers[n] = result
return result
class Captcha:
"""验证码"""
def __init__(self, width, height, fonts=None, color=None):
self._image = None
self._fonts = fonts if fonts else \
[os.path.join('./fonts', font)
for font in ['Arial.ttf', 'Georgia.ttf', 'Action.ttf']]
self._color = color if color else random_color(0, 200, random.randint(220, 255))
self._width, self._height = width, height
@classmethod
def instance(cls, width=200, height=75):
prop_name = f'_instance_{width}_{height}'
if not hasattr(cls, prop_name):
setattr(cls, prop_name, cls(width, height))
return getattr(cls, prop_name)
def _background(self):
"""绘制背景"""
Draw(self._image).rectangle([(0, 0), self._image.size],
fill=random_color(230, 255))
def _smooth(self):
"""平滑图像"""
return self._image.filter(ImageFilter.SMOOTH)
def _curve(self, width=4, number=6, color=None):
"""绘制曲线"""
dx, height = self._image.size
dx /= number
path = [(dx * i, random.randint(0, height))
for i in range(1, number)]
bcoefs = Bezier().make_bezier(number - 1)
points = []
for coefs in bcoefs:
points.append(tuple(sum([coef * p for coef, p in zip(coefs, ps)])
for ps in zip(*path)))
Draw(self._image).line(points, fill=color if color else self._color, width=width)
def _noise(self, number=50, level=2, color=None):
"""绘制扰码"""
width, height = self._image.size
dx, dy = width / 10, height / 10
width, height = width - dx, height - dy
draw = Draw(self._image)
for i in range(number):
x = int(random.uniform(dx, width))
y = int(random.uniform(dy, height))
draw.line(((x, y), (x + level, y)),
fill=color if color else self._color, width=level)
def _text(self, captcha_text, fonts, font_sizes=None, drawings=None, squeeze_factor=0.75, color=None):
"""绘制文本"""
color = color if color else self._color
fonts = tuple([truetype(name, size)
for name in fonts
for size in font_sizes or (65, 70, 75)])
draw = Draw(self._image)
char_images = []
for c in captcha_text:
font = random.choice(fonts)
c_width, c_height = draw.textsize(c, font=font)
char_image = Image.new('RGB', (c_width, c_height), (0, 0, 0))
char_draw = Draw(char_image)
char_draw.text((0, 0), c, font=font, fill=color)
char_image = char_image.crop(char_image.getbbox())
for drawing in drawings:
d = getattr(self, drawing)
char_image = d(char_image)
char_images.append(char_image)
width, height = self._image.size
offset = int((width - sum(int(i.size[0] * squeeze_factor)
for i in char_images[:-1]) -
char_images[-1].size[0]) / 2)
for char_image in char_images:
c_width, c_height = char_image.size
mask = char_image.convert('L').point(lambda i: i * 1.97)
self._image.paste(char_image,
(offset, int((height - c_height) / 2)),
mask)
offset += int(c_width * squeeze_factor)
@staticmethod
def _warp(image, dx_factor=0.3, dy_factor=0.3):
"""图像扭曲"""
width, height = image.size
dx = width * dx_factor
dy = height * dy_factor
x1 = int(random.uniform(-dx, dx))
y1 = int(random.uniform(-dy, dy))
x2 = int(random.uniform(-dx, dx))
y2 = int(random.uniform(-dy, dy))
warp_image = Image.new(
'RGB',
(width + abs(x1) + abs(x2), height + abs(y1) + abs(y2)))
warp_image.paste(image, (abs(x1), abs(y1)))
width2, height2 = warp_image.size
return warp_image.transform(
(width, height),
Image.QUAD,
(x1, y1, -x1, height2 - y2, width2 + x2, height2 + y2, width2 - x2, -y1))
@staticmethod
def _offset(image, dx_factor=0.1, dy_factor=0.2):
"""图像偏移"""
width, height = image.size
dx = int(random.random() * width * dx_factor)
dy = int(random.random() * height * dy_factor)
offset_image = Image.new('RGB', (width + dx, height + dy))
offset_image.paste(image, (dx, dy))
return offset_image
@staticmethod
def _rotate(image, angle=25):
"""图像旋转"""
return image.rotate(random.uniform(-angle, angle),
Image.BILINEAR, expand=1)
def generate(self, captcha_text='', fmt='PNG'):
"""生成验证码(文字和图片)"""
self._image = Image.new('RGB', (self._width, self._height), (255, 255, 255))
self._background()
self._text(captcha_text, self._fonts,
drawings=['_warp', '_rotate', '_offset'])
self._curve()
self._noise()
self._smooth()
image_bytes = BytesIO()
self._image.save(image_bytes, format=fmt)
return image_bytes.getvalue()
def pascal_row(n=0):
"""生成毕达哥拉斯三角形(杨辉三角)"""
result = [1]
x, numerator = 1, n
for denominator in range(1, n // 2 + 1):
x *= numerator
x /= denominator
result.append(x)
numerator -= 1
if n & 1 == 0:
result.extend(reversed(result[:-1]))
else:
result.extend(reversed(result))
return result
def random_color(start=0, end=255, opacity=255):
"""获得随机颜色"""
red = random.randint(start, end)
green = random.randint(start, end)
blue = random.randint(start, end)
if opacity is None:
return red, green, blue
return red, green, blue, opacity
def random_code(length=4):
return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
if __name__ == '__main__':
captcha = Captcha.instance()
image_data = captcha.generate(random_code())
with open('resources/captcha.png', 'wb') as file:
file.write(image_data)
封装请求超级鹰打码的代码
MD5 ---> 哈希算法(单向哈希函数)---> 给对象生成签名(指纹、摘要)
128bit ---> 长度为32的十六进制字符串
SHA-1 / SHA-256
import requests
from hashlib import md5
class ChaojiyingClient:
"""请求超级鹰打码的客户端"""
def __init__(self, username, password, soft_id):
self.username = username
password = password.encode('utf8')
# 将密码处理成密码的MD5摘要(密码的指纹)
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 post_pic(self, im, codetype):
"""上传图片打码"""
params = {'codetype': codetype}
params.update(self.base_params)
files = {'userfile': ('ccc.jpg', im)}
# 通过requests的post函数上传图片到超级鹰
resp = requests.post(
url='http://upload.chaojiying.net/Upload/Processing.php',
data=params,
files=files,
headers=self.headers
)
return resp.json()
def main():
chaojiying = ChaojiyingClient('jackfrued', '1Qaz2Wsx', '900260')
# 说明:1902代表普通验证码(英文数字构成的验证码)
with open('resources/captcha.png', 'rb') as file:
result_dict = chaojiying.post_pic(file.read(), 1902)
print(result_dict)
print(result_dict['pic_str'])
# # 说明:9004代表点触验证码(点指定图片或文字的验证码)
# with open('resources/e.png', 'rb') as file:
# result_dict = chaojiying.post_pic(file.read(), 9004)
# print(result_dict['pic_str'])
if __name__ == '__main__':
main()
)
return resp.json()
def main():
chaojiying = ChaojiyingClient(‘jackfrued’, ‘1Qaz2Wsx’, ‘900260’)
# 说明:1902代表普通验证码(英文数字构成的验证码)
with open('resources/captcha.png', 'rb') as file:
result_dict = chaojiying.post_pic(file.read(), 1902)
print(result_dict)
print(result_dict['pic_str'])
# # 说明:9004代表点触验证码(点指定图片或文字的验证码)
# with open('resources/e.png', 'rb') as file:
# result_dict = chaojiying.post_pic(file.read(), 9004)
# print(result_dict['pic_str'])
if name == ‘main’:
main()
总结:今天的内容有些多,慢慢消化,每天跟着练习,又不懂的就问.问题不要隔夜