python爬虫-滑动验证码
1. 滑动验证码
说到滑动验证码,一定一定要提某验,虽然说市面上关于滑动验证码的产品有很多,但是某验的地位就像 10 年前脑白金在保健品市场的地位一样,业界标杆啊。
它越牛逼,市场上用它做防护的网站也越多,像国家企业信用信息公示系统、B 站、京东等等。
像某验的解决方案也有很多,不过原理大同小异。
1.1 简单滑动验证码
目标网址:https://member.zjtcn.com/common/login.html
一般来说我们与页面的交互可以使用
Webelement的方法来进行点击等操作。
但是,有时候我们需要一些更复杂的动作,类似于拖动,双击,长按等等。
这时候就需要用到我们的
Action Chains(动作链)了。
2. 极验验证
极验官网:http://www.geetest.com/
现在极验验证码已经更新到了 3.0 版本,截至 2017 年 7 月全球已有十六万家企业正在使用极验,每天服务响应超过四亿次,广泛应用于直播视频、金融服务、电子商务、游戏娱乐、政府企业等各大类型网站
对于这类验证,如果我们直接模拟表单请求,繁琐的认证参数与认证流程会让你蛋碎一地,我们可以用selenium驱动浏览器来解决这个问题,大致分为以下几个步骤
1、输入用户名,密码
2、点击按钮验证,弹出没有缺口的图
3、获得没有缺口的图片
4、点击滑动按钮,弹出有缺口的图
5、获得有缺口的图片
6、对比两张图片,找出缺口,即滑动的位移
7、按照人的行为行为习惯,把总位移切成一段段小的位移
8、按照位移移动
9、完成登录
步骤大致是将缺口图和原图进行对比获取缺口的横坐标,并使用计算完成拖动轨迹模拟,之后使用 selenium 按照轨迹滑动完成缺口的拼接。
这一类方法的优点是门槛低,原理简单,缺点是完成滑动耗时较长,成功率无法估计(同一轨迹计算规则使用多次后成功率迅速下降)
2.1 滑动验证
目标网址:http://www.cnbaowen.net/api/geetest
位移移动相当于匀变速直线运动,类似于小汽车从起点开始运行到终点的过程(首先为匀加速,然后再匀减速)。
其中a为加速度,且为恒量(即单位时间内的加速度是不变的),t为时间
2.1.1 获取图片
def get_image(driver, div_path): """ 下载无序的图片 获得所有图片的偏移值 :param driver: 传入浏览器对象 :param div_path: 根据xpath提取图片,传入xpath规则 :return: 返回一个文件缓存对象 和 图片的偏移值 """ time.sleep(2) # 强制等待两秒 background_images = driver.find_elements_by_xpath(div_path) # 根据xpath语法提取所有图片所在的标签 location_list = [] # 定义一个空列表,后期存放所有图片的偏移值信息 for background_image in background_images: # 循环遍历出 background_images 里面所有提取出来的图片标签 location = {} # 定义一个空字典,后期以键值对的形式记录一张图片的偏移量 result = re.findall('background-image: url\("(.*?)"\); background-position: (.*?)px (.*?)px;', background_image.get_attribute('style')) # 根据每一个图片对应的标签, # 提取图片的[url地址][第一个偏移量][第二个偏移量] # 匹配到的结果是一个列表, 列表里面的元素是一个元组,元组里面有三个对应的匹配结果 location['x'] = int(result[0][1]) # 第一个偏移量用 x 做字典的第一个键 location['y'] = int(result[0][2]) # 第二个偏移量用 y 做字典的第二个键 image_url = result[0][0] # 取出匹配结果中的图片的url地址,后期需要下载 location_list.append(location) # 将当前所有图片偏移值信息添加到 location_list 列表中记录 image_url = image_url.replace('webp', 'jpg') # 把图片链接地址的尾缀由 webp 替换成 jpg # '替换url http://static.geetest.com/pictures/gt/579066de6/579066de6.webp' image_result = requests.get(image_url).content # 请求图片数据 # with open('1.jpg','wb') as f: # f.write(image_result) # 是一张无序的图片 image_file = BytesIO(image_result) # 使用 IO 模块中的 BytesIO模块,把请求的到的图片加载到系统缓存区 # image = merge_image(image_file, location_list) return image_file, location_list # 返回缓存的文件对象 和 所有图片的偏移值信息
2.1.2 对图片进行处理
def merge_image(image_file, location_list): """ 拼接图片 :param image_file: :param location_list: :return: """ im = Image.open(image_file) im.save('code.jpg') new_im = Image.new('RGB', (260, 116)) # 把无序的图片 切成52张小图片 im_list_upper = [] im_list_down = [] # print(location_list) for location in location_list: # print(location['y']) if location['y'] == -58: # 上半边 im_list_upper.append(im.crop((abs(location['x']), 58, abs(location['x']) + 10, 116))) if location['y'] == 0: # 下半边 im_list_down.append(im.crop((abs(location['x']), 0, abs(location['x']) + 10, 58))) x_offset = 0 for im in im_list_upper: new_im.paste(im, (x_offset, 0)) # 把小图片放到 新的空白图片上 x_offset += im.size[0] x_offset = 0 for im in im_list_down: new_im.paste(im, (x_offset, 58)) x_offset += im.size[0] new_im.show() return new_im
2.1.3 计算移动距离
def get_distance(image1, image2): """ 拿到滑动验证码需要移动的距离 :param image1:没有缺口的图片对象 :param image2:带缺口的图片对象 :return:需要移动的距离 """ # print('size', image1.size) threshold = 50 for i in range(0, image1.size[0]): # 260 for j in range(0, image1.size[1]): # 160 pixel1 = image1.getpixel((i, j)) pixel2 = image2.getpixel((i, j)) res_R = abs(pixel1[0] - pixel2[0]) # 计算RGB差 res_G = abs(pixel1[1] - pixel2[1]) # 计算RGB差 res_B = abs(pixel1[2] - pixel2[2]) # 计算RGB差 if res_R > threshold and res_G > threshold and res_B > threshold: return i # 需要移动的距离
2.1.4 获取移动轨迹
def get_track(distance): ''' 拿到移动轨迹,模仿人的滑动行为,先匀加速后匀减速 匀变速运动基本公式: ① v=v0+at ② s=v0t+(1/2)at² ③ v²-v0²=2as :param distance: 需要移动的距离 :return: 存放每0.2秒移动的距离 ''' # 初速度 v = 0 # 单位时间为0.2s来统计轨迹,轨迹即0.2内的位移 t = 0.2 # 位移/轨迹列表,列表内的一个元素代表0.2s的位移 tracks = [] # 当前的位移 current = 0 # 到达mid值开始减速 mid = distance * 7 / 8 distance += 10 # 先滑过一点,最后再反着滑动回来 # a = random.randint(1,3) while current < distance: # 设置速度 if current < mid: # 加速度越小,单位时间的位移越小,模拟的轨迹就越多越详细 a = random.randint(2, 4) # 加速运动 else: a = -random.randint(3, 5) # 减速运动 # 初速度 v0 = v # 0.2秒时间内的位移 s = v0 * t + 0.5 * a * (t ** 2) # 当前的位置 current += s # 添加到轨迹列表 tracks.append(round(s)) # 速度已经达到v,该速度作为下次的初速度 v = v0 + a * t while (total - distance - 10) > 0: # 反着滑动到大概准确位置 tracks.append(-random.randint(2, 3)) total = sum(tracks) return tracks
3. 浏览器使用用户数据
加载 Chrome 用户默认数据绕过登录
们每次打开浏览器做相应操作时,对应的缓存和 cookie 会保存到浏览器默认的路径下,我们先查看个人资料路径,以 chrome 为例,我们在地址栏输入 chrome://version/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TUmcCtmK-1597544200564)(assets/1581676388412.png)]
图中的个人资料路径就是我们需要的,我们去掉后面的 \Default,然后在路径前加上「–user-data-dir=」就拼接出我们要的路径了。
from selenium import webdriver option = webdriver.ChromeOptions() option.add_argument(r'--user-data-dir=C:\Users\xxp\AppData\Local\Google\Chrome\User Data') # 设置成用户自己的数据目录 driver = webdriver.Chrome(chrome_options=option) driver.get('https://www.baidu.com')
我们启动浏览器的时候采用带选项时的启动,这种方式启动浏览器需要注意,运行代码前需要关闭所有的正在运行 chrome 程序,不然会报错。
执行代码运行程序,selenium 自动化启动浏览器后我们会发现我之前保存的书签完整在浏览器上方,个人数据全部都在。
参考:
https://github.com/duziea/Python-imitate-login
_options=option)
driver.get(‘https://www.baidu.com’)
我们启动浏览器的时候采用带选项时的启动,这种方式启动浏览器需要注意,运行代码前需要关闭所有的正在运行 chrome 程序,不然会报错。 执行代码运行程序,selenium 自动化启动浏览器后我们会发现我之前保存的书签完整在浏览器上方,个人数据全部都在。 参考: https://github.com/duziea/Python-imitate-login https://blog.csdn.net/qq_34192032/article/details/101059706
- python输出带有颜色的内容
- Python Celery异步任务队列使用方法解析
- 基于Python pyecharts实现多种图例代码解析
- Python grequests模块使用场景及代码实例
- 基于Python实现下载网易音乐代码实例
- Python如何测试stdout输出
- 零基础学python应该从哪里入手
- Python命名空间及作用域原理实例解析
- Python面向对象实现方法总结
- Python如何设置指定窗口为前台活动窗口
- Python自动发送和收取邮件的方法
- 基于python requests selenium爬取excel vba过程解析
- 利用python将喜欢的csdn文章保存成pdf
- Python 一般的print()格式化输出
- python爬虫练习之用urllib模块来爬取百度贴吧指定内容指定页面的全网页内容,(版本2)
- python测开常见面试题汇总
- Python升级pip和安装numpy、pandas库时遇到的问题及解决办法
- python math库
- python:IndentationError: unindent does not match any outer indentation level、
- Python 函数为什么会默认返回 None?