最新selenium+验证码识别模拟登陆b站

作者刚学python爬虫的菜鸟一枚,内容如有不足,敬请指出。

在这里插入图片描述

主要步骤:

1.分析登录界面结构

在这里插入图片描述
首先明确我们的目标,打开登陆界面,定位用户名和密码对应的标签,输入相关数据后,点击登录,此时页面会弹出验证码。
在这里插入图片描述
下面用两种方法进行验证码的获取,然后提交给超级鹰进行识别,接收到汉字的坐标后,处理数据,然后用动作链进行点击操作,最后定位点击确认,登陆成功。

2.使用selenium打开登录页面

代码实现:

# 使用selenium打开登录界面
bro = webdriver.Chrome(executable_path='./chromedriver')
bro.get('https://passport.bilibili.com/login')

# 定位用户名,密码输入框
username = bro.find_element_by_id('login-username')
password = bro.find_element_by_id('login-passwd')

sleep(1)
# 将自己的用户名密码替换xxxxxx
username.send_keys('xxxxxx')
sleep(1)
password.send_keys('xxxxxx')
sleep(1)

# 定位登录按钮并点击
bro.find_element_by_xpath('//*[@id="geetest-wrap"]/div/div[5]/a[1]').click()
sleep(2)

3.获取页面当前验证码图片

3.1方法一、页面截图,将验证码区域进行裁剪保存

使用此方法时,注意我们截取验证码图片时需要截取完整,完整验证码截图如下
在这里插入图片描述
首先做的当然是将点击登录后的页面进行截图,然后定位到验证码的位置,通过location()方法获取验证码左上角的坐标, size() 获取验证码的宽和高,左上角坐标加上宽和高就是验证码右下角的坐标。获取坐标后就可以用crop()方法来进行裁剪,然后将裁剪到的验证码图片保存。

此时虽然获取了验证码图片,但是还不能直接提交给超级鹰。。
因为超级鹰识别的验证码图片的宽和高有限制,最好不超过460px,310px。
但是截取到的验证码图片宽高为338px,432px,这时就要先将图片缩小一倍再提交即可,等到收到坐标数据再将坐标乘2

代码实现:

# save_screenshot就是将当前页面进行截图且保存
bro.save_screenshot('page.png')

# 定位验证码图片的位置
code_img_ele = bro.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div')
location = code_img_ele.location  # 验证码左上角的坐标x,y
size = code_img_ele.size  # 验证码图片对应的长和宽

# 左上角和右下角的坐标
# 这里坐标乘1.25是由于电脑屏幕的比例不是100%,我的是125%,请自行在设置中查看
rangle = (
    int(location['x'] * 1.25), int(location['y'] * 1.25), int((location['x'] + size['width']) * 1.25),
    int((location['y'] + size['height']) * 1.25)
)

i = Image.open('./page.png')
code_img_name = './code.png'
# crop根据rangle元组内的坐标进行裁剪
frame = i.crop(rangle)
frame.save(code_img_name)

# 缩小图片,宽为169,高为216
code = Image.open('./code.png')
small_img = code.resize((169, 216))
small_img.save('./small_img.png')
print(code.size, small_img.size)

3.2方法二、通过网页获取图片地址,并保存

这种方法比上一种更加方便,分析网页源码获取图片地址,对该地址发送请求,接收返回的二进制文件,进行保存。首先打开网页源码找到图片地址。
在这里插入图片描述
图片地址是img标签的src属性值,通过xpath得到地址,直接对此url发送请求,接收数据并保存即可。
注意:由于获取的图片的高度仍然大于超级鹰标准格式,所以也需要将图片缩小。

代码实现:

# 获取img标签的src属性值
img_url = bro.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div/div[2]/div[1]/div/div[2]/img').get_attribute('src')
headers = {
    
    
    'Users-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36'
}
# 获取图片二进制数据
img_data = requests.get(url=img_url, headers=headers).content
with open('./node1.png', 'wb')as fp:
    fp.write(img_data)
i = Image.open('./node1.png')
# 将图片缩小并保存,设置宽为172,高为192
small_img = i.resize((172, 192))
small_img.save('./small_img1.png')

4.使用超级鹰识别验证码

这部分没什么说的,直接调用就行。

代码如下:

# 将验证码提交给超级鹰进行识别
chaojiying = Chaojiying_Client('用户名', '密码', '96001')  # 用户中心>>软件ID 生成一个替换 96001
im = open('small_img.png', 'rb').read()  # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
# 9004是验证码类型
print(chaojiying.PostPic(im, 9004)['pic_str'])
result = chaojiying.PostPic(im, 9004)['pic_str']

5.对获取的坐标数据进行提取,并用动作链完成点击

超级鹰识别返回的数据格式是:123,12 | 234,21。我们可以将数据以’ | '进行分割,保存到列表中,再以逗号分割将x,y的坐标保存,得到[ [123,12],[234,21] ]这一格式,然后遍历这一列表,使用动作链对每一个列表元素对应的x,y指定的位置进行点击操作,最后定位并点击确认,登录成功。

代码实现:

all_list = []  # 要存储即将被点击的点的坐标  [[x1,y1],[x2,y2]]
if '|' in result:
    list_1 = result.split('|')
    count_1 = len(list_1)
    for i in range(count_1):
        xy_list = []
        x = int(list_1[i].split(',')[0])
        y = int(list_1[i].split(',')[1])
        xy_list.append(x)
        xy_list.append(y)
        all_list.append(xy_list)
else:
    x = int(result.split(',')[0])
    y = int(result.split(',')[1])
    xy_list = []
    xy_list.append(x)
    xy_list.append(y)
    all_list.append(xy_list)

# 遍历列表,使用动作链对每一个列表元素对应的x,y指定的位置进行点击操作
# x,y坐标乘2和0.8,是由于
for l in all_list:
    x = l[0] * 2 * 0.8
    y = l[1] * 2 * 0.8
    # 将点击操作的参照物移动到指定的模块,
    # 若用方法二获取的验证码图片,要添加下面代码对code_img_ele赋值
    # code_img_ele = bro.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div/div[2]/div[1]/div/div[2]/img')
    ActionChains(bro).move_to_element_with_offset(code_img_ele, x, y).click().perform()
    sleep(0.1)
    print('点击已完成')

# 完成动作链点击操作后,定位确认按钮并点击
bro.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div/div[3]/a').click()

完整代码

import requests
from hashlib import md5

class Chaojiying_Client(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: 图片字节
        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()


# 以上为超级鹰文档代码

from selenium import webdriver
from time import sleep
from PIL import Image
from selenium.webdriver import ActionChains
import random

# 使用selenium打开登录界面
bro = webdriver.Chrome(executable_path='./chromedriver')


def login():
    bro.get('https://passport.bilibili.com/login')

    # 定位用户名,密码输入框
    username = bro.find_element_by_id('login-username')
    password = bro.find_element_by_id('login-passwd')
    username.send_keys('xxxxx')
    password.send_keys('xxxxx')

    # 定位登录按钮并点击
    bro.find_element_by_xpath('//*[@id="geetest-wrap"]/div/div[5]/a[1]').click()
    sleep(random.random()*3)

def save_img():
    # save_screenshot就是将当前页面进行截图且保
    bro.save_screenshot('page.png')
    # 定位验证码图片的位置
    code_img_ele = bro.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div')
    location = code_img_ele.location  # 验证码左上角的坐标x,y
    size = code_img_ele.size  # 验证码图片对应的长和宽

    # 左上角和右下角的坐标
    rangle = (
        int(location['x'] * 1.25), int(location['y'] * 1.25), int((location['x'] + size['width']) * 1.25),
        int((location['y'] + size['height']) * 1.25)
    )

    i = Image.open('./page.png')
    code_img_name = './code.png'
    # crop根据rangle元组内的坐标进行裁剪
    frame = i.crop(rangle)
    frame.save(code_img_name)
    return code_img_ele

def narrow_img():
    # 缩小图片
    code = Image.open('./code.png')
    small_img = code.resize((169, 216))
    small_img.save('./small_img.png')
    print(code.size, small_img.size)

def submit_img():
    # 将验证码提交给超级鹰进行识别
    chaojiying = Chaojiying_Client('1837751407', '123456', '908533')  # 用户中心>>软件ID 生成一个替换 96001
    im = open('small_img.png', 'rb').read()  # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
    print(chaojiying.PostPic(im, 9004)['pic_str'])
    result = chaojiying.PostPic(im, 9004)['pic_str']
    return result

def parse_data(result):
    all_list = []  # 存储即将被点击的点的坐标  [[x1,y1],[x2,y2]]
    if '|' in result:
        list_1 = result.split('|')
        count_1 = len(list_1)
        for i in range(count_1):
            xy_list = []
            x = int(list_1[i].split(',')[0])
            y = int(list_1[i].split(',')[1])
            xy_list.append(x)
            xy_list.append(y)
            all_list.append(xy_list)
    else:
        print(result.split(',')[0])
        print(result.split(',')[1])

        x = int(result.split(',')[0])
        y = int(result.split(',')[1])
        xy_list = []
        xy_list.append(x)
        xy_list.append(y)
        all_list.append(xy_list)
    return all_list

def click_codeImg(all_list, code_img_ele):
    # 遍历列表,使用动作链对每一个列表元素对应的x,y指定的位置进行点击操作
    for l in all_list:
        x = l[0] * 1.6
        y = l[1] * 1.6
        # move_to_element_with_offset移动到距某个元素(左上角坐标)多少距离的位置
        ActionChains(bro).move_to_element_with_offset(code_img_ele, x, y).click().perform()
        sleep(random.random())
        print('点击已完成')

    sleep(random.random()*2)
    # 完成动作链点击操作后,定位确认按钮并点击
    bro.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div/div[3]/a').click()

def main():
    # 进入登录界面,输入账号密码
    login()
    # 保存页面截图,并根据坐标裁剪获取验证码图片
    code_img_ele = save_img()
    # 缩小图片
    narrow_img()
    # 将图片提交给超级鹰,获取返回值
    result = submit_img()
    # 解析返回值,将数据格式化
    all_list = parse_data(result)
    # 在页面验证码上完成点击操作
    click_codeImg(all_list, code_img_ele)

if __name__=='__main__':
    main()

知识参考链接

猜你喜欢

转载自blog.csdn.net/qq_43965708/article/details/109010694