Python爬虫 Pyppeteer模拟登录(带验证码识别)

发布时间 2023-03-23 09:17:54作者: 英飞

Python爬虫 Pyppeteer模拟登录(带验证码识别)

需求

绕过登录验证码或自动登录

参考

主流网站 Python 爬虫模拟登陆方法汇总 - 知乎 (zhihu.com)

python爬虫_hwwaizs的博客-CSDN博客

技术路线

1 request

本地请求

实现基于python的Web联网认证自动登录脚本 - 知乎 (zhihu.com)

自动登录校园网脚本(Python实现) - 知乎 (zhihu.com)

2 模拟浏览器操作

pyppeteer

Pyppeteer入门及中文教程 - 简书 (jianshu.com)

Linux安装部署Puppeteer踩坑_张驰Zhangchi的博客-CSDN博客

selenium + webdriver

2 万字带你了解 Selenium 全攻略 - 知乎 (zhihu.com)

3 利用浏览器插件

爬虫实战: 利用浏览器插件绕过登录验证码 - 知乎 (zhihu.com)

有哪些超神的油猴脚本? - 知乎 (zhihu.com)

Chrome 扩展(插件)开发官方入门教程 - 知乎 (zhihu.com)

chrome插件最新版本开发指南来了 - 掘金 (juejin.cn)

思路

使用pyppeteer使用本地帐号模拟登录,遇到验证码进行截图然后调用百度识图api进行识别,登录成功之后保存cookies,下一次使用cookies直接登录

代码实现

1 进入登录页面,截取验证码

2 百度api试别验证码

3 输入账号,密码,验证码 进行登陆 ,保存cookies

4 尝试使用cookies登录

# -*- coding: utf-8 -*-

import asyncio
import json
import os
import time

import requests
from PIL import Image
from pyppeteer import launch
from aip import AipOcr

APP_ID = ''
API_KEY = ''
SECRET_KEY = ''
client = AipOcr(APP_ID, API_KEY, SECRET_KEY)  # 调用API接口
def ocr_code(img_path):
    """
    识别验证码图片,得到验证码
    :param img_path: 验证码图片
    :return: 验证码
    """
    # 百度API参数


    # 使用百度API读取
    # 读取图片,应为百度API中提供的方法参数只能是字节流
    with open(img_path, 'rb') as f:
        image = f.read()

    # 使用API中提供的方法识别验证码并返回验证码
    data = client.accurate(image)
    print(data)
    # print(data)
    if 'words_result' in data:
        if data['words_result_num'] > 0:
            code = data['words_result'][0]['words']
            return code
        else:
            return 0
    else:
        # return 0
        time.sleep(1)
        ocr_code(img_path)


async def login_pyppeteer(username, password):
    """
    使用pyppeteer进行一次登录,有可能因为验证码错误导致登录失败
    :param username: 平台用户名名
    :param password:  平台密码
    :return:
    """
    # 涉及到的相关文件路径
    photo_path = "screen.png"  # 浏览器截图路径
    crop_photo_path = "code.png"  # 对浏览器截图得到验证码部分
    cookies_path = username + "Cookies.txt"  # 保存cookies文件路径

    browser = await launch({
        # Windows 和 Linux 的目录不一样,情换成自己对应的executable文件地址
        'executablePath': 'C:/Users/xxxx/AppData/Local/pyppeteer/pyppeteer/local-chromium/588429/chrome-win32/chrome.exe',

        'headless': False
    })
    page = await browser.newPage()

    # 浏览器操作,进入登录页面
    await page.goto("https://www.xxx.cn/login")

    # 浏览器截图
    await page.screenshot({'path': photo_path})
    # print('截图成功')

    # 裁剪图片
    left = 470  # 获取图片左上角坐标x int(img.location['x'])
    top = 320  # 获取图片左上角y  int(img.location['y'])
    right = left + 116  # 获取图片右下角x  int(img.location['x']) + img.size['width'])
    bottom = top + 36  # 获取图片右下角y   int(img.location['y'])+img.size['height'])
    rangle = (left, top, right, bottom)
    code_img = Image.open(photo_path).crop(rangle)  # 截取验证码图片
    code_img.save(crop_photo_path)
    # OCR识别验证码
    code_ocr = ocr_code(crop_photo_path)

    # print(code_ocr)
    if code_ocr != 0:
        code_ocr = code_ocr.replace(' ', '')
        # 输入账号密码
        uniqueIdElement = await page.querySelector('#username')
        await uniqueIdElement.type(username, delay=2)
        passwordElement = await page.querySelector('#password_show')
        await passwordElement.type(password, delay=2)

        # 输入验证码
        codeElement = await page.querySelector('#captchaCode')
        await codeElement.type(code_ocr, delay=2)

        # 点击登录
        okButtonElement = await page.querySelector('#login-btn')
        await okButtonElement.click()

        time.sleep(2)
        # 查看登录结果,是否跳转成功
        await  page.goto("https://www.xxx.cn/index")
        userNameElement = await page.querySelector('#menuColumn')
        # print(userNameElement)

        # 如果登录成功,保存cookies并返回相关信息
        if userNameElement != None:
            Cookies = await page.cookies()
            # print(f'Cookies{Cookies}')
            cookies = {}

            for itme in Cookies:
                # print(itme)
                cookies[itme['name']] = itme['value']

            # 将cookies信息写入文件
            # print(f'cookis:{cookies}')
            with open(cookies_path, 'w') as file:
                file.write(json.dumps(cookies))

            await  browser.close()
            return cookies
        else:
            await browser.close()
            return False

    else:
        await browser.close()
        return False


def login(username, password):
    """
     主函数 ,多次调用,直到登录成功
    :param username:  账号
    :param password:  密码
    :return:  cookies信息
    """

    # 多次尝试,直至登录成功

    cookies = asyncio.get_event_loop().run_until_complete(login_pyppeteer(username, password))

    while not cookies:
        cookies = asyncio.get_event_loop().run_until_complete(login_pyppeteer(username, password))

    #print(cookies)
    return cookies


def login_cookies(username):
    """
    读取txt文本中的信息,进入登录后页面
    :param username: 用户名
    :return: 登录后页面的内容
    """
    # 读取cookies
    cookies_path = username + 'Cookies.txt'
    cookies = None
    if os.path.exists(cookies_path):
        fo = open(cookies_path, 'r')
        cookies = fo.read()
        fo.close()

    cookies_json = json.loads(cookies)
    # cookies = {}
    # print(cookies_json)
    # print(type(cookies_json))

    # 使用cookies进行登录
    # 使用cookies登录
    # request登录
    url = 'https://www.xxx.cn/index'
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.146 Safari/537.36'
    }
    conn = requests.Session()  # 创建会话
    resp = conn.get(url=url, headers=headers, cookies=cookies_json)
    # selector = Selector(text=resp.text)
    print(resp.text)

from login_pyppeteer import login, login_cookies

cookies = login('xxxx@qq.com','xxxxx')
print(cookies)
login_cookies('xxxx@qq.com')