mirror of
https://github.com/sijiyo/projects.git
synced 2025-04-20 20:45:07 +08:00
Add files via upload
This commit is contained in:
commit
94d9f32e3f
26395
geetest3_fullpage/jiyan.js
Normal file
26395
geetest3_fullpage/jiyan.js
Normal file
File diff suppressed because one or more lines are too long
32
geetest3_fullpage/mian.py
Normal file
32
geetest3_fullpage/mian.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import random,threading, execjs, requests, time, json
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
frist_time = str(round(time.time() * 1000))
|
||||||
|
url = "https://www.geetest.com/demo/gt/register-fullpage?t=" + str(round(time.time() * 1000))
|
||||||
|
res = requests.get(url).json()
|
||||||
|
gt = res['gt']
|
||||||
|
challenge = res['challenge']
|
||||||
|
with open('jiyan.js', 'r', encoding='utf-8') as f:
|
||||||
|
js = execjs.compile(f.read())
|
||||||
|
key = js.call('get_key')
|
||||||
|
w = js.call('get_w1', gt, challenge, key)
|
||||||
|
url = "https://apiv6.geetest.com/get.php?gt=" + gt + "&challenge=" + challenge + "&lang=zh-cn&pt=0&client_type=web&w=" + w + "&callback=geetest_" + str(
|
||||||
|
round(time.time() * 1000))
|
||||||
|
res = requests.get(url).text
|
||||||
|
res = json.loads(res[res.index("(") + 1:res.rindex(")")])
|
||||||
|
s = res['data']['s']
|
||||||
|
w = js.call('get_w2',s,str(random.randint(500, 3000)),gt,challenge,frist_time,key)
|
||||||
|
url = "https://api.geetest.com/ajax.php?gt=" + gt + "&challenge=" + challenge + "&lang=zh-cn&pt=0&client_type=web&w=" + w + "&callback=geetest_" + str(
|
||||||
|
round(time.time() * 1000))
|
||||||
|
res = requests.get(url).text
|
||||||
|
res = json.loads(res[res.index("(") + 1:res.rindex(")")])
|
||||||
|
print(res)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
for i in range(1):
|
||||||
|
thr = threading.Thread(target=main)
|
||||||
|
thr.start()
|
||||||
|
time.sleep(2)
|
BIN
geetest3_slide/__pycache__/gap.cpython-38.pyc
Normal file
BIN
geetest3_slide/__pycache__/gap.cpython-38.pyc
Normal file
Binary file not shown.
BIN
geetest3_slide/__pycache__/trace.cpython-38.pyc
Normal file
BIN
geetest3_slide/__pycache__/trace.cpython-38.pyc
Normal file
Binary file not shown.
92
geetest3_slide/gap.py
Normal file
92
geetest3_slide/gap.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import cv2,os
|
||||||
|
from PIL import Image
|
||||||
|
class SlideCrack(object):
|
||||||
|
def __init__(self, gap, bg, out):
|
||||||
|
self.gap = gap
|
||||||
|
self.bg = bg
|
||||||
|
self.out = out
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def clear_white(img):
|
||||||
|
# 清除图片的空白区域,这里主要清除滑块的空白
|
||||||
|
img = cv2.imread(img)
|
||||||
|
rows, cols, channel = img.shape
|
||||||
|
min_x = 255
|
||||||
|
min_y = 255
|
||||||
|
max_x = 0
|
||||||
|
max_y = 0
|
||||||
|
for x in range(1, rows):
|
||||||
|
for y in range(1, cols):
|
||||||
|
t = set(img[x, y])
|
||||||
|
if len(t) >= 2:
|
||||||
|
if x <= min_x:
|
||||||
|
min_x = x
|
||||||
|
elif x >= max_x:
|
||||||
|
max_x = x
|
||||||
|
|
||||||
|
if y <= min_y:
|
||||||
|
min_y = y
|
||||||
|
elif y >= max_y:
|
||||||
|
max_y = y
|
||||||
|
img1 = img[min_x:max_x, min_y: max_y]
|
||||||
|
return img1
|
||||||
|
|
||||||
|
def template_match(self, tpl, target):
|
||||||
|
th, tw = tpl.shape[:2]
|
||||||
|
result = cv2.matchTemplate(target, tpl, cv2.TM_CCOEFF_NORMED)
|
||||||
|
# 寻找矩阵(一维数组当作向量,用Mat定义) 中最小值和最大值的位置
|
||||||
|
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
|
||||||
|
tl = max_loc
|
||||||
|
br = (tl[0] + tw, tl[1] + th)
|
||||||
|
cv2.rectangle(target, tl, br, (0, 0, 255), 2)
|
||||||
|
cv2.imwrite(self.out, target)
|
||||||
|
return tl[0]
|
||||||
|
@staticmethod
|
||||||
|
def image_edge_detection(img):
|
||||||
|
edges = cv2.Canny(img, 100, 200)
|
||||||
|
return edges
|
||||||
|
def discern(self):
|
||||||
|
img1 = self.clear_white(self.gap)
|
||||||
|
img1 = cv2.cvtColor(img1, cv2.COLOR_RGB2GRAY)
|
||||||
|
slide = self.image_edge_detection(img1)
|
||||||
|
|
||||||
|
back = cv2.imread(self.bg, 0)
|
||||||
|
back = self.image_edge_detection(back)
|
||||||
|
|
||||||
|
slide_pic = cv2.cvtColor(slide, cv2.COLOR_GRAY2RGB)
|
||||||
|
back_pic = cv2.cvtColor(back, cv2.COLOR_GRAY2RGB)
|
||||||
|
x = self.template_match(slide_pic, back_pic)
|
||||||
|
# 输出横坐标, 即 滑块在图片上的位置
|
||||||
|
return x
|
||||||
|
def get_gap():
|
||||||
|
# 滑块图片
|
||||||
|
# image1 = "img/tukuai.png"
|
||||||
|
image1 = r'./img/slide.png'
|
||||||
|
# 背景图片
|
||||||
|
# image2 = "img/beijing.png"
|
||||||
|
image2 = r'./img/bg.png'
|
||||||
|
# 处理结果图片,用红线标注
|
||||||
|
#image3 = "img/show_image.png"
|
||||||
|
image3 = r'./img/show_image.png'
|
||||||
|
sc = SlideCrack(image1, image2, image3)
|
||||||
|
os.remove('./img/oldbg.png')
|
||||||
|
os.remove('./img/oldallbg.png')
|
||||||
|
os.remove('./img/newallbg.png')
|
||||||
|
return sc.discern()
|
||||||
|
def restore_picture():
|
||||||
|
img_list = ["./img/oldbg.png", "./img/oldallbg.png"]
|
||||||
|
for index, img in enumerate(img_list):
|
||||||
|
image = Image.open(img)
|
||||||
|
s = Image.new("RGBA", (260, 160))
|
||||||
|
ut = [39, 38, 48, 49, 41, 40, 46, 47, 35, 34, 50, 51, 33, 32, 28, 29, 27, 26, 36, 37, 31, 30, 44, 45, 43,42,12, 13, 23, 22, 14, 15, 21, 20, 8, 9, 25, 24, 6, 7, 3, 2, 0, 1, 11, 10, 4, 5, 19, 18, 16, 17]
|
||||||
|
height_half = 80
|
||||||
|
for inx in range(52):
|
||||||
|
c = ut[inx] % 26 * 12 + 1
|
||||||
|
u = height_half if ut[inx] > 25 else 0
|
||||||
|
l_ = image.crop(box=(c, u, c + 10, u + 80))
|
||||||
|
s.paste(l_, box=(inx % 26 * 10, 80 if inx > 25 else 0))
|
||||||
|
if index == 0:
|
||||||
|
s.save("./img/bg.png")
|
||||||
|
else:
|
||||||
|
s.save("./img/newallbg.png")
|
BIN
geetest3_slide/img/bg.png
Normal file
BIN
geetest3_slide/img/bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
BIN
geetest3_slide/img/show_image.png
Normal file
BIN
geetest3_slide/img/show_image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
BIN
geetest3_slide/img/slide.png
Normal file
BIN
geetest3_slide/img/slide.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
2276
geetest3_slide/jiyan.js
Normal file
2276
geetest3_slide/jiyan.js
Normal file
File diff suppressed because one or more lines are too long
47
geetest3_slide/mian.py
Normal file
47
geetest3_slide/mian.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import threading,execjs, requests, time, json
|
||||||
|
from urllib import request
|
||||||
|
from gap import *
|
||||||
|
from trace import *
|
||||||
|
|
||||||
|
|
||||||
|
def get_image():
|
||||||
|
url = "https://www.geetest.com/demo/gt/register-slide?t=" + str(round(time.time() * 1000))
|
||||||
|
res = requests.get(url).json()
|
||||||
|
gt = res['gt']
|
||||||
|
challenge = res['challenge']
|
||||||
|
res = requests.get("https://api.geetest.com/ajax.php?gt=" + gt + "&challenge=" + challenge + "&lang=zh-cn&pt=0&w=&callback=geetest_" + str(
|
||||||
|
round(time.time() * 1000))).text
|
||||||
|
url = "https://api.geetest.com/get.php?is_next=true&type=slide3>=" + gt + "&challenge=" + challenge + "&lang=zh-cn&https=true&protocol=https%3A%2F%2F&offline=false&product=embed&api_server=api.geetest.com&isPC=true&autoReset=true&width=100%25&callback=geetest_" + str(
|
||||||
|
round(time.time() * 1000))
|
||||||
|
res = requests.get(url).text
|
||||||
|
res = json.loads(res[res.index("(") + 1:res.rindex(")")])
|
||||||
|
challenge = res['challenge']
|
||||||
|
s = res['s']
|
||||||
|
request.urlretrieve('https://static.geetest.com/' + res['fullbg'], 'img/oldallbg.png')
|
||||||
|
request.urlretrieve('https://static.geetest.com/' + res['bg'], 'img/oldbg.png')
|
||||||
|
request.urlretrieve('https://static.geetest.com/' + res['slice'], 'img/slide.png')
|
||||||
|
restore_picture()
|
||||||
|
distance = get_gap()
|
||||||
|
track = get_track(distance - 5)
|
||||||
|
return gt, challenge, s, distance, track
|
||||||
|
|
||||||
|
def main():
|
||||||
|
gt, challenge, s, distance, track = get_image()
|
||||||
|
with open('jiyan.js', 'r', encoding='utf-8') as f:
|
||||||
|
js = execjs.compile(f.read())
|
||||||
|
passtime = track[-1][-1]
|
||||||
|
track = js.call('get_encode_trace', track, s)
|
||||||
|
w = js.call('get_w', distance - 5, track, challenge, challenge[:32], passtime, str(random.randint(100, 200)),gt)
|
||||||
|
url = "https://api.geetest.com/ajax.php?gt=" + gt + "&challenge=" + challenge + "&lang=zh-cn&pt=0&w=" + w + "&callback=geetest_" + str(
|
||||||
|
round(time.time() * 1000))
|
||||||
|
res = requests.get(url).text
|
||||||
|
res = json.loads(res[res.index("(") + 1:res.rindex(")")])
|
||||||
|
print(res)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
for i in range(1):
|
||||||
|
thr = threading.Thread(target=main)
|
||||||
|
thr.start()
|
||||||
|
time.sleep(2)
|
47
geetest3_slide/trace.py
Normal file
47
geetest3_slide/trace.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
def __ease_out_expo(sep):
|
||||||
|
'''
|
||||||
|
轨迹相关操作
|
||||||
|
'''
|
||||||
|
if sep == 1:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 1 - pow(2, -10 * sep)
|
||||||
|
|
||||||
|
def get_track(distance):
|
||||||
|
"""
|
||||||
|
根据滑动距离生成滑动轨迹
|
||||||
|
:param distance: 需要滑动的距离
|
||||||
|
:return: 滑动轨迹<type 'list'>: [[x,y,t], ...]
|
||||||
|
x: 已滑动的横向距离
|
||||||
|
y: 已滑动的纵向距离, 除起点外, 均为0
|
||||||
|
t: 滑动过程消耗的时间, 单位: 毫秒
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not isinstance(distance, int) or distance < 0:
|
||||||
|
raise ValueError(f"distance类型必须是大于等于0的整数: distance: {distance}, type: {type(distance)}")
|
||||||
|
# 初始化轨迹列表
|
||||||
|
slide_track = [
|
||||||
|
[random.randint(-50, -10), random.randint(-50, -10), 0],
|
||||||
|
[0, 0, 0],
|
||||||
|
]
|
||||||
|
# 共记录count次滑块位置信息
|
||||||
|
count = 30 + int(distance / 2)
|
||||||
|
# 初始化滑动时间
|
||||||
|
t = random.randint(50, 100)
|
||||||
|
# 记录上一次滑动的距离
|
||||||
|
_x = 0
|
||||||
|
_y = 0
|
||||||
|
for i in range(count):
|
||||||
|
# 已滑动的横向距离
|
||||||
|
x = round(__ease_out_expo(i / count) * distance)
|
||||||
|
# 滑动过程消耗的时间
|
||||||
|
t += random.randint(10, 20)
|
||||||
|
if x == _x:
|
||||||
|
continue
|
||||||
|
slide_track.append([x, _y, t])
|
||||||
|
_x = x
|
||||||
|
slide_track.append(slide_track[-1])
|
||||||
|
return slide_track
|
57
geetest4_fullpage/jiyan.js
Normal file
57
geetest4_fullpage/jiyan.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
const NodeRSA = require('node-rsa');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const CryptoJS = require("crypto-js");
|
||||||
|
function get_key() {
|
||||||
|
var s4 = "";
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
s4 = s4 + ((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1);
|
||||||
|
}
|
||||||
|
return s4;
|
||||||
|
}
|
||||||
|
function MD5_Encrypt(word) {
|
||||||
|
return CryptoJS.MD5(word).toString();
|
||||||
|
}
|
||||||
|
function AES_Encrypt(key, word) {
|
||||||
|
var srcs = CryptoJS.enc.Utf8.parse(word);
|
||||||
|
var encrypted = CryptoJS.AES.encrypt(srcs, CryptoJS.enc.Utf8.parse(key), {
|
||||||
|
iv: CryptoJS.enc.Utf8.parse("0000000000000000"),
|
||||||
|
mode: CryptoJS.mode.CBC,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
});
|
||||||
|
return CryptoJS.enc.Hex.stringify(CryptoJS.enc.Base64.parse(encrypted.toString()));
|
||||||
|
}
|
||||||
|
function RSA_encrypt(data) {
|
||||||
|
const public_key_1 = '00C1E3934D1614465B33053E7F48EE4EC87B14B95EF88947713D25EECBFF7E74C7977D02DC1D9451F79DD5D1C10C29ACB6A9B4D6FB7D0A0279B6719E1772565F09AF627715919221AEF91899CAE08C0D686D748B20A3603BE2318CA6BC2B59706592A9219D0BF05C9F65023A21D2330807252AE0066D59CEEFA5F2748EA80BAB81';
|
||||||
|
const public_key_2 = '10001';
|
||||||
|
const public_key = new NodeRSA();
|
||||||
|
public_key.importKey({
|
||||||
|
n: Buffer.from(public_key_1, 'hex'),
|
||||||
|
e: parseInt(public_key_2, 16),
|
||||||
|
}, 'components-public');
|
||||||
|
const encrypted = crypto.publicEncrypt({
|
||||||
|
key: public_key.exportKey('public'),
|
||||||
|
padding: crypto.constants.RSA_PKCS1_PADDING
|
||||||
|
}, Buffer.from(data));
|
||||||
|
return encrypted.toString('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_w(captchaId, lot_number, detail_time, distance) {
|
||||||
|
romdon_key = get_key()
|
||||||
|
pow_msg = "1|0|md5|" + detail_time + "|" + captchaId + "|" + lot_number + "||" + romdon_key
|
||||||
|
xiyu = {
|
||||||
|
"setLeft": distance,
|
||||||
|
"userresponse": distance / (.8876 * 340 / 300),
|
||||||
|
"device_id": "D00D",
|
||||||
|
"lot_number": lot_number,
|
||||||
|
"pow_msg": pow_msg,
|
||||||
|
"pow_sign": MD5_Encrypt(pow_msg),
|
||||||
|
"geetest": "captcha",
|
||||||
|
"lang": "zh",
|
||||||
|
"ep": "123",
|
||||||
|
'cuel': '632729377',
|
||||||
|
"em": {"ph": 0, "cp": 0, "ek": "11", "wd": 1, "nt": 0, "si": 0, "sc": 0}
|
||||||
|
}
|
||||||
|
xiyu = JSON.stringify(xiyu).replace(" ", "").replace("'", '"')
|
||||||
|
w = AES_Encrypt(romdon_key, xiyu)+ RSA_encrypt(romdon_key)
|
||||||
|
return w
|
||||||
|
}
|
48
geetest4_fullpage/mian.py
Normal file
48
geetest4_fullpage/mian.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import re, requests, time, uuid, execjs, json
|
||||||
|
from lxml import etree
|
||||||
|
from urllib import request
|
||||||
|
|
||||||
|
|
||||||
|
def get_captchaId():
|
||||||
|
url = "https://www.geetest.com/adaptive-captcha-demo"
|
||||||
|
res = requests.get(url).text
|
||||||
|
js_url = re.search(r'preload" href="(/_next/static/[^"]+\.js)" as="script"/>', res).group(1)
|
||||||
|
res = requests.get("https://www.geetest.com" + js_url).text
|
||||||
|
captchaId = re.search('captchaId:"([0-9a-z]+)"', res).group(1)
|
||||||
|
return captchaId
|
||||||
|
|
||||||
|
|
||||||
|
def main(captchaId, challenge):
|
||||||
|
url = "https://gcaptcha4.geetest.com/load?captcha_id=" + captchaId + "&challenge=" + challenge + "&client_type=web&risk_type=ai&lang=zh&callback=geetest_" + str(
|
||||||
|
round(time.time() * 1000))
|
||||||
|
res = requests.get(url).text
|
||||||
|
res = json.loads(res[res.index("(") + 1:res.rindex(")")])
|
||||||
|
lot_number = res['data']['lot_number']
|
||||||
|
detail_time = res['data']["pow_detail"]["datetime"]
|
||||||
|
with open('jiyan.js', 'r', encoding='utf-8') as f:
|
||||||
|
js = execjs.compile(f.read())
|
||||||
|
key = js.call('get_key')
|
||||||
|
w = js.call('get_w', captchaId, lot_number, detail_time)
|
||||||
|
url = "https://gcaptcha4.geetest.com/verify"
|
||||||
|
params = {
|
||||||
|
"callback": "geetest_" + str(round(time.time() * 1000)),
|
||||||
|
"captcha_id": captchaId,
|
||||||
|
"client_type": "web",
|
||||||
|
"lot_number": lot_number,
|
||||||
|
"risk_type": "ai",
|
||||||
|
"payload": res['data']['payload'],
|
||||||
|
"process_token": res['data']['process_token'],
|
||||||
|
"payload_protocol": "1",
|
||||||
|
"pt": "1",
|
||||||
|
"w": w
|
||||||
|
}
|
||||||
|
res = requests.get(url, params=params).text
|
||||||
|
res = json.loads(res[res.index("(") + 1:res.rindex(")")])
|
||||||
|
print('fullpage4:',res)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
captchaId = get_captchaId()
|
||||||
|
challenge = str(uuid.uuid4())
|
||||||
|
main(captchaId, challenge)
|
BIN
geetest4_slide/__pycache__/gap.cpython-38.pyc
Normal file
BIN
geetest4_slide/__pycache__/gap.cpython-38.pyc
Normal file
Binary file not shown.
BIN
geetest4_slide/__pycache__/trace.cpython-38.pyc
Normal file
BIN
geetest4_slide/__pycache__/trace.cpython-38.pyc
Normal file
Binary file not shown.
89
geetest4_slide/gap.py
Normal file
89
geetest4_slide/gap.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
|
||||||
|
class SlideCrack(object):
|
||||||
|
def __init__(self, gap, bg, out):
|
||||||
|
"""
|
||||||
|
init code
|
||||||
|
:param gap: 缺口图片
|
||||||
|
:param bg: 背景图片
|
||||||
|
:param out: 输出图片
|
||||||
|
"""
|
||||||
|
self.gap = gap
|
||||||
|
self.bg = bg
|
||||||
|
self.out = out
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def clear_white(img):
|
||||||
|
# 清除图片的空白区域,这里主要清除滑块的空白
|
||||||
|
img = cv2.imread(img)
|
||||||
|
rows, cols, channel = img.shape
|
||||||
|
min_x = 255
|
||||||
|
min_y = 255
|
||||||
|
max_x = 0
|
||||||
|
max_y = 0
|
||||||
|
for x in range(1, rows):
|
||||||
|
for y in range(1, cols):
|
||||||
|
t = set(img[x, y])
|
||||||
|
if len(t) >= 2:
|
||||||
|
if x <= min_x:
|
||||||
|
min_x = x
|
||||||
|
elif x >= max_x:
|
||||||
|
max_x = x
|
||||||
|
|
||||||
|
if y <= min_y:
|
||||||
|
min_y = y
|
||||||
|
elif y >= max_y:
|
||||||
|
max_y = y
|
||||||
|
img1 = img[min_x:max_x, min_y: max_y]
|
||||||
|
return img1
|
||||||
|
|
||||||
|
def template_match(self, tpl, target):
|
||||||
|
th, tw = tpl.shape[:2]
|
||||||
|
result = cv2.matchTemplate(target, tpl, cv2.TM_CCOEFF_NORMED)
|
||||||
|
# 寻找矩阵(一维数组当作向量,用Mat定义) 中最小值和最大值的位置
|
||||||
|
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
|
||||||
|
tl = max_loc
|
||||||
|
br = (tl[0] + tw, tl[1] + th)
|
||||||
|
# 绘制矩形边框,将匹配区域标注出来
|
||||||
|
# target:目标图像
|
||||||
|
# tl:矩形定点
|
||||||
|
# br:矩形的宽高
|
||||||
|
# (0,0,255):矩形边框颜色
|
||||||
|
# 1:矩形边框大小
|
||||||
|
cv2.rectangle(target, tl, br, (0, 0, 255), 2)
|
||||||
|
cv2.imwrite(self.out, target)
|
||||||
|
return tl[0]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def image_edge_detection(img):
|
||||||
|
edges = cv2.Canny(img, 100, 200)
|
||||||
|
return edges
|
||||||
|
|
||||||
|
def discern(self):
|
||||||
|
img1 = self.clear_white(self.gap)
|
||||||
|
img1 = cv2.cvtColor(img1, cv2.COLOR_RGB2GRAY)
|
||||||
|
slide = self.image_edge_detection(img1)
|
||||||
|
|
||||||
|
back = cv2.imread(self.bg, 0)
|
||||||
|
back = self.image_edge_detection(back)
|
||||||
|
|
||||||
|
slide_pic = cv2.cvtColor(slide, cv2.COLOR_GRAY2RGB)
|
||||||
|
back_pic = cv2.cvtColor(back, cv2.COLOR_GRAY2RGB)
|
||||||
|
x = self.template_match(slide_pic, back_pic)
|
||||||
|
# 输出横坐标, 即 滑块在图片上的位置
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
def get_gap():
|
||||||
|
# 滑块图片
|
||||||
|
image1 = "img/slide.png"
|
||||||
|
# 背景图片
|
||||||
|
image2 = "img/bg.png"
|
||||||
|
|
||||||
|
# 处理结果图片,用红线标注
|
||||||
|
image3 = "img/show_image.png"
|
||||||
|
sc = SlideCrack(image1, image2, image3)
|
||||||
|
return sc.discern()
|
BIN
geetest4_slide/img/bg.png
Normal file
BIN
geetest4_slide/img/bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 84 KiB |
BIN
geetest4_slide/img/show_image.png
Normal file
BIN
geetest4_slide/img/show_image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
BIN
geetest4_slide/img/slide.png
Normal file
BIN
geetest4_slide/img/slide.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
189539
geetest4_slide/img/tracks.json
Normal file
189539
geetest4_slide/img/tracks.json
Normal file
File diff suppressed because it is too large
Load Diff
59
geetest4_slide/jiyan.js
Normal file
59
geetest4_slide/jiyan.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
const NodeRSA = require('node-rsa');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const CryptoJS = require("crypto-js");
|
||||||
|
function get_key() {
|
||||||
|
var s4 = "";
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
s4 = s4 + ((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1);
|
||||||
|
}
|
||||||
|
return s4;
|
||||||
|
}
|
||||||
|
function MD5_Encrypt(word) {
|
||||||
|
return CryptoJS.MD5(word).toString();
|
||||||
|
}
|
||||||
|
function AES_Encrypt(key, word) {
|
||||||
|
var srcs = CryptoJS.enc.Utf8.parse(word);
|
||||||
|
var encrypted = CryptoJS.AES.encrypt(srcs, CryptoJS.enc.Utf8.parse(key), {
|
||||||
|
iv: CryptoJS.enc.Utf8.parse("0000000000000000"),
|
||||||
|
mode: CryptoJS.mode.CBC,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
});
|
||||||
|
return CryptoJS.enc.Hex.stringify(CryptoJS.enc.Base64.parse(encrypted.toString()));
|
||||||
|
}
|
||||||
|
function RSA_encrypt(data) {
|
||||||
|
const public_key_1 = '00C1E3934D1614465B33053E7F48EE4EC87B14B95EF88947713D25EECBFF7E74C7977D02DC1D9451F79DD5D1C10C29ACB6A9B4D6FB7D0A0279B6719E1772565F09AF627715919221AEF91899CAE08C0D686D748B20A3603BE2318CA6BC2B59706592A9219D0BF05C9F65023A21D2330807252AE0066D59CEEFA5F2748EA80BAB81';
|
||||||
|
const public_key_2 = '10001';
|
||||||
|
const public_key = new NodeRSA();
|
||||||
|
public_key.importKey({
|
||||||
|
n: Buffer.from(public_key_1, 'hex'),
|
||||||
|
e: parseInt(public_key_2, 16),
|
||||||
|
}, 'components-public');
|
||||||
|
const encrypted = crypto.publicEncrypt({
|
||||||
|
key: public_key.exportKey('public'),
|
||||||
|
padding: crypto.constants.RSA_PKCS1_PADDING
|
||||||
|
}, Buffer.from(data));
|
||||||
|
return encrypted.toString('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_w(captchaId, lot_number, detail_time, distance, passtime, track) {
|
||||||
|
romdon_key = get_key()
|
||||||
|
pow_msg = "1|0|md5|" + detail_time + "|" + captchaId + "|" + lot_number + "||" + romdon_key
|
||||||
|
xiyu = {
|
||||||
|
"setLeft": distance,
|
||||||
|
"track": track,
|
||||||
|
"passtime": passtime,
|
||||||
|
"userresponse": distance / (.8876 * 340 / 300),
|
||||||
|
"device_id": "D00D",
|
||||||
|
"lot_number": lot_number,
|
||||||
|
"pow_msg": pow_msg,
|
||||||
|
"pow_sign": MD5_Encrypt(pow_msg),
|
||||||
|
"geetest": "captcha",
|
||||||
|
"lang": "zh",
|
||||||
|
"ep": "123",
|
||||||
|
'cuel': '632729377',
|
||||||
|
"em": {"ph": 0, "cp": 0, "ek": "11", "wd": 1, "nt": 0, "si": 0, "sc": 0}
|
||||||
|
}
|
||||||
|
xiyu = JSON.stringify(xiyu).replace(" ", "").replace("'", '"')
|
||||||
|
w = AES_Encrypt(romdon_key, xiyu)+ RSA_encrypt(romdon_key)
|
||||||
|
return w
|
||||||
|
}
|
60
geetest4_slide/mian.py
Normal file
60
geetest4_slide/mian.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import re, requests, time, uuid, execjs,json
|
||||||
|
from lxml import etree
|
||||||
|
from urllib import request
|
||||||
|
from gap import *
|
||||||
|
from trace import *
|
||||||
|
|
||||||
|
|
||||||
|
def get_captchaId():
|
||||||
|
url = "https://www.geetest.com/adaptive-captcha-demo"
|
||||||
|
res = requests.get(url).text
|
||||||
|
HTML = etree.HTML(res)
|
||||||
|
js_url = HTML.xpath("//link[contains(@href, 'adaptive-captcha-demo')]")[0].attrib["href"]
|
||||||
|
res = requests.get("https://www.geetest.com" + js_url).text
|
||||||
|
captchaId = re.search('captchaId:"([0-9a-z]+)"', res).group(1)
|
||||||
|
return captchaId
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(captchaId, challenge):
|
||||||
|
url = "https://gcaptcha4.geetest.com/load?captcha_id=" + captchaId + "&challenge=" + challenge + "&client_type=web&risk_type=slide&pt=1&lang=zho&callback=geetest_" + str(
|
||||||
|
round(time.time() * 1000))
|
||||||
|
res = requests.get(url).text
|
||||||
|
res = json.loads(res[res.index("(") + 1:res.rindex(")")])
|
||||||
|
request.urlretrieve('https://static.geetest.com/' + res['data']['bg'], 'img/bg.png')
|
||||||
|
request.urlretrieve('https://static.geetest.com/' + res['data']['slice'], 'img/slide.png')
|
||||||
|
distance = get_gap()
|
||||||
|
track = get_track(distance)
|
||||||
|
return res, distance, track
|
||||||
|
|
||||||
|
|
||||||
|
def main(captchaId, challenge):
|
||||||
|
res, distance, track = get_image(captchaId, challenge)
|
||||||
|
lot_number = res['data']['lot_number']
|
||||||
|
passtime = track[-1][-1]
|
||||||
|
detail_time = res['data']["pow_detail"]["datetime"]
|
||||||
|
with open('jiyan.js', 'r', encoding='utf-8') as f:
|
||||||
|
js = execjs.compile(f.read())
|
||||||
|
key = js.call('get_key')
|
||||||
|
w = js.call('get_w', captchaId, lot_number, detail_time, distance, passtime, track)
|
||||||
|
url = "https://gcaptcha4.geetest.com/verify"
|
||||||
|
params = {
|
||||||
|
"callback": "geetest_" + str(round(time.time() * 1000)),
|
||||||
|
"captcha_id": captchaId,
|
||||||
|
"client_type": "web",
|
||||||
|
"lot_number": lot_number,
|
||||||
|
"risk_type": "slide",
|
||||||
|
"payload": res['data']['payload'],
|
||||||
|
"process_token": res['data']['process_token'],
|
||||||
|
"payload_protocol": "1",
|
||||||
|
"pt": "1",
|
||||||
|
"w": w
|
||||||
|
}
|
||||||
|
res = requests.get(url, params=params).text
|
||||||
|
res = json.loads(res[res.index("(") + 1:res.rindex(")")])
|
||||||
|
print(res)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
captchaId = get_captchaId()
|
||||||
|
challenge = str(uuid.uuid4())
|
||||||
|
main(captchaId, challenge)
|
33
geetest4_slide/trace.py
Normal file
33
geetest4_slide/trace.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
def __ease_out_expo(x):
|
||||||
|
if x == 1:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 1 - pow(2, -10 * x)
|
||||||
|
def get_track(distance):
|
||||||
|
if not isinstance(distance, int) or distance < 0:
|
||||||
|
raise ValueError(f"distance类型必须是大于等于0的整数: distance: {distance}, type: {type(distance)}")
|
||||||
|
# 初始化轨迹列表
|
||||||
|
slide_track = [[random.randint(20, 60), random.randint(10, 40), 0]]
|
||||||
|
# 共记录count次滑块位置信息
|
||||||
|
count = 30 + int(distance / 2)
|
||||||
|
# 初始化滑动时间
|
||||||
|
t = random.randint(50, 100)
|
||||||
|
# 记录上一次滑动的距离
|
||||||
|
_x = 0
|
||||||
|
_y = 0
|
||||||
|
for i in range(count):
|
||||||
|
# 已滑动的横向距离
|
||||||
|
x = round(__ease_out_expo(i / count) * distance)
|
||||||
|
# 滑动过程消耗的时间
|
||||||
|
t = random.randint(10, 20)
|
||||||
|
if x == _x:
|
||||||
|
continue
|
||||||
|
slide_track.append([x - _x, _y, t])
|
||||||
|
_x = x
|
||||||
|
slide_track.append([0, 0, random.randint(200, 300)])
|
||||||
|
return slide_track
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user