赞
踩
需要用到以下文件
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
防止打印一些无用或者显示错误的日志。
wait是为后面wait.until做准备。
# 初始化
# 防止打印一些无用的日志
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)
重点的来了,滑块验证需要分成两部分,
第一部分为将验证滑块的图片的,带缺口图片和完整背景图片保存。
第二部分比对这两张图片,并计算缺口位置距图片左边界的距离,
第三部分为模拟人工滑动滑块。
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') #隐藏所有的
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
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))
获取分为两步,第一步定位到某个页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)
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()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。