当前位置:   article > 正文

爬虫-python -综合练习-51job信息-滑块验证-selenium_51job 滑块检测

51job 滑块检测

1.爬51job职位信息

0.头文件

需要用到以下文件

from selenium import webdriver
from selenium.webdriver import Chrome
from selenium.webdriver.common.by import By
import time
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PIL import Image
import csv
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

1.初始化

防止打印一些无用或者显示错误的日志。
wait是为后面wait.until做准备。

# 初始化
# 防止打印一些无用的日志
option = webdriver.ChromeOptions()
option.add_experimental_option("excludeSwitches", ['enable-automation', 'enable-logging'])
web = Chrome(options = option)
# 设置等待超时
wait = WebDriverWait(web, 20)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.页面登陆

这个没什么好说的,打开页面以及输入账号密码点确定。

# 登录
def login():
    web.get(url)
    web.maximize_window() #窗口最大化
    time.sleep(2)
    #登录
    web.find_element(By.ID,'loginname').send_keys('账户')
    web.find_element(By.ID,'password').send_keys('密码')
    web.find_element(By.ID,'isread_em').click()
    web.find_element(By.ID,'login_btn_withPwd').click()
    time.sleep(2)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3.滑块验证

重点的来了,滑块验证需要分成两部分,
第一部分为将验证滑块的图片的,带缺口图片和完整背景图片保存。
第二部分比对这两张图片,并计算缺口位置距图片左边界的距离,
第三部分为模拟人工滑动滑块。
1.保存带缺口图片和完整背景图片
这里保存了四张图片,其中51job_slice是没有用的,51job图片是为后面处理可以图片截取部分。
其中1.25系数是将图片与网页上原图做对比后得出的系数。
设置可见与不可见,对应网站更新后的代码内,验证图片的路径,可以通过浏览器工具获得,类似这样验证码这里是不变的,所以可以直接复制。

#对某元素截图   
def save_pic(obj,name):
    try:
        pic_url=web.save_screenshot('.\\51job.png')
        print("%s:截图成功!" % pic_url)
        
        #获取元素位置信息
        left = obj.location['x']*1.25  #自己通过原图与实际图片对比得出的系数
        top = obj.location['y']*1.25
        right = left + obj.size['width']*1.25
        bottom = top + obj.size['height']*1.25
        
        print('图:'+name)
        print('Left %s' % left)
        print('Top %s' % top)
        print('Right %s' % right)
        print('Bottom %s' % bottom)
        print('')
         
        im = Image.open('.\\51job.png')
        im = im.crop((left, top, right, bottom))    #元素裁剪
        file_name='51job_'+name+'.png'
        im.save(file_name)    #元素截图
    except BaseException as msg:
        print("%s:截图失败!" % msg)
#设置元素可见    
def show_element(element):
    web.execute_script("arguments[0].style=arguments[1]",element,"display: block;")
#设置元素不可见
def hide_element(element):
    web.execute_script("arguments[0].style=arguments[1]",element,"display: none;")
def cut():
    c_background=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'canvas.geetest_canvas_bg.geetest_absolute')))
    c_slice=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'canvas.geetest_canvas_slice.geetest_absolute')))
    c_full_bg=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'canvas.geetest_canvas_fullbg.geetest_fade.geetest_absolute')))
    hide_element(c_slice)
    save_pic(c_background,'back') #隐藏滑块
    show_element(c_slice)
    save_pic(c_slice,'slice') #所有的
    show_element(c_full_bg)
    save_pic(c_full_bg,'full') #隐藏所有的
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

2.计算移动距离


将图一中1移动到到2 相当于比对缺口图与背景图的从左向右第一个不同的点的位置。

# 判断像素是否相同
def is_pixel_equal(bg_image, fullbg_image, x, y):
    """
    :param bg_image: (Image)缺口图片
    :param fullbg_image: (Image)完整图片
    :param x: (Int)位置x
    :param y: (Int)位置y
    :return: (Boolean)像素是否相同
    """
    # 获取缺口图片的像素点(按照RGB格式)
    bg_pixel = bg_image.load()[x, y]
    # 获取完整图片的像素点(按照RGB格式)
    fullbg_pixel = fullbg_image.load()[x, y]
    # 设置一个判定值,像素值之差超过判定值则认为该像素不相同
    threshold = 20
    # 判断像素的各个颜色之差,abs()用于取绝对值
    if (abs(bg_pixel[0] - fullbg_pixel[0] < threshold) and abs(bg_pixel[1] - fullbg_pixel[1] < threshold) and abs(bg_pixel[2] - fullbg_pixel[2] < threshold)):
        # 如果差值在判断值之内,返回是相同像素
        return True
    else:
        # 如果差值在判断值之外,返回不是相同像素
        return False
# 计算滑块移动距离
def get_distance(bg_image, fullbg_image):
    '''
    :param bg_image: (Image)缺口图片
    :param fullbg_image: (Image)完整图片
    :return: (Int)缺口离滑块的距离
    '''
    # 滑块的初始位置
    distance = 60
    # 遍历像素点横坐标
    for i in range(distance, fullbg_image.size[0]):
        # 遍历像素点纵坐标
        for j in range(fullbg_image.size[1]):
            # 如果不是相同像素
            if not is_pixel_equal(fullbg_image, bg_image, i, j):
                # 返回此时横轴坐标就是滑块需要移动的距离
                return i
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

3.模拟现实移动滑块
这里的滑块会验证是否为机器操作,如果被发现了,即使移动位置正确,也会出现‘怪物吃了拼图 请重试’。
其实这里很简单,主要看滑块移动时候,是否在中间断开,其实可以一下子拉到某个位置,然后稍微调整。

#破解滑块验证
def slide():
    distance=get_distance(Image.open('.\\51job_back.png'),Image.open('.\\51job_full.png'))/1.25   #要将原图与实际图对比的系数除掉
    try:
        slider=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'div.geetest_slider_button')))  #找到滑块
        if slider:
            print("====有滑块验证=====")
            action_chains = webdriver.ActionChains(web)
            # 点击,准备拖拽
            action_chains.click_and_hold(slider)
            action_chains.pause(0.2)
            action_chains.move_by_offset(distance-10,0)
            action_chains.pause(0.6)
            action_chains.move_by_offset(10,0)   #添加修正过程
            action_chains.pause(0.6)
            action_chains.release()
            action_chains.perform()   # 释放滑块
            time.sleep(5)
        else:
            print("===没有滑块验证===")
    except Exception as e:
        print("==="+str(e))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

4.获取网站的职位信息

获取分为两步,第一步定位到某个页page_nums=1,第二步将网页内的有用数据保存。
将page_nums变大,同时点击下一页。

#取的页面职位信息
def get_data(page_nums):
    lists = web.find_element(By.CLASS_NAME,'j_joblist').find_elements(By.CLASS_NAME,'e')
    with open('data_job.csv',mode='a',encoding='utf-8',newline='') as f:
        csv_w = csv.writer(f)
        for list in lists:  
            job_name = list.find_element(By.CLASS_NAME,'jname').text
            com_name = list.find_element(By.CLASS_NAME,'cname').text
            sal_val = list.find_element(By.CLASS_NAME,'sal').text
            din = list.find_element(By.CLASS_NAME,'d').text 
            csv_w.writerow([job_name,com_name,sal_val,din])
    print(page_nums,'over!!')
#搜索框输入python开始搜索前max_page页面
def search(input_str,max_page):
    web.find_element(By.ID,'kwdselectid').send_keys(input_str)
    web.find_element(By.XPATH,'/html/body/div[3]/div/div[1]/div/button').click()
    time.sleep(0.5)
    page_nums = 1
    while page_nums<=max_page:
        get_data(page_nums)
        page_nums+=1
        web.find_element(By.CLASS_NAME,'p_in').click()
        time.sleep(1)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

2.爬51job页面-利用selenium-破解滑块验证-完整代码

from selenium import webdriver
from selenium.webdriver import Chrome
from selenium.webdriver.common.by import By
import time
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PIL import Image
import csv
# 初始化
# 防止打印一些无用的日志
option = webdriver.ChromeOptions()
option.add_experimental_option("excludeSwitches", ['enable-automation', 'enable-logging'])
web = Chrome(options = option)
# 设置等待超时
wait = WebDriverWait(web, 20)

# 登录
def login():
    web.get(url)
    web.maximize_window() #窗口最大化
    time.sleep(2)
    #登录
    web.find_element(By.ID,'loginname').send_keys('账号')
    web.find_element(By.ID,'password').send_keys('密码')
    web.find_element(By.ID,'isread_em').click()
    web.find_element(By.ID,'login_btn_withPwd').click()
    time.sleep(2)
#对某元素截图   
def save_pic(obj,name):
    try:
        pic_url=web.save_screenshot('.\\51job.png')
        print("%s:截图成功!" % pic_url)
        
        #获取元素位置信息
        left = obj.location['x']*1.25  #自己通过原图与实际图片对比得出的系数
        top = obj.location['y']*1.25
        right = left + obj.size['width']*1.25
        bottom = top + obj.size['height']*1.25
        
        print('图:'+name)
        print('Left %s' % left)
        print('Top %s' % top)
        print('Right %s' % right)
        print('Bottom %s' % bottom)
        print('')
         
        im = Image.open('.\\51job.png')
        im = im.crop((left, top, right, bottom))    #元素裁剪
        file_name='51job_'+name+'.png'
        im.save(file_name)    #元素截图
    except BaseException as msg:
        print("%s:截图失败!" % msg)
#设置元素可见    
def show_element(element):
    web.execute_script("arguments[0].style=arguments[1]",element,"display: block;")
#设置元素不可见
def hide_element(element):
    web.execute_script("arguments[0].style=arguments[1]",element,"display: none;")
def cut():
    c_background=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'canvas.geetest_canvas_bg.geetest_absolute')))
    c_slice=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'canvas.geetest_canvas_slice.geetest_absolute')))
    c_full_bg=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'canvas.geetest_canvas_fullbg.geetest_fade.geetest_absolute')))
    hide_element(c_slice)
    save_pic(c_background,'back') #隐藏滑块
    show_element(c_slice)
    save_pic(c_slice,'slice') #所有的
    show_element(c_full_bg)
    save_pic(c_full_bg,'full') #隐藏所有的
# 判断像素是否相同
def is_pixel_equal(bg_image, fullbg_image, x, y):
    """
    :param bg_image: (Image)缺口图片
    :param fullbg_image: (Image)完整图片
    :param x: (Int)位置x
    :param y: (Int)位置y
    :return: (Boolean)像素是否相同
    """
    # 获取缺口图片的像素点(按照RGB格式)
    bg_pixel = bg_image.load()[x, y]
    # 获取完整图片的像素点(按照RGB格式)
    fullbg_pixel = fullbg_image.load()[x, y]
    # 设置一个判定值,像素值之差超过判定值则认为该像素不相同
    threshold = 20
    # 判断像素的各个颜色之差,abs()用于取绝对值
    if (abs(bg_pixel[0] - fullbg_pixel[0] < threshold) and abs(bg_pixel[1] - fullbg_pixel[1] < threshold) and abs(bg_pixel[2] - fullbg_pixel[2] < threshold)):
        # 如果差值在判断值之内,返回是相同像素
        return True
    else:
        # 如果差值在判断值之外,返回不是相同像素
        return False
# 计算滑块移动距离
def get_distance(bg_image, fullbg_image):
    '''
    :param bg_image: (Image)缺口图片
    :param fullbg_image: (Image)完整图片
    :return: (Int)缺口离滑块的距离
    '''
    # 滑块的初始位置
    distance = 60
    # 遍历像素点横坐标
    for i in range(distance, fullbg_image.size[0]):
        # 遍历像素点纵坐标
        for j in range(fullbg_image.size[1]):
            # 如果不是相同像素
            if not is_pixel_equal(fullbg_image, bg_image, i, j):
                # 返回此时横轴坐标就是滑块需要移动的距离
                return i
#破解滑块验证
def slide():
    distance=get_distance(Image.open('.\\51job_back.png'),Image.open('.\\51job_full.png'))/1.25   #要将原图与实际图对比的系数除掉
    try:
        slider=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'div.geetest_slider_button')))  #找到滑块
        if slider:
            print("====有滑块验证=====")
            action_chains = webdriver.ActionChains(web)
            # 点击,准备拖拽
            action_chains.click_and_hold(slider)
            action_chains.pause(0.2)
            action_chains.move_by_offset(distance-10,0)
            action_chains.pause(0.6)
            action_chains.move_by_offset(10,0)   #添加修正过程
            action_chains.pause(0.6)
            action_chains.release()
            action_chains.perform()   # 释放滑块
            time.sleep(5)
        else:
            print("===没有滑块验证===")
    except Exception as e:
        print("==="+str(e))
#取的页面职位信息
def get_data(page_nums):
    lists = web.find_element(By.CLASS_NAME,'j_joblist').find_elements(By.CLASS_NAME,'e')
    with open('data_job.csv',mode='a',encoding='utf-8',newline='') as f:
        csv_w = csv.writer(f)
        for list in lists:  
            job_name = list.find_element(By.CLASS_NAME,'jname').text
            com_name = list.find_element(By.CLASS_NAME,'cname').text
            sal_val = list.find_element(By.CLASS_NAME,'sal').text
            din = list.find_element(By.CLASS_NAME,'d').text 
            csv_w.writerow([job_name,com_name,sal_val,din])
    print(page_nums,'over!!')
#搜索框输入python开始搜索前max_page页面
def search(input_str,max_page):
    web.find_element(By.ID,'kwdselectid').send_keys(input_str)
    web.find_element(By.XPATH,'/html/body/div[3]/div/div[1]/div/button').click()
    time.sleep(0.5)
    page_nums = 1
    while page_nums<=max_page:
        get_data(page_nums)
        page_nums+=1
        web.find_element(By.CLASS_NAME,'p_in').click()
        time.sleep(1)

if __name__=='__main__':
    url = 'https://login.51job.com/login.php?loginway=0&isjump=0&lang=c&from_domain=i&url=http%3A%2F%2Fwww.51job.com%2F'
    login()
    cut()
    slide()
    search('python',10)
    web.close()


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/696058
推荐阅读
相关标签
  

闽ICP备14008679号