曾几何时,你是否被一个旋转验证码而困扰,没错今日主题——旋转验证码。
之前也是被他伤透了心,研究了好几天的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
还有这位老哥的反爬策略
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,注意:需要把模型下载下来解压到根目录
今天的感触就是,让我们站在巨人的肩膀上快速成长吧。加油,兄弟!!!
文章浏览阅读202次。packagecode;//importjava.awt.*;//importjava.awt.Canvas;//importjava.awt.event.*;//importjavax.swing.*;importjava.util.Random;importjavax.microedition.lcdui.*;//写界面所需要的包/***//***俄罗斯方块*高雷*2007年1..._240×320java游戏
文章浏览阅读779次,点赞14次,收藏19次。然后,实现系统的数据管理和服务功能,包括用户的注册与登录、电影的分类与展示、电影信息的查询与推荐、座位的选择与预订、在线支付与电子票生成等。此外,随着在线视频平台的兴起,越来越多的人选择在线观看电影,这对传统电影院产生了巨大的冲击。研究意义: 开发在线电影院售票平台对于提升用户的观影体验、优化电影院的运营效率、促进电影产业的发展具有重要的意义。该系统旨在通过技术手段解决传统电影院售票中的问题,提供一个集成化的电影信息展示、座位选择、在线支付和用户评价平台,同时也为电影院和电影制作方提供有效的工具。
文章浏览阅读509次。保护我们剩下的人的通话信息安全,使用TOX可以让你在和家人,朋友,爱人交流时保护你的隐私不受政府无孔不入的的偷窥.关于TOX:其他牛逼的软件因为一些细化服务问你要钱的时候, TOX分文不取 . 你用了TOX, 想干嘛就干嘛.网友评论:项目源码展示:源码测试效果:最后,如果你学C/C++编程有什么不懂的,可以来问问我哦,或许我能够..._基于c++的即时聊天系统设计
文章浏览阅读584次。鱼弦:CSDN内容合伙人、CSDN新星导师、全栈领域创作新星创作者 、51CTO(Top红人+专家博主) 、github开源爱好者(go-zero源码二次开发、游戏后端架构 https://github.com/Peakchen)当Java服务在Linux系统中运行时,可能会出现swap分区被占用的内存泄露问题,导致系统性能下降或者崩溃。下面是该问题的故障及解决方法、底层结构、架构图、工作原理、使用场景详解和实际应用方式、原理详细描述、相关命令使用示例以及文献材料链接。_linux swap占用很高
文章浏览阅读662次。Alt+F11,然后插入-模块:复制下面代码到编辑窗口:Sub 半角标点符号转换为全角标点符号()'中英互译文档中将中文段落中的英文标点符号替换为中文标点符号 Dim i As Paragraph, ChineseInterpunction() As Variant, EnglishInterpunction() As Variant Dim MyRange..._替换半角宏
文章浏览阅读2.8k次。#.简介: WebView是Android提供的用来展示展示web页面的View,内部使用webkit浏览器引擎(一个轻量级的浏览器引擎),除了展示Web页面外,还可与Web页面内的JS脚本交互调用。WebView内部的WebSetting对象负责管理WebView的参数配置; WebViewClient负责处理WebView的各种请求和通知事件,在对应事件发生时会执行WebViewClient的对应回调; ChromeWebviewClient辅助Webview处理与JS一些交互......_android webview真正加载完成
文章浏览阅读1.6k次。_bitcoin 调试环境搭建
文章浏览阅读4.3k次,点赞93次,收藏94次。为了解决贝塞尔曲线无法局部修正、控制性减弱、曲线次数过高、不易拼接的缺陷,引入B样条曲线(B-Spline)。本文介绍B样条曲线的基本概念:节点向量、支撑性、次数阶数、加权性质、节点生成算法等,为后续曲线计算打下基础。_样条曲线生成
文章浏览阅读902次。配置本地repo库下载我的阿里云盘文件文件放置#创建目录mkdir -p /opt/cloudera/parcel-repo/mkdir -p /opt/cloudera/cm/yum install createrepoCDH 6.2.0 的三个文件放到/opt/cloudera/parcel-repo/中,并且注意把sha256后缀的文件名修改为sha#执行createrepo命令生成rpm元数据 最终/opt/cloudera/parcel-repo/会多一个repodata目录_/opt/cloudera/cm-agent/service/mgmt/mgmt.sh: line 76: /usr/java/jdk1.8.0_181
文章浏览阅读943次,点赞2次,收藏2次。uni.canvasToTempFilePath_uni.canvastotempfilepath
文章浏览阅读3.1k次。SRAM :静态RAM,不用刷新,速度可以非常快,像CPU内部的cache,都是静态RAM,缺点是一个内存单元需要的晶体管数量多,因而价格昂贵,容量不大。DRAM:动态RAM,需要刷新,容量大。SDRAM:同步动态RAM,需要刷新,速度较快,容量大。DDR SDRAM:双通道同步动态RAM,需要刷新,速度快,容量大。........................_sdram 干扰
文章浏览阅读7.3k次。假设表格有A、B、C、D四列数据,希望导入到你的数据库中表格table,对应的字段分别是col1、col2、col3、col4。_excel数据怎么生成sql语句