旋转拖动验证码解决方案_load_model("keras2.hdf5", custom_objects={'angle_e-程序员宅基地

技术标签: 爬虫  python  机器学习  

前因

曾几何时,你是否被一个旋转验证码而困扰,没错今日主题——旋转验证码。

之前也是被他伤透了心,研究了好几天的js,想直接通过接口传输直接解决验证码的,然而我失败了,不过这一次,他来了他来了,他带着RotNet走来了。

彩虹屁

RotNet也是我无意间发现的,没错时隔了好几个月,他自己出现在我眼前的。这是他的github:https://github.com/d4nst/RotNet/tree/master,他主要是预测图像的旋转角度以校正其方向,库中包括很全,数据集的下载,训练,预测全都有,而且最最最重要的是,大神提供了模型,我的天。。。这是什么神仙,你是孙悟空派来拯救我的吧!兄弟!!!

当然有兴趣的同学可以看看他的文章,有具体的思路和网络实现。还有觉得有用的同学可以星一下他的github

好的,话不多说,先看看我最后的成果吧,

思路和修改

然后因为在跳出验证码的时候一般是直接给出图片的网址,所以我修改了源文件,用来直接读取网络图片和修整图片大小来适应网络,

#utils.py


#在RotNetDataGenerator._get_batches_of_transformed_samples中添加响应代码
#增加读取网络图片的函数

class RotNetDataGenerator(Iterator):
    def _get_batches_of_transformed_samples(self, index_array):
        # create array to hold the images
        batch_x = np.zeros((len(index_array),) + self.input_shape, dtype='float32')
        # create array to hold the labels
        batch_y = np.zeros(len(index_array), dtype='float32')

        # iterate through the current batch
        for i, j in enumerate(index_array):
            if self.filenames is None:
                image = self.images[j]
            else:
                is_color = int(self.color_mode == 'rgb')
                #修改这这一块{
   {
   {
   {
   {
   {
   {
   {
   {
                image = ImageScale(self.filenames[j]) if self.filenames[j][:4].lower()=="http" else cv2.imread(self.filenames[j], is_color)
                h,w=image.shape[:2]
                if h !=224 or w !=224:
                    image = cv2.resize(image, (224, 224), interpolation=cv2.INTER_CUBIC)
                
                #}}}}}}}}
                if is_color:
                    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

            if self.rotate:
                # get a random angle
                rotation_angle = np.random.randint(360)
            else:
                rotation_angle = 0

            # generate the rotated image
            rotated_image = generate_rotated_image(
                image,
                rotation_angle,
                size=self.input_shape[:2],
                crop_center=self.crop_center,
                crop_largest_rect=self.crop_largest_rect
            )

            # add dimension to account for the channels if the image is greyscale
            if rotated_image.ndim == 2:
                rotated_image = np.expand_dims(rotated_image, axis=2)

            # store the image and label in their corresponding batches
            batch_x[i] = rotated_image
            batch_y[i] = rotation_angle

        if self.one_hot:
            # convert the numerical labels to binary labels
            batch_y = to_categorical(batch_y, 360)
        else:
            batch_y /= 360

        # preprocess input images
        if self.preprocess_func:
            batch_x = self.preprocess_func(batch_x)

        return batch_x, batch_y

def ImageScale(url):
    resp = request.urlopen(url)
    image = np.asarray(bytearray(resp.read()), dtype="uint8")
    image = cv2.imdecode(image, cv2.IMREAD_COLOR)
    return image

预测角度,也是根据他的源码基础上做修改的,需要注意的是模型位置和测试图片的位置需要修改为你电脑上的文件位置

from __future__ import print_function

import os
import numpy as np

from keras.applications.imagenet_utils import preprocess_input
from keras.models import load_model

from utils import RotNetDataGenerator, angle_error


def process_images(input_path,
                   batch_size=64, crop=True):
    #需要修改模型文件位置
    model = load_model("I:\\pythonProject\\RotNet\\rotnet_models\\rotnet_street_view_resnet50_keras2.hdf5", custom_objects={'angle_error': angle_error}, compile=False)

    extensions = ['.jpg', '.jpeg', '.bmp', '.png']

    if os.path.isfile(input_path) or input_path[:4].lower()=="http":
        image_paths = [input_path]

    else:
        image_paths = [os.path.join(input_path, f)
                       for f in os.listdir(input_path)
                       if os.path.splitext(f)[1].lower() in extensions]


    predictions = model.predict_generator(
        RotNetDataGenerator(
            image_paths,
            input_shape=(224, 224, 3),
            batch_size=batch_size,
            one_hot=True,
            preprocess_func=preprocess_input,
            rotate=False,
            crop_largest_rect=True,
            crop_center=True
        ),
        val_samples=len(image_paths)
    )

    predicted_angles = np.argmax(predictions, axis=1)
    print(predicted_angles)
    return predicted_angles



if __name__ == '__main__':
    #修改测试图片位置,本地地址,或是网络图片地址
    process_images("I:\\pythonProject\\RotNet\\data\\test_examples\\008999_4.jpg")

然后通过分析百度指数的js源码发现旋转角度的公式是 angle=o/b*360

即o为拖动的距离,b=底轴宽-按钮宽

所以我们需要知道的拖动的距离就是  o=angle*360*b

好的,汇总到一起,就可以了。模拟登录百度指数,而且支持无头模式

中间有参考一段这位老哥写的pyppeteer的拖动,https://blog.csdn.net/qq393912540/article/details/91956136

还有这位老哥的反爬策略

https://github.com/wkunzhi/Python3-Spider/blob/master/%E3%80%90%E6%B7%98%E5%AE%9D%E3%80%91%E8%87%AA%E5%8A%A8%E7%99%BB%E9%99%86/auto_login_pyppeteer.py

import asyncio
from pyppeteer import launch
import random
from correct_rotation_for_angle import process_images


async def page_evaluate(page):
    await page.evaluate(
        '''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } });window.screen.width=1366; }''')
    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], }); }''')


async def main(username, password, width, height):

    browser = await launch({'headless': False,#可以无头
                            'slowMo':1.3,
                            'userDataDir': './userdata',
                            'args': [
                              f'--window-size={width},{height}'
                              '--disable-extensions',
                              '--hide-scrollbars',
                              '--disable-bundled-ppapi-flash',
                              '--mute-audio',
                              '--no-sandbox',
                              '--disable-setuid-sandbox',
                              '--disable-gpu',
                              '--disable-infobars'
                            ],
                            'dumpio': True
                            })
    page = await browser.newPage()
    # 设置浏览器头部
    await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36")

    # 设置浏览器大小
    await page.setViewport({'width': width, 'height': height})
    # 注入js,防反爬
    await page_evaluate(page)
    res=await page.goto('http://index.baidu.com/v2/index.html')

    await page.waitFor(2000)
    # 获取登录位置的文字,如果是登录就登录,不是就使用cookie
    elements = await (await(await page.querySelector('.username-text')).getProperty('textContent')).jsonValue()

    if elements == "登录":

        await page.click(".username-text")
        await asyncio.sleep(1.6)
        # 填写用户名
        await page.type('.pass-text-input-userName', username)
        # 填写密码
        await page.hover(".pass-text-input-password")
        await asyncio.sleep(0.5)
        await page.mouse.down()
        await asyncio.sleep(random.random())
        await page.mouse.up()
        # await page.click(".pass-text-input-password")
        await page.type('.pass-text-input-password', password)
        # 点击登录
        await page.mouse.move(page.mouse._x+random.randint(50,100), page.mouse._y+random.randint(100,200), options={"step": 3})
        await page.hover(".pass-button-submit")
        await page.mouse.down()
        await asyncio.sleep(random.random())
        await page.mouse.up()
        # await page.click(".pass-button-submit")
        await asyncio.sleep(2)
        rotImg = await page.querySelector('.vcode-spin-img')
        # 如果有验证码就去旋转
        while rotImg:
            img_url=await (await(rotImg).getProperty("src")).jsonValue()
            angle=process_images(img_url)[0]
            bottom_line=await (await(await page.querySelector(".vcode-spin-bottom")).getProperty("offsetWidth")).jsonValue()
            button_line = await (await(await page.querySelector(".vcode-spin-button")).getProperty("offsetWidth")).jsonValue()
            b=bottom_line-button_line
            move_line = angle/360*b
            await try_validation(page,move_line)
            # 停个3秒
            await asyncio.sleep(3)
            rotImg = await page.querySelector('.vcode-spin-img')

        #如果有需要短信验证码的弹窗的就费了
        no_in = await page.querySelector(".pass-forceverify-wrapper .forceverify-header-a")
        if no_in:
            print("有短信验证码废了")
            await no_in.click()
    # 停个2秒
    await asyncio.sleep(2)
    cookies = await page.cookies()
    # 无头模式可以打印一下用户名看看能不能登录
    elements = await (await(await page.querySelector('.username-text')).getProperty('textContent')).jsonValue()
    print(elements)
    await browser.close()
    if elements == "登录":
        return None
    return cookies

async def try_validation(page, distance=308):
    # 将距离拆分成两段,模拟正常人的行为
    distance1 = distance - 10
    distance2 = 10
    btn_position = await page.evaluate('''
       () =>{
        return {
         x: document.querySelector('.vcode-spin-button').getBoundingClientRect().x,
         y: document.querySelector('.vcode-spin-button').getBoundingClientRect().y,
         width: document.querySelector('.vcode-spin-button').getBoundingClientRect().width,
         height: document.querySelector('.vcode-spin-button').getBoundingClientRect().height
         }}
        ''')
    x = btn_position['x'] + btn_position['width'] / 2
    y = btn_position['y'] + btn_position['height'] / 2
    # print(btn_position)
    await page.mouse.move(x, y)
    await page.mouse.down()
    await page.mouse.move(x + distance1, y, {'steps': 30})
    await page.waitFor(800)
    await page.mouse.move(x + distance1 + distance2, y, {'steps': 20})
    await page.waitFor(800)
    await page.mouse.up()

def baidu_login(username, password, width, height):
    return asyncio.get_event_loop().run_until_complete(main(username, password, width, height))


if __name__ == "__main__":

    width, height = 1366, 768
    username = '你的账户'
    password = '你的密码'

    cookies = baidu_login(username, password, width, height)
    print(cookies)
    if cookies:
        string_cookies = ""
        for each in cookies:
            string_cookies += f"{each['name']}={each['value']};"

最后 

完整的项目放在https://github.com/ShortCJL/RotateCode注意:需要把模型下载下来解压到根目录

今天的感触就是,让我们站在巨人的肩膀上快速成长吧。加油,兄弟!!!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Laozizuiku/article/details/106645583

智能推荐

Windows安装word2vec的那些坑_word2vec安装失败-程序员宅基地

文章浏览阅读2.5k次。打开命令窗口,执行pip install word2vec,如图:ERROR: Command errored out with exit status 1: command: 'e:\python\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\TEMP\\pip-install-x..._word2vec安装失败

jsp在页面获取不到值的方法_在jsp文件中requestscoped读取不到元素-程序员宅基地

文章浏览阅读6.1k次,点赞6次,收藏16次。自己在做项目的时候,在jsp页面通。过${xxx}获取不到值,困扰了自己好久。自己jsp页面如下:<input id="uuid" type="hidden" value="${user.uId}" name="userId"/>controller如下: @RequestMapping(value = "/checkLogin",method = Reques_在jsp文件中requestscoped读取不到元素

Objective-C使用form方式提交json_oc post form-程序员宅基地

文章浏览阅读531次。NSString *urlStr = @"http://localhost:8080/datainterface/interfacename"; NSMutableURLRequest *jsonRequest = [[NSMutableURLRequest alloc] init]; [jsonRequest setURL:[NSURL URLWithString:ur_oc post form

KMS激活理论_kms csdn-程序员宅基地

文章浏览阅读915次。如果要在同一台KMS服务器上激活多个产品(如Office 2010和Windows 7),则需要同时安装并激活Windows KMS主机密钥。例如,当用户A安装完Office 2010后,6、KMS激活之后并非永久有效,KMS客户端必需在180之内再次连接到KMS服务器上对产品进行激活。1、Office 2007的批量授权版本是不需要激活,安装完成便可以正常使用的,但从Office 2010开始,激活的180天之内,KMS 客户端必需主动联系到KMS服务器进行重新激活,激活完成后可以再使用180天。_kms csdn

Visual Studio Team Foundation Server 2010_microsoft visual studio team foundation server 201-程序员宅基地

文章浏览阅读1w次。当前的工作用到了TFS,从没玩过,赶紧补习下,推荐下载地址:http://download.csdn.net/detail/wujiandao/4128032 Getting Started with Visual Studio Application Lifecycle ManagementVisual Studio 2010Other Ver_microsoft visual studio team foundation server 2010

史上最全的JVM配置参数大全_jvm参数-程序员宅基地

文章浏览阅读1.9w次,点赞15次,收藏88次。1、JVM参数配置我们学习Java GC机制的目的是为了实用,也就是为了在JVM出现问题时分析原因并解决之,JVM监控与调优主要的着眼点在于如何配置、如何监控、如何优化3点上。在Java虚拟机的参数中,有3种表示方法标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容; 非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容;非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用..._jvm参数

随便推点

soldworks文件在线预览_solidworks在线预览-程序员宅基地

文章浏览阅读4.1k次。今天很多工程师都使用不同的CAD软件,以至于产生了不同格式的CAD格式文件,因此所有人都难以互换,其中主流的CAD软件有:PTC Creo,Siemens NX,CATIA,SolidWorks,Autodesk Inventor等,如果要向下游进行传递或是需要在线预览下车间等,则需要统一轻量化处理后方可传递或是在线预览,经过近三年的时间探索,目前实现了几种主流CAD文件的轻量化处理,处理后的文件可以在线预览或是传递给下游系统,如有需要可以扫描下方且交流,其中sldprt文件在线预览如下:..._solidworks在线预览

用户登录状态记录cookie被禁用 怎么保存在html中,怎样将用户名和密码保存到Cookie中? (html部分)...-程序员宅基地

文章浏览阅读398次。在网站中,我们经常看到每当我们准备登陆时,网页询问我们是否保存用户名和密码,以便下次登陆时不用再次输入。诸如此类的功能如何实现哪?经过两天的研究,终于有了收获!现将我的经验与大家分享。在网页中记录用户的信息通常有如下几种方式:Session、Cookie、以及.Net环境下的ViewState等。比较起来,Session将用户的信息暂存在内存中,除非用户关闭网页,否则信息将一直有效。所以,用Ses..._cookie无法使用时如何保存用户信息

php pdo mysql_PHP中利用PDO_mysql操作MySQL数据库-程序员宅基地

文章浏览阅读559次。在刚刚接触PHP时,曾遇到过这样一个坑,就是在PHP7.0版本中无法使用mysql连接数据库,当时只好降级PHP版本来通过mysql来连接数据库(很无奈的做法),但作为一个与时俱进的程序员,必须学习新的技术才能保持竞争力,所以今天就介绍一下利用PDO_mysql连接MySQL,这也是PHP新版本推荐使用的一个扩展。PDO_mysql操作在php.ini中开启PDO_mysql扩展//取消注释ext..._pat pdo_mysql

vue 中数组中的某个对象的属性发生变化,视图不更新如何解决?_vue改变数组或对象视图没更新-程序员宅基地

文章浏览阅读1.8k次。第一种是数组的值改变,在改变数组的值的时候使用索引值去更改某一项,这样视图不会实时更新,这种情况是因为直接通过索引去改变数组,vue对象监听不到他的变化,所以没有更新;使用vue的变异方法pop(),push(),shift(),unshift(),revese(),sort(),splice()等方法也会触发视图更新。1.利用vue.set(object,key,val):例:vue.set(vm.obj,'k1','v1');2.利用Object.assign({},this.obj)创建新对象;_vue改变数组或对象视图没更新

系统性能优化的十大策略(强烈推荐,建议收藏)-程序员宅基地

文章浏览阅读654次。点击上方“芋道源码”,选择“设为星标”管她前浪,还是后浪?能浪的浪,才是好浪!每天 10:33更新文章,每天掉亿点点头发...源码精品专栏原创 | Java 2021超神之路,很肝~中文详细注释的开源项目RPC 框架 Dubbo 源码解析网络应用框架 Netty 源码解析消息中间件 RocketMQ 源码解析数据库中间件 Sharding-JDBC 和 MyCAT 源码解析作业调度中间件 E..._系统级的优化

如何下载和安装MinGW64_mingw下载-程序员宅基地

文章浏览阅读1.6k次,点赞25次,收藏34次。如何下载和安装MinGW64_mingw下载