pyppeteer 登录一般网站 并利用 http方法获取登录页面的验证码

主函数

新建浏览器,进行登录,由于验证码的识别准确率不是百分之百,需要多次尝试。

    async def main(self, username, pwd, url):  # 定义main协程函数,

        login_count = 0

        # 打开浏览器
        browser = await launch(
            {'headless': False, "userDataDir": r"./temp_data", 'args': ['--no-sandbox'], })

        # 登录检测
        while login_count < 10:
            # 登录
            await self.login(browser, username, pwd, url)

            # 检测是否登录成功
            if await self.check_login(browser):
                break
            else:
                login_count += 1

        # 尝试登录次数大于10就退出
        if login_count > 10:
            print("login failed!")
            await browser.close()
            return
		
		do_something()

        await browser.close()
		

登录函数

可以替换程序中验证操作函数,实现不同的验证方式。
其中提交过程采用了xpath定位提交按钮。

    async def login(self, browser, username, pwd, url):
        page = await browser.newPage()  # 启动个新的浏览器页面
        await page.setUserAgent(
            'Mozilla/5.0 (Windows NT 6.1; WOW64) '
            'AppleWebKit/537.36 (KHTML, like Gecko) '
            'Chrome/68.0.3440.106 Safari/537.36')

        await page.goto(url)  # 访问登录页面

        # 就是在浏览器运行的时候,始终让window.navigator.webdriver=false
        # navigator是windiw对象的一个属性,同时修改plugins,languages,navigator 且让
        await page.evaluate(
            '''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')

        # 以下为插入中间js,将淘宝会为了检测浏览器而调用的js修改其结果。
        await page.evaluate('''() =>{ window.navigator.chrome = { runtime: {},  }; }''')
        await page.evaluate('''() =>{ Object.defineProperty(navigator,
         'languages', { get: () => ['en-US', 'en'] }); }''')
        await page.evaluate('''() =>{ Object.defineProperty(navigator, 
         'plugins', { get: () => [1, 2, 3, 4, 5,6], }); }''')
         
        time.sleep(2)
        
        # 使用type选定页面元素,并修改其数值,用于输入账号密码,修改的速度仿人类操作,因为有个输入速度的检测机制
        # 因为 pyppeteer 框架需要转换为js操作,而js和python的类型定义不同,所以写法与参数要用字典,类型导入
        await page.type('#username', username, {'delay': self.input_time_random() - 50})
        await page.type('#password', pwd, {'delay': self.input_time_random()})

        # await page.screenshot({'path': './picture/headless-test-result.png'})    # 截图测试

        time.sleep(1)
        
        # 验证码操作
		verification_code(page);

        # 点击提交
        submit = await page.xpath("//button[@class='auth_login_btn primary full_width']")
        await submit[0].click()

        time.sleep(1)

验证码识别和输入

我在这里利用了某网站的验证码识别api,通过http方式就能上传验证码图片,并获取验证码。这个网站每天有固定的1000张图片免费次数,足够我们使用。第一个请求链接的用户名和密码换成我们注册该网站的用户名和密码即可。具体可以看官方的API文档。
该网站地址:http://fast.95man.com/

    # 验证码登录
    async def verification_code(self, page):
        await page.waitFor(5 * 1000)                                     # 等待验证码图片加载
        yazhengma = await page.waitForSelector('#captchaImg')            # 定位验证码元素
        await yazhengma.screenshot({'path': './picture/yazhengma.png'})  # 保存验证码图片

        # 获取验证码
        code = self.get_code('./picture/yazhengma.png')

        # 输入验证码
        await page.type('#captchaResponse', code, {'delay': self.input_time_random()})

    def get_code(self, file_path):
            # 以下为GET请求
            url = 'http://api.95man.com:8888/api/Http/UserTaken?user=username&pwd=password&isref=0'
            token_request = requests.get(url)
            token_raw = str(token_request.content)

            # 切片获取token
            token = token_raw[4: -1]

            print(token)

            # 发送图片解析请求
            url = "http://api.95man.com:8888/api/Http/Recog?Taken=" + token + "&imgtype=1&len=4"
            file_path = file_path
            files = {'file': open(file_path, 'rb')}

            # 上传图片
            r = requests.post(url, files=files)
            print(r.url, r.text)

            # 切片获取验证码
            return r.text[6:10]

参考

本文中的验证码像素级保存和获取登录页面时的反反爬操作是参考了别人的博客完成的。

https://www.jianshu.com/p/4dd2737a3048
https://www.jianshu.com/p/a4c4935d5dd7
http://fast.95man.com/auth/quickchk.html

原文地址:https://www.cnblogs.com/lippon/p/14117724.html