IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> python环境下browsermobproxy+selenium实现豆瓣模拟登录 -> 正文阅读

[开发测试]python环境下browsermobproxy+selenium实现豆瓣模拟登录

一、实验名称

python环境下browsermobproxy+selenium实现豆瓣模拟登录。

二、基本原理

(一)概述

? 使用selenium模拟打开页面、输入账户密码、点击、滑动等操作,browsermobproxy设置代理抓取包含滑动验证码图像的请求。实验中难点在于滑动验证码的破解。

(二)browsermobproxy

? BrowserMob Proxy允许操作HTTP请求和响应,捕获HTTP内容,并将性能数据导出为HAR文件。按下列教程安装好后即可运行。(https://blog.csdn.net/qq_44315987/article/details/116501955)

? 如下所示例子中result存储了webdriver访问时的请求。

from selenium import webdriver
from browsermobproxy import Server

server = Server(r'D:\python_env\exper4\browsermob-proxy-2.1.4\bin\browsermob-proxy.bat')
server.start()
proxy = server.create_proxy()
print('proxy', proxy.proxy)
chrome_options = Options()
chrome_options.add_argument('--proxy-server={0}'.format(proxy.proxy))
proxy.new_har("douban", options={'captureHeaders': True, 'captureContent': True})
browser.get('https://accounts.douban.com/passport/login_popup?login_source=anony')
result = proxy.har

使用json格式化工具可以查看每一条请求的url。
请添加图片描述

从目标url中可以抓取验证图片。这样处理是因为直接通过元素查找不能找到所需图片。
请添加图片描述

(三)查找缺口位置

? 获取到无缺口的原图、带缺口的图片后,我们需要定位缺口的位置。由于图片中存在一些干扰因素(如下方两张灰度图的上面一张图的上边缘依稀可以看到一些白色的噪点,也就是说两张图不同的部分不止缺口所在位置),直接通过单个像素比较不能准确找到缺口的位置。
请添加图片描述
请添加图片描述

? 下面时我借助卷积神经网络的思想实现的一种图片比较方法。

? 将两个灰度图像对应的矩阵进行相减,同时采取极端的阈值(设为1)将所得图像进行二值化,得到如下图像(白色部分灰度值为255,黑色部分灰度值为0)。

请添加图片描述

然后用一个大小与拼图块相同,元素全为1的卷积核对图像进行类似卷积的操作(即分块求和)。

# seghalf 为 拼图块的边长的一半
# height,width分别为原图的宽和长
core_array = np.zeros((height,width))
step_size = 5 # 步长,减小计算量
for i in range(seghalf,height-seghalf, step_size):
    for j in range(seghalf,width-seghalf, step_size):
        temp_array = minus_pic[i-seghalf:i+seghalf,j-seghalf:j+seghalf]
        core_array[i][j] = np.sum(temp_array)

? 所得结果core_array中最大元素所在位置即为拼图的中心。

(四)滑动操作

? 使用坐标工具对相关位置进行定位,调用Selenium相关鼠标事件即可完成操作。

? 滑动不能过于僵硬,需要模拟人手动滑动过程。

# 模拟人为拖动
def get_track(distance):
    """
    根据偏移量获取移动轨迹
    :param distance: 偏移量
    :return: 移动轨迹
    """
    # 移动轨迹
    track = []
    # 当前位移
    current = 0
    # 减速阈值
    mid = distance * 4 / 5
    # 计算间隔
    t = 0.2
    # 初速度
    v = 0
    while current < distance:
        if current < mid:
            # 加速度为正2
            a = 2
        else:
            # 加速度为负3
            a = -1
        # 初速度v0
        v0 = v
        # 当前速度v = v0 + at
        v = v0 + a * t
        # 移动距离x = v0t + 1/2 * a * t^2
        move = v0 * t + 1 / 2 * a * t * t
        # 当前位移
        current += move
        # 加入轨迹
        track.append(round(move))
    return track

(五)防检测

? 这是后面发现的问题,selenium默认情况下会出现表单无法提交的情况。

请添加图片描述

? 因此也需要设置一些参数将自己隐藏起来,如打开谷歌开发者模式,去取webdriver标识。

# 开发者模式
chrome_options.add_experimental_option('excludeSwitches', ['enable-automation'])
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
    
# 去除webdriver标识
browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
            "source": """
                            Object.defineProperty(navigator, 'webdriver', {
                              get: () => undefined
                            })
                          """
        })

打开开发者模式后,标签栏附近的自动测试提示也消失了。
请添加图片描述

三、具体步骤

1. 导入相关库

import re
import cv2
import time
import requests
import numpy as np
from selenium import webdriver
from browsermobproxy import Server
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options

2.配置代理

# 配置代理
    server = Server(r'D:\python_env\exper4\browsermob-proxy-2.1.4\bin\browsermob-proxy.bat') # bat路径
    server.start()
    proxy = server.create_proxy()
    print('proxy', proxy.proxy)
    chrome_options = Options()
    chrome_options.add_argument('--proxy-server={0}'.format(proxy.proxy))
    proxy.new_har("douban", options={'captureHeaders': True, 'captureContent': True})
    # 防检测
    chrome_options.add_experimental_option('excludeSwitches', ['enable-automation'])
    chrome_options.add_argument("--disable-blink-features=AutomationControlled")

3.打开浏览器访问登录页面

browser = webdriver.Chrome(chrome_options=chrome_options)

# 去掉webdriver标识防检测
browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": """
                            Object.defineProperty(navigator, 'webdriver', {
                              get: () => undefined
                            })
                          """
})
# 打开目标窗口
browser.get('https://accounts.douban.com/passport/login_popup?login_source=anony')
browser.maximize_window()
time.sleep(1)
browser.find_elements(by=By.XPATH,value='//li[@class="account-tab-account"]')[0].click()
time.sleep(1)

username = ''	# 账号
password = ''	# 密码
browser.find_elements(by=By.XPATH,value='//input[@class="account-form-input"]')[0].send_keys(username)  # 输入用户名
browser.find_elements(by=By.XPATH,value='//input[@class="account-form-input password"]')[0].send_keys(password) # 输入密码
browser.find_elements(by=By.XPATH,value='//div[@class="account-form-field-submit "]')[0].click() # 点击登录
time.sleep(sleep_time)
result = proxy.har
# with open('output.txt','w',encoding='utf8') as f:
#     f.write(str(result))
# break
pic_url = None
# 抓取图像url
for entry in result['log']['entries']:
    _url = entry['request']['url']
    # 根据URL找到数据接口
    if "hycdn?" in _url:
        pic_url = _url
        print(pic_url)
        break

# 抓取时尚未发出请求,则重新访问抓取
if pic_url is None:
    print('no_data')
    sleep_time += 1
    browser.close()
    continue
# 停止代理
server.stop()

成功输入账号密码,打开验证码界面:

在这里插入图片描述

同时获得pic_url如下:

https://t.captcha.qq.com/hycdn?index=1&image=937625773573401088?aid=2044348370&sess=s0BPJKOhJ6Ui0xiAFkP8g9qIYCeMDfa0j2uQUgwwb0AT-dzDfRcdgckFzZL0EeTHhTKk8cCf0pHiyGsz2es72seJrNody8vV65ESofx0b2w8Y4WVkARtWmUjanuJjIoyMK2tYrqfU1A9mYcf7Ekv64ycewssZ_RW-nYJfiWuG6wkqqZ50ZcfrLuDaxsXDVkff1BUkUOV2HBjTRyGbVO08Gy7azDs8_sBJI7_KVuDQWoL8zuJVl6sDw_WkXL-5h3XnNirWtKA0Yf5tRT0MfAOW0fMXmbuCGNJ5ljszCluWuHJXxUME_O9R59g

4.将验证图片保存到本地

? 使用正则表达式对url关键位置字符进行替换得到三张图的url。使用requests库访问后将返回值保存到本地。

# 分别获取三张图片
origin_pic = re.sub('img_index=\d&','img_index=0&',pic_url)
unfull_pic = re.sub('img_index=\d&','img_index=1&',pic_url)
seg_pic = re.sub('img_index=\d&','img_index=2&',pic_url)

# 保存原图
response = requests.get(origin_pic)
with open('origin.jpg','wb') as f:
    f.write(response.content)

# 保存带缺口的图片
response = requests.get(unfull_pic)
with open('unfull.jpg','wb') as f:
    f.write(response.content)

# 保存缺口图片
response = requests.get(seg_pic)
with open('seg.jpg','wb') as f:
    f.write(response.content)

5.查找缺口位置

# 打开灰度图像origin = cv2.imread('origin.jpg',cv2.IMREAD_GRAYSCALE)unfull = cv2.imread('unfull.jpg',cv2.IMREAD_GRAYSCALE)seg = cv2.imread('seg.jpg',cv2.IMREAD_GRAYSCALE)height,width = origin.shape # 图像大小segheight = 114/171*136     # 拼图块中央部分大小seghalf = int(segheight/2)  # 拼图块大小的一半rate = 282/width            # 网页中图片与下载图片的比例# 求minus_pic = np.array(origin)-np.array(unfull)# 二值化m, n = minus_pic.shapefor i in range(m):    for j in range(n):        if minus_pic[i][j] > 0:            minus_pic[i][j] = 255cv2.imwrite('minus.jpg',minus_pic)core_array = np.zeros((height,width))# 依次计算每个窗口灰度值的和step_size = 5for i in range(seghalf,height-seghalf, step_size):    for j in range(seghalf,width-seghalf, step_size):        temp_array = minus_pic[i-seghalf:i+seghalf,j-seghalf:j+seghalf]        core_array[i][j] = np.sum(temp_array)# 获得最大值索引m, n = core_array.shapeindex = int(core_array.argmax())y_move = int(index / n)x_move = index % nprint(n,m)print(x_move,y_move)

结果如下所示(上方为图片尺寸,下方为缺口位置):

请添加图片描述

与二图相减并二值化处理的图像进行对比,发现几乎一致。

请添加图片描述

6.根据坐标对滑块进行拖动

# 网页中图片与下载图片的比例rate = 282/width            # 滑块目标位置x_target = x_move*rate + 12/375*298y_target = y_base# 移动到滑动条起始位置webdriver.ActionChains(browser).move_by_offset(x_base,y_base).click().perform()distance = x_target-x_base# 模仿人类行为缓慢滑动tracks = get_track(distance)tracks.append(-(sum(tracks)-distance)) # 补正操作for track in tracks: 	    webdriver.ActionChains(browser).move_by_offset(track,0).perform()webdriver.ActionChains(browser).click().perform()

截图快捷键捕捉不到成功的瞬间,就用手机相机拍摄图片了。

在这里插入图片描述

可以看到验证通过,精准无敌了!

此外尝试登陆次数过多时官网也会对帐号进行检测,需下载App扫码登陆,最近好像一直不行(可能这就是它的营销策略吧)。

请添加图片描述

四、完整代码

加入简单的异常处理后总结完整代码如下

import reimport cv2import timeimport requestsimport numpy as npfrom selenium import webdriverfrom browsermobproxy import Serverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.chrome.options import Options# 帐号密码username = ''password = ''# 模拟人为拖动def get_track(distance):    """    根据偏移量获取移动轨迹    :param distance: 偏移量    :return: 移动轨迹    """    # 移动轨迹    track = []    # 当前位移    current = 0    # 减速阈值    mid = distance * 4 / 5    # 计算间隔    t = 0.2    # 初速度    v = 0    while current < distance:        if current < mid:            # 加速度为正2            a = 2        else:            # 加速度为负3            a = -1        # 初速度v0        v0 = v        # 当前速度v = v0 + at        v = v0 + a * t        # 移动距离x = v0t + 1/2 * a * t^2        move = v0 * t + 1 / 2 * a * t * t        # 当前位移        current += move        # 加入轨迹        track.append(round(move))    return trackif __name__ == '__main__':    # 配置代理    server = Server(r'D:\python_env\exper4\browsermob-proxy-2.1.4\bin\browsermob-proxy.bat')    server.start()    proxy = server.create_proxy()    print('proxy', proxy.proxy)    chrome_options = Options()    chrome_options.add_argument('--proxy-server={0}'.format(proxy.proxy))    # 防检测    chrome_options.add_experimental_option('excludeSwitches', ['enable-automation'])    chrome_options.add_argument("--disable-blink-features=AutomationControlled")    proxy.new_har("douban", options={'captureHeaders': True, 'captureContent': True})    pic_url = None    sleep_time = 6    while not pic_url:        # 打开目标窗口        browser = webdriver.Chrome(chrome_options=chrome_options)        # 去掉webdriver标识防检测        browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {            "source": """                            Object.defineProperty(navigator, 'webdriver', {                              get: () => undefined                            })                          """        })        # browser = webdriver.Chrome()        browser.get('https://accounts.douban.com/passport/login_popup?login_source=anony')        # browser.get('https://accounts.douban.com/passport/login?redir=https://accounts.douban.com/')        browser.maximize_window()        time.sleep(1)        browser.find_elements(by=By.XPATH,value='//li[@class="account-tab-account"]')[0].click()        time.sleep(1)        browser.find_elements(by=By.XPATH,value='//input[@class="account-form-input"]')[0].send_keys(username)  # 输入用户名        time.sleep(2)        browser.find_elements(by=By.XPATH,value='//input[@class="account-form-input password"]')[0].send_keys(password) # 输入密码        time.sleep(2)        browser.find_elements(by=By.XPATH,value='//div[@class="account-form-field-submit "]')[0].click() # 点击登录        time.sleep(sleep_time)        result = proxy.har        # with open('output.txt','w',encoding='utf8') as f:        #     f.write(str(result))        # break        pic_url = None        # 抓取图像url        for entry in result['log']['entries']:            _url = entry['request']['url']            # 根据URL找到数据接口            if "hycdn?" in _url:                pic_url = _url                print(pic_url)                break        # 抓取时尚未发出请求,则重新访问抓取        if pic_url is None:            print('no_data')            sleep_time += 1            browser.close()            continue        # 停止代理        server.stop()    # 分别获取三张图片    origin_pic = re.sub('img_index=\d&','img_index=0&',pic_url)    unfull_pic = re.sub('img_index=\d&','img_index=1&',pic_url)    seg_pic = re.sub('img_index=\d&','img_index=2&',pic_url)    # 保存原图    response = requests.get(origin_pic)    with open('origin.jpg','wb') as f:        f.write(response.content)    # 保存带缺口的图片    response = requests.get(unfull_pic)    with open('unfull.jpg','wb') as f:        f.write(response.content)    # 保存缺口    response = requests.get(seg_pic)    with open('seg.jpg','wb') as f:        f.write(response.content)    # 打开灰度图像    origin = cv2.imread('origin.jpg',cv2.IMREAD_GRAYSCALE)    unfull = cv2.imread('unfull.jpg',cv2.IMREAD_GRAYSCALE)    seg = cv2.imread('seg.jpg',cv2.IMREAD_GRAYSCALE)    height,width = origin.shape # 图像大小    segheight = 114/171*136     # 拼图块中央部分大小    seghalf = int(segheight/2)  # 拼图块大小的一半    rate = 282/width            # 网页中图片与下载图片的比例    # 求    minus_pic = np.array(origin)-np.array(unfull)    # 二值化    m, n = minus_pic.shape    for i in range(m):        for j in range(n):            if minus_pic[i][j] > 0:                minus_pic[i][j] = 255    cv2.imwrite('minus.jpg',minus_pic)    core_array = np.zeros((height,width))    # 依次计算每个窗口灰度值的和    step_size = 5    for i in range(seghalf,height-seghalf, step_size):        for j in range(seghalf,width-seghalf, step_size):            temp_array = minus_pic[i-seghalf:i+seghalf,j-seghalf:j+seghalf]            core_array[i][j] = np.sum(temp_array)    # 获得最大值索引    m, n = core_array.shape    index = int(core_array.argmax())    y_move = int(index / n)    x_move = index % n    print(n,m)    print(x_move,y_move)    # 滑动条起始位置    x_base = 76/375*298    y_base = 287/375*298    print(x_base,y_base)    # 滑块目标位置    x_target = x_move*rate + 12/375*298    y_target = y_base    print(x_target,y_target)    # 移动到滑动条起始位置    webdriver.ActionChains(browser).move_by_offset(x_base,y_base).click().perform()    distance = x_target-x_base    # webdriver.ActionChains(browser).move_by_offset(distance, 0).click().perform()    tracks = get_track(distance)    tracks.append(-(sum(tracks)-distance))    for track in tracks:        webdriver.ActionChains(browser).move_by_offset(track,0).perform()    webdriver.ActionChains(browser).click().perform()    time.sleep(10)

五、实验感受

? 1.实验中验证图片不能直接通过查找元素得到,需要拦截请求做出相应操作,browsermobproxy可以很好地解决这个问题。

? 2.图片比较过程中单纯比较像素点的方法不是很有效,参考卷积神经网络思想使用卷积核对图像进行分块求和可以以相对较高的效率地查找到两张图片的不同区域位置。

? 3.在网页通过坐标进行鼠标事件操作是个令人头疼的问题,出于显示设置及坐标工具显示问题,在选取过程中一般需要通过css显示尺寸和所量得的尺寸进行一个等比缩放。

? 4.即使使用selenium也有被检测的可能。

? 5.打码服务贵有贵的理由。

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-12-16 17:59:12  更:2021-12-16 18:00:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/18 6:38:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码