验证码获取及解加密(模拟人进入网页获取数据)

一.模拟人的登录查看网页获取数据

1.豆瓣登录

网址:http://www.douban.com
使用的技术:

  1. selenium+Chrome 浏览器完成自动登录

  2. 使用ActionChains控制鼠标操作(鼠标按住–鼠标拖动–鼠标释放)

  3. 使用物理知识(加速度)模拟人的拖动轨迹(先加速后减速)

2.代码

# 需求:破解滑块验证码,完成登录

from selenium import webdriver
import time
# 导入动作链
from selenium.webdriver.common.action_chains import ActionChains

# 2. 调用浏览器
driver = webdriver.Chrome(executable_path=r'D:\chrome\chromedriver.exe')  

# 最大化窗口
driver.maximize_window()

# 3. 请求
driver.get(url='https://www.douban.com/')

# time.sleep(3)

# 1. 点击密码登录
# driver.find_element_by_xpath('/html/body/div[1]/div[1]/ul[1]/li[2]').click()
# 出现问题:没有点击到密码登录,而是点击了电影
# 分析,可能的原因:
# 1. 页面没有加载完成就点击(不是因为这个)
# 2. xpath的路径指定到了电影,路径有问题(不是因为这个)
# 电影路径://*[@id="anony-nav"]/div[1]/ul/li[2]
# 3. 是因为iframe标签:在主页面中嵌套一个子页面
# 解决:切入到子页面中
# switch_to.frame(0)   切入到iframe中
# 0代表第一个iframe标签
driver.switch_to.frame(0)
driver.find_element_by_xpath('/html/body/div[1]/div[1]/ul[1]/li[2]').click()

# 查找并输入账号
driver.find_element_by_id('username').send_keys('账号')
# 查找并输入密码
driver.find_element_by_id('password').send_keys('密码')
# 查找并点击登录
driver.find_element_by_xpath('/html/body/div[1]/div[2]/div[1]/div[5]').click()

# 出现滑块验证码
# 移动滑块到指定位置,完成登录

time.sleep(3)

# 1. 获取滑块
# huakuai = driver.find_element_by_id('tcaptcha_drag_thumb')
# print(huakuai)
# 出现问题:没有找到元素
# 1. 可能是程序运行太快,滑块还没有加载完就开始查找,所以,休眠一会儿
# 2. id可能有问题
# 3. 可能是有iframe标签
# 切入到第2个iframe标签中
driver.switch_to.frame(1)
# 再查找滑块
huakuai = driver.find_element_by_id('tcaptcha_drag_thumb')

# 找到滑块后,需要按住并保持不动
# click_and_hold() 点击并保持点击状态
# on_element:将此状态加载到哪一个元素身上
# perform():执行
ActionChains(driver).click_and_hold(on_element=huakuai).perform()

# 拖动滑块
# move_by_offset()  移动
# xoffset:横向移动距离
# yoffset:纵向移动距离
ActionChains(driver).move_by_offset(xoffset=76,yoffset=0).perform()
# print(huakuai)

# 释放鼠标
# ActionChains(driver).release().perform()

# 出现问题:
# 网络恍惚了一下,请重试
# 原因:识别出是机器人了
# 需要将连续行的移动,转换成间断性的移动,完全模拟出人类的移动操作
# 先匀加速,再匀减速
# 涉及物理知识:a(加速度)

# 定义获取运动轨迹函数
def get_tracks(distance):
    """
    v = v0+at
    x = v0t+1/2at**2
    """
    # 定义存放运动轨迹的列表
    tracks = []
    # 定义初速度
    v = 0
    # 定义单位时间
    t = 0.5
    # 定义匀加速运动和匀减速运动的分界线
    mid = distance * 4/5
    # 定义当前位移
    current = 0
    # 为了一直移动,定义循环
    while current < distance:
        if mid > current:
            a = 2
        else:
            a = -3
        v0 = v
        # 计算位移
        x = v0 * t + 1/2*a*t**2
        # 计算滑块当前位移
        current += x
        # 计算末速度
        v = v0+a*t
        tracks.append(round(x))
    return tracks

tracks = get_tracks(176)
print(tracks)
for track in tracks:
    ActionChains(driver).move_by_offset(xoffset=track,yoffset=0).perform()

time.sleep(1)

# 释放鼠标
ActionChains(driver).release().perform()

二.春秋航空注册

网址:https://account.ch.com/NonRegistrations-Regist


from selenium import webdriver
# 导入配置
from selenium.webdriver.chrome.options import Options
import time
from PIL import Image
# 导入动作链
from selenium.webdriver.common.action_chains import ActionChains

# 定义计算移动距离的函数
def get_difference(image1,image2):
    """
    循环每一个点,计算出对应的像素值
    """
    # 外层循环循环长度
    for i in range(image1.width):
        # 内层循环循环宽度
        for j in range(image1.height):
            # 找出缺口
            if not is_similar(image1,image2,i,j):
                return i

# 定义找出缺口位置的函数
def is_similar(image1,image2,x,y):
    # 计算RGB值
    pixel1 = image1.getpixel((x,y))
    pixel2 = image2.getpixel((x,y))
    # 设置一个容差范围,设置30位容差范围
    if abs(pixel1[0] - pixel2[0]) >30 and abs(pixel1[1] - pixel2[1]) > 30 and abs(pixel1[2] - pixel2[2])>30:
        return False
    return True

# 定义获取运动轨迹函数
def get_tracks(distance):
    """
    v = v0+at
    x = v0t+1/2at**2
    """
    # 定义存放运动轨迹的列表
    tracks = []
    # 定义初速度
    v = 0
    # 定义单位时间
    t = 0.5
    # 定义匀加速运动和匀减速运动的分界线
    mid = distance * 4/5
    # 定义当前位移
    current = 0
    # 为了一直移动,定义循环
    while current < distance:
        if mid > current:
            a = 2
        else:
            a = -3
        v0 = v
        # 计算位移
        x = v0 * t + 1/2*a*t**2
        # 计算滑块当前位移
        current += x
        # 计算末速度
        v = v0+a*t
        tracks.append(round(x))
    return tracks

# 实例化Options对象
options = Options()

# 启动开发者模式
options.add_experimental_option('excludeSwitches',['enable-automation'])
options.add_experimental_option('useAutomationExtension',False)

# 2. 调用浏览器
driver = webdriver.Chrome(executable_path=r'D:\chrome\chromedriver.exe',options=options)

# 将webdriver属性干掉
driver.execute_cdp_cmd(
    "Page.addScriptToEvaluateOnNewDocument",{
        "source":'Object.defineProperty(navigator,"webdriver",{get:()=>undefined})'
    }
)

# 最大化窗口
driver.maximize_window()

# 3. 请求
driver.get(url='https://account.ch.com/NonRegistrations-Regist')

# 输入手机号
driver.find_element_by_xpath('/html/body/div[3]/div[1]/div/div[4]/div[2]/div[1]/input').send_keys('手机号')
time.sleep(2)
# 点击发送验证码
driver.execute_script('document.getElementById("getDynamicPwd").click()')

# 出现滑块验证码
# 发现:每一个滑块移动的距离都是不同的,差距也比较大,所以,不能够写一个固定的移动距离
# 思路:将移动距离计算出来
# 核心:
# 1. 找出无缺口的图片
# 2. 使用有缺口的图片和无缺口的图片做对比
# 目的:获取移动的距离(确定缺口位置)

# 休眠,等待验证码加载
time.sleep(2)

# 截图,获取有缺口图片
driver.save_screenshot('quekou.png')

# 找到图片
element = driver.find_element_by_xpath('//div[@class="geetest_canvas_img geetest_absolute"]')

# 获取图片位置
# loaction:获取元素位置
# size:获取元素大小
print(element.location)
print(element.size)

# 计算截图范围
left = element.location['x']
right = element.location['x'] + element.size['width']
top = element.location['y']
bottom = element.location['y'] + element.size['height']

# 打开图片
im = Image.open('quekou.png')
# 开始局部截图
im = im.crop((left+60,top+10,right,bottom))
im.save('quekou_jubu.png')


# 执行js,显示无缺口图片
driver.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].style="display:block"')

# 截取无缺口图片
driver.save_screenshot('wuque.png')

im = Image.open('wuque.png')
# 开始局部截图
im = im.crop((left+60,top+10,right,bottom))
im.save('wuque_jubu.png')

# 将两张图片进行对比,计算移动距离
wuque_jubu = Image.open('wuque_jubu.png')
quekou_jubu = Image.open('quekou_jubu.png')
distance = get_difference(wuque_jubu,quekou_jubu)

# 获取滑块
huakuai = driver.find_element_by_xpath('//div[@class="geetest_slider_button"]')

ActionChains(driver).click_and_hold(on_element=huakuai).perform()

ActionChains(driver).move_by_offset(xoffset=(distance+54)*0.8,yoffset=0).perform()

tracks = get_tracks((distance+54)*0.2)

for track in tracks:
    ActionChains(driver).move_by_offset(xoffset=track,yoffset=0).perform()

time.sleep(1)

# 释放鼠标
ActionChains(driver).release().perform()

三.有道翻译


# 需求:和百度翻译一样

"""
JS加密:是一个非常常见的加密,大部分的页面都会存在
JS加密一般都是对参数进行加密(比如:salt、sign、token、signature等)
JS加密的分析步骤:
    1. 找到哪些参数在影响数据的获取?
        需要做不同的请求,对比参数,找出不同的参数即可
    2. 找到参数之后,需要查找这些参数从哪里获得的/生成的原理是什么?
        (1) 这些参数可能是通过之前的一些请求传递过来的
        (2) 参数是在某个JS文件中生成的 ---> 找出对应的JS文件,分析JS代码,得到参数生成的原理
"""

# 导入requests
import time,random

import requests,hashlib

# 定义请求头
headers = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Content-Length': '236',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Cookie': 'OUTFOX_SEARCH_USER_ID=986208581@10.108.160.102; JSESSIONID=aaaLdHZ6LoWe0bYE2Fiyx; OUTFOX_SEARCH_USER_ID_NCOO=1300305255.7828863; SESSION_FROM_COOKIE=unknown; ___rl__test__cookies=1606460419940',
'Host': 'fanyi.youdao.com',
'Origin': 'http://fanyi.youdao.com',
'Referer': 'http://fanyi.youdao.com/',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest',
}

# 自定义输入单词
word = input('请输入想要查询的单词:')

# 发现问题:
# 单词只能查询as,其余单词的都不行

"""
var r = function(e) {
        var t = n.md5(navigator.appVersion)
          , r = "" + (new Date).getTime()
          , i = r + parseInt(10 * Math.random(), 10);
        return {
            ts: r,
            bv: t,
            salt: i,
            sign: n.md5("fanyideskweb" + e + i + "]BjuETDhU)zqSxf-=B#7m")
        }
    };
"""

"""
分析salt:
salt: i
i = r + parseInt(10 * Math.random(), 10);
r = "" + (new Date).getTime()

salt = "" + (new Date).getTime() + parseInt(10 * Math.random(), 10)

使用Python代码生成salt
(new Date).getTime() 时间戳的毫秒数 ---> int(round(time.time()*1000))
parseInt(10 * Math.random()) ---> parseInt([0,10))  ---> [0,9]  ---> random.randint(0,9)
"""
salt = str(int(round(time.time()*1000))) + str(random.randint(0,9))


# 获取sign
"""
分析sign:
sign: n.md5("fanyideskweb" + e + i + "]BjuETDhU)zqSxf-=B#7m")
sign: n.md5("fanyideskweb" + word + salt + "]BjuETDhU)zqSxf-=B#7m")
"""
def get_sign(sign):
    # 1. 初始化md5
    md5 = hashlib.md5()
    # 2. 加密
    md5.update(sign.encode('utf-8'))
    # 3. 返回加密数据
    return md5.hexdigest()

sign = get_sign("fanyideskweb" + word + salt + "]BjuETDhU)zqSxf-=B#7m")

# 定义参数字典
data = {
'i': word,
'from': 'AUTO',
'to': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': salt,
'sign': sign,
'lts': str(int(round(time.time()*1000))),
'bv': '1dfc4dfa8627abec379e26d41735b09a',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME',
}

# 发起请求,接收响应
response = requests.post(url='http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule',headers=headers,data=data)
print(response.json())
print(response.json()['translateResult'][0][0]['tgt'])


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值