曾几何时,你是否被一个旋转验证码而困扰,没错今日主题——旋转验证码。
之前也是被他伤透了心,研究了好几天的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,注意:需要把模型下载下来解压到根目录
今天的感触就是,让我们站在巨人的肩膀上快速成长吧。加油,兄弟!!!
文章浏览阅读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安装失败
文章浏览阅读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读取不到元素
文章浏览阅读531次。NSString *urlStr = @"http://localhost:8080/datainterface/interfacename"; NSMutableURLRequest *jsonRequest = [[NSMutableURLRequest alloc] init]; [jsonRequest setURL:[NSURL URLWithString:ur_oc post form
文章浏览阅读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
文章浏览阅读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
文章浏览阅读1.9w次,点赞15次,收藏88次。1、JVM参数配置我们学习Java GC机制的目的是为了实用,也就是为了在JVM出现问题时分析原因并解决之,JVM监控与调优主要的着眼点在于如何配置、如何监控、如何优化3点上。在Java虚拟机的参数中,有3种表示方法标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容; 非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容;非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用..._jvm参数
文章浏览阅读4.1k次。今天很多工程师都使用不同的CAD软件,以至于产生了不同格式的CAD格式文件,因此所有人都难以互换,其中主流的CAD软件有:PTC Creo,Siemens NX,CATIA,SolidWorks,Autodesk Inventor等,如果要向下游进行传递或是需要在线预览下车间等,则需要统一轻量化处理后方可传递或是在线预览,经过近三年的时间探索,目前实现了几种主流CAD文件的轻量化处理,处理后的文件可以在线预览或是传递给下游系统,如有需要可以扫描下方且交流,其中sldprt文件在线预览如下:..._solidworks在线预览
文章浏览阅读398次。在网站中,我们经常看到每当我们准备登陆时,网页询问我们是否保存用户名和密码,以便下次登陆时不用再次输入。诸如此类的功能如何实现哪?经过两天的研究,终于有了收获!现将我的经验与大家分享。在网页中记录用户的信息通常有如下几种方式:Session、Cookie、以及.Net环境下的ViewState等。比较起来,Session将用户的信息暂存在内存中,除非用户关闭网页,否则信息将一直有效。所以,用Ses..._cookie无法使用时如何保存用户信息
文章浏览阅读559次。在刚刚接触PHP时,曾遇到过这样一个坑,就是在PHP7.0版本中无法使用mysql连接数据库,当时只好降级PHP版本来通过mysql来连接数据库(很无奈的做法),但作为一个与时俱进的程序员,必须学习新的技术才能保持竞争力,所以今天就介绍一下利用PDO_mysql连接MySQL,这也是PHP新版本推荐使用的一个扩展。PDO_mysql操作在php.ini中开启PDO_mysql扩展//取消注释ext..._pat pdo_mysql
文章浏览阅读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..._系统级的优化
文章浏览阅读1.6k次,点赞25次,收藏34次。如何下载和安装MinGW64_mingw下载