IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Python 爬虫实战 — 模拟登陆 bilibili【点触验证码对抗】 -> 正文阅读

[Python知识库]Python 爬虫实战 — 模拟登陆 bilibili【点触验证码对抗】


项目概述


文章目录

# 1. 思维导图

# 2. 超级鹰打码平台介绍

# 3. 初始化模块

## 3.1?初始化函数

## 3.2 账号密码登录

# 4. 验证码处理模块

## 4.1 验证码图片裁剪

# 4.2 调用超级鹰接口

# 4.3 验证码坐标解析

# 4.4 模拟点击验证码

# 5. 登录模块

## 5.1 点击验证按钮

## 5.2 获取验证成功标识

## 5.3 登陆失败处理

# 6.? 最终效果

# 7. 心路历程


# 1. 思维导图


# 2. 超级鹰打码平台介绍

超级鹰验证码识别-专业的验证码云端识别服务,让验证码识别更快速、更准确、更强大

  • 用户充值题分,1 块钱 1000 题分
  • 用户通过 chaojiying.post_pic 调用平台接口传入图片
  • 平台智能分配任务,人工识别返回坐标,一次花费 15 题分左右
  • 若错误,可以调用 chaojiying.report_error 接口返回错误,返回题分

# 3. 初始化模块

## 3.1?初始化函数

USERNAME = 'xxxxxxxxxx'
PASSWORD = 'xxxxxxxxxx'
# 超级鹰用户名、密码、软件 ID、验证码类型
CHAOJIYING_USERNAME = 'xxxxx'
CHAOJIYING_PASSWORD = 'xxxxx'
CHAOJIYING_SOFT_ID = 893590
CHAOJIYING_KIND = 9004

class CrackTouClick:
    def __init__(self):
        self.url = 'https://passport.bilibili.com/login?from_spm_id=333.1007.top_bar.login'
        s = Service("D:\Software\webdrivers\chromedriver.exe")
        options = Options()
        options.add_argument('--start-maximized')
        self.browser = webdriver.Chrome(service=s,options=options)
        self.wait = WebDriverWait(self.browser, 5)
        self.username = USERNAME
        self.password = PASSWORD
        self.chaojiying = Chaojiying(CHAOJIYING_USERNAME, CHAOJIYING_PASSWORD, CHAOJIYING_SOFT_ID)

初始化 bilibili 账号(USERNAME)、密码(PASSWORD)、超级鹰用户名(CHAOJIYING_USERNAME)、超级鹰登录密码(CHAOJIYING_PASSWORD)、超级鹰软件 ID(CHAOJIYING_SOFT_ID)、验证码类型(CHAOJIYING_KIND),webdriver 初始化

🎇 self.wait = WebDriverWait(self.browser, 5):显示等待列入类变量里,在后面可以直接 self.wait.until(EC.presence_of_element_located((By.ID, 'login-username')))?,方便了很多


## 3.2 账号密码登录

def open(self):
    """
    打开网页输入用户名密码
    :return: None
    """
    self.browser.get(self.url)
    self.browser.execute_script('document.body.style.zoom="0.667"')
    username = self.wait.until(EC.presence_of_element_located((By.ID, 'login-username')))
    password = self.wait.until(EC.presence_of_element_located((By.ID, 'login-passwd')))
    username.send_keys(self.username)
    password.send_keys(self.password)

def get_touclick_button(self):
    """
    获取初始验证按钮
    :return: 登录按钮对象
    """
    button = self.wait.until(EC.element_to_be_clickable((By.XPATH, '//a[contains(@class,"btn btn-login")]')))
    return button

🎇 self.browser.execute_script('document.body.style.zoom="0.667"') 是对 JavaScript 代码的执行,是为了把屏幕分辨率从 150% 缩小到 100%,这样才不会导致截图截出来是完全错位的,详情可见文章?验证码对抗 - 解决 PIL.Image 库 crop 函数截取图片不准确的问题

🎇 在 Xpath 时,若一个属性对应的值有空格,则 @xxx='xx xx' 的方式会选择不到结果,这时候用 contains 函数是可以解决这个问题


# 4. 验证码处理模块

## 4.1 验证码图片裁剪

>? bilibili 将验证码的图片分为两个部分,验证码在 geetest_head ,图片在 geetest_item_img,需要将他们两个分别获取,然后进行 position 以及 size 的拼接

👇? 获取验证码的?geetest_head

def get_geetest_head(self):
    """
    获取验证码区域头部:含验证码
    :return: 验证码对象
    """
    element = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_head')))
    return element

👇? 获取验证码的?geetest_item_img


def get_touclick_element(self):
    """
    获取验证图片对象
    :return: 图片对象
    """
    element = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_item_img')))
    return element

👇? 对极验验证码的头部和图片本身进行拼接,这样才能把全部验证码信息截取下来

def get_position(self):
    """
    获取验证码位置
    :return: 验证码位置元组
    """
    head_element = self.get_geetest_head()
    touclick_element = self.get_touclick_element()

    head_location = head_element.location
    touclick_location = touclick_element.location
    size = touclick_element.size

    top = head_location['y']
    bottom = touclick_location['y'] + size['height']
    left = touclick_location['x']
    right = touclick_location['x'] + size['width']

    return (top, bottom, left, right)

?👇 调用 webdriver 自带的截图函数 get_screenshot_as_png(),BytesIO 转为字节对象,因为超级鹰的接口要求传入的是图片的字节

def get_screenshot(self):
    """
    获取网页截图
    :return: 截图对象
    """
    screenshot = self.browser.get_screenshot_as_png()
    screenshot = Image.open(BytesIO(screenshot))
    return screenshot

👇 ?这是一个对之前函数的调用函数,同时想 save 图片到指定路径,我们查看 Image 类的 save 函数,发现可以传入 pathlib 对象来指定路径,为了记录测试的时间,我同时调用了 datetime 库的 datetime.now.strftime("%H_%M_%S") 函数生成当前时间,用 pathlib.Path() 对象在文件名加入当前时间,方便查看每一次的保存结果

def get_touclick_image(self, name='0_bilibiliTouClick'):
    """
    获取验证码图片
    :return: 图片对象
    """
    now = datetime.now() # current date and time
    now_time = now.strftime("%H_%M_%S")

    top, bottom, left, right = self.get_position()
    screenshot = self.get_screenshot()

    p = pathlib.Path(r'D:\SOP\Crawler\Demos\VerificationCodedemo\HandleBilibiliTouclick\screenshot & captcha')
    screenshot_name = '0_screenshot__{}.png'.format(now_time)
    screenshot_pathlib_object = p/screenshot_name
    screenshot.save(screenshot_pathlib_object)

    captcha = screenshot.crop((left, top, right, bottom))
    captcha_name = name+'__{}.png'.format(now_time)
    captcha_pathlib_object = p/captcha_name
    captcha.save(captcha_pathlib_object)
    return captcha

到此为止,我们获得了超级鹰平台需要格式的 9004 图片!


# 4.2 调用超级鹰接口

>? 查看超级鹰提供的 Python 官方文档,要求用?字节?形式传入

image = self.get_touclick_image()
bytes_array = BytesIO()
image.save(bytes_array, format='PNG')
result = self.chaojiying.post_pic(bytes_array.getvalue(),CHAOJIYING_KIND)

# 4.3 验证码坐标解析

>? 超级鹰在 get_touclick_image()?调用后几秒内,用 json 的形式返回转化后的坐标值,这里则是将 json 形式转为更易于读写的 list 形式

def distinguish_locations(self, captcha_result):
    """
    解析识别结果
    :param captcha_result: 识别结果
    :return: 转化后的结果
    """
    groups = captcha_result.get('pic_str').split('|')
    locations = [[int(number) for number in group.split(',')] for group in groups]
    return locations

# 4.4 模拟点击验证码

>? 将?distinguish_locations() 传回的验证字的位置列表,逐个解析出验证字的页面横纵坐标,进行点击,注意?休息的时间不能太长或者太均匀,bilibili 检测到就会立即换图

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

🎇 .click().perform() 是一种可以显示点击的点击方式


# 5. 登录模块

## 5.1 点击验证按钮

def get_geetest_commit(self):
    """
    获取验证码界面的 '确定'
    :return: 确定按钮对象
    """
    button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_commit_tip')))
    return button

## 5.2 获取验证成功标识

def touch_click_verify(self):
    """
    点击验证按钮
    :return: None
    """
    button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_commit_tip')))
    button.click()

## 5.3 登陆失败处理

>? 失败 3 次以内,点击 🔃 按钮;失败次数 > 3,再次 crack()

👇? 获得 🔃 按钮

def get_geetest_refresh(self):
    """
    获取刷新按钮对象
    :return: 刷新按钮对象
    """
    element = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_refresh')))
    return element

?👇? 登陆失败处理

refresh_time = 0
while 1:

    image = self.get_touclick_image()
    bytes_array = BytesIO()
    image.save(bytes_array, format='PNG')
    result = self.chaojiying.post_pic(bytes_array.getvalue(),CHAOJIYING_KIND)
    locations = self.distinguish_locations(result)
    self.touch_click_words(locations)
    self.login()

    try:
        success = self.wait.until(EC.text_to_be_present_in_element((By.CLASS_NAME, 'geetest_panel_success_title'), '通过验证'))
        print(success)
        self.login()
        break

    except TimeoutException:
        self.chaojiying.report_error(result['pic_id'])
        if refresh_time <= 2:
            refresh_time += 1
            continue
        else:
            time.sleep(random.random()*3)
            self.crack()

print("Success!!!")
time.sleep(10)
self.browser.close()

# 6.? 最终效果

>? 最终效果的呈现,并不是每次都验证成功,经过多次实验,大概三次之内一定会成功 (在循环之内),会失败的原因可能是在拼接 geetest_head 和 geetest_item_img 的时候,让他们完全上下边完全重合了 —— 实际的网页里,两个元素还是相差了一个指甲盖左右的距离,事实上,可以不用拼接,而是直接截取外框,效果也是一样的。

不过这个动图截得很不错,所以就用这个动图展现啦!


# 7. 心路历程

首先感谢大家读到这里!

这次的项目,本来是想做 bilibili 的滑动验证码的,但是发现 bilibili 改成了点触验证码,于是就先做了这么一个点触验证码的项目,这个项目开始,我开始做版本管理,并给自己制定了版本管理的一些标准,在做项目的时候很开心,觉得自己在解决一个又一个的问题且在记录,不像之前,可能改了这里那里又没改,结果就一下乱了,和大家分享一下我这次项目的文件夹!

这篇文章主要总结了自己的思路,完整的代码在:GitHub - Shawshank-LIUYU/Python3-Crawler-projects: Python3 爬虫实战项目,Python 3 practice of spiders.

再次感谢大家的阅读!?

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-10-24 14:53:43  更:2021-10-24 14:55:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 20:21:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码