spider_review-爬虫复习1.0

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()


总结:今天的内容有些多,慢慢消化,每天跟着练习,又不懂的就问.问题不要隔夜
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值