frankyxu 发表于 2019-2-22 13:19

利用selenium和ocr破解点击验证码模拟登录52pojie并自动签到

本帖最后由 frankyxu 于 2019-2-22 14:41 编辑



# 利用selenium和ocr破解文字点击验证码
### hello,下午好,这次给大家带来的是selenium和ocr破解文字点击验证码,希望大家会喜欢,项目采用的是selenium模拟人进行点击和滑动,通过ocr计算出要点击文字的位置,然后利用selenium完成最后的剪辑,主要难点是计算距离,[项目地址](https://github.com/guapier/52pojie)


## 主要用到的技术
- selenium

---

## 项目截图
!(http://cdn.guapier.net/QQ20190222-125335-HD.gifhttps://github.com/guapier/52pojie/blob/master/QQ20190222-125335-HD.gif)
---

## 核心源码 :beers:
```python
# -*- coding: utf-8 -*-
# @Time    : 2018/01/23 10:02
# @AuThor: xuzy
# @Software: PyCharm
# @Function:
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
import time
import base64
import apiutil
import random



class CrackSlider():
    """
    通过浏览器截图,识别验证码中缺口位置,获取需要滑动距离,并模仿人类行为破解滑动验证码
    """

    def __init__(self):
      super(CrackSlider, self).__init__()
      # 实际地址
      self.url = 'https://www.52pojie.cn/member.php?mod=logging&action=login'
      self.driver = webdriver.Chrome()
      self.wait = WebDriverWait(self.driver, 30)
      self.zoom = 1

    def open(self):
      self.driver.get(self.url)
      self.driver.maximize_window()

    def recognize_image(self):

      #https://ai.qq.com/product/ocr.shtml#identify优图ocr地址,免费申请
      app_id = 'appid'
      app_key = 'appkey'
      with open('./captcha.jpg', 'rb') as bin_data:
            image_data = bin_data.read()

      ai_obj = apiutil.AiPlat(app_id, app_key)

      print('----------------------SEND REQ----------------------')
      rsp = ai_obj.getOcrGeneralocr(image_data)
      print(rsp)
      return rsp

    def cal_location(self, word, rsp):
      try:
            if rsp['ret'] == 0:
                for i in rsp['data']['item_list']:
                  result = i['itemstring'].find(word)
                  if result == -1:
                        continue
                  else:
                        x = i['itemcoord']['x']
                        y = i['itemcoord']['y']
                        width = i['itemcoord']['width']
                        height = i['itemcoord']['height']

                        location_x = int(x + (width / 4) * (result + 0.5))
                        location_y = int(y + height / 2)

                        return int(location_x * 23 / 20), int(location_y * 23 / 20)

                return 50, 50
      except Exception as e:
            print(e)
            return 100, 100

    def get_tracks(self, distance):
      v = 0
      t = random.uniform(0.2, 0.3)
      forward_tracks = []
      current = 0
      mid = distance * 3 / 5
      while current < distance:
            if current < mid:
                a = 2
            else:
                a = -3
            s = v * t + 0.5 * a * (t ** 2)
            v = v + a * t
            current += s
            forward_tracks.append(round(s))

      return {'forward_tracks': forward_tracks}

    def crack_slider(self):
      try:
            time.sleep(3)
            self.open()
            captcha = 'captcha.jpg'
            time.sleep(1)
            self.driver.find_element_by_xpath('//input[@name="username"]').send_keys('你的用户名')
            time.sleep(1)
            self.driver.find_element_by_xpath('//input[@name="password"]').send_keys('你的密码')

            distance = 260
            tracks = self.get_tracks((distance + 2) * self.zoom)# 对位移的缩放计算

            time.sleep(2)
            # slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'nc_iconfont btn_slide')))
            slider = self.driver.find_element_by_xpath("//*[@id='nc_1_n1z']")

            time.sleep(1)

            ActionChains(self.driver).click_and_hold(slider).perform()

            for track in tracks['forward_tracks']:
                ActionChains(self.driver).move_by_offset(xoffset=track, yoffset=0).perform()

            time.sleep(0.5)

            while True:

                print('进入while循环')
                print('*' * 50)
                # print(location_x,location_y)
                print('*' * 50)
                time.sleep(0.5)
                # self.driver.find_element_by_xpath('//i[@id="nc_1__btn_2"]').click()
                captcha_image = self.driver.find_element_by_xpath('//div[@class="clickCaptcha_img"]/img')
                captcha = captcha_image.get_attribute('src')
                print(captcha)

                # 下载图片
                fh = open("captcha.jpg", "wb")
                fh.write(base64.b64decode(captcha.split(',')))
                fh.close()

                # 获取要识别的文字

                word_ele = self.driver.find_element_by_xpath('//div[@id="nc_1__scale_text"]/i')
                word = word_ele.text.replace('”', '').replace('“', '').strip()

                print('请点击图中的{}字'.format(word))

                # 识别图中的文字
                rsp = self.recognize_image()

                # 计算要点击的文字在图中的位置

                location_x, location_y = self.cal_location(word, rsp)
                print(location_x, location_y)
                ActionChains(self.driver).move_to_element_with_offset(captcha_image, location_x,
                                                                      location_y).click().perform()
                time.sleep(1)
                if '验证通过' in self.driver.page_source:
                  break
                # try:
                #   menu = self.driver.find_element_by_xpath('//a[@class="showmenu"]')
                # except Exception as e:
                #   menu = None
                # if menu:
                #   break

                # 刷新页面
            self.driver.find_element_by_xpath('//button[@name="loginsubmit"]').click()
            time.sleep(2)
            print('已经跳出while循环')
            self.driver.get('https://www.52pojie.cn/home.php?mod=task&do=apply&id=2')
            # qd = WebDriverWait(self.driver, 10).until(EC.visibility_of(self.find_element(by=By.CLASS_NAME, value='qq_bind')))
            #
            # qd.click()
            time.sleep(5)
            self.driver.quit()
      except Exception as e:
            print(e)
            exit(0)

            c.crack_slider()


if __name__ == '__main__':
    c = CrackSlider()
    c.crack_slider()


```
---
## 如何使用

- pip install selenium

- python3 52.py

- 顺便来点热心值呗

frankyxu 发表于 2019-2-22 15:01

tanghengvip 发表于 2019-2-22 14:42
https://www.freebuf.com/articles/web/194628.html
今天正好看到这篇文章~ 楼主的成品就来了。感谢分享。

哈哈哈,你说的这篇文章我也看过,还有一种思路是利用opencv的模板匹配方法来计算距离,你如果有兴趣的话可以自己尝试一下

frankyxu 发表于 2019-2-22 16:21

时空之外 发表于 2019-2-22 16:16
这个优图识别好像不太准确,我换了个百度,依旧不行。还有就是建议self.driver.get(url)和self.maximize_wi ...

这个是基于优图的,返回的数据中有坐标信息,百度的ocr不是太适合,优图的ocr一般三次以内吧

麦迪就是帅 发表于 2019-2-22 13:28

谢谢!!!

左三圈 发表于 2019-2-22 13:41

前排合影,优秀作品~

frankyxu 发表于 2019-2-22 14:11

左三圈 发表于 2019-2-22 13:41
前排合影,优秀作品~

{:1_918:}{:1_918:}{:1_918:},感谢,还有些地方不够完善

tanghengvip 发表于 2019-2-22 14:42

https://www.freebuf.com/articles/web/194628.html
今天正好看到这篇文章~ 楼主的成品就来了。感谢分享。

yuelass 发表于 2019-2-22 15:50

不错 学习学习               

时空之外 发表于 2019-2-22 16:16

本帖最后由 时空之外 于 2019-2-22 16:18 编辑

这个优图识别好像不太准确,我换了个百度,依旧不行。还有就是建议self.driver.get(url)和self.maximize_window互换位置,不然每次加载会被提示挡住拖动按钮

时空之外 发表于 2019-2-22 17:17

frankyxu 发表于 2019-2-22 16:21
这个是基于优图的,返回的数据中有坐标信息,百度的ocr不是太适合,优图的ocr一般三次以内吧

楼主知道selenium怎么过检测嘛{:1_918:}
页: [1] 2 3
查看完整版本: 利用selenium和ocr破解点击验证码模拟登录52pojie并自动签到