爬虫通过验证码

爬虫通过验证码

一、验证码

验证码:全自动区分计算机和人类的图灵测试

常见验证码分类:
1、汉字验证码:
在这里插入图片描述
2、数字 + 字母验证码:
在这里插入图片描述
3、算术验证码:
在这里插入图片描述
4、问答式验证码:
在这里插入图片描述
找不到,这是唯一样图

5、坐标型验证码:
爬虫通过验证码_第1张图片
6、九宫格验证码:
爬虫通过验证码_第2张图片
7、滑块验证码:
在这里插入图片描述
8、旋转验证码(蘑菇街):
爬虫通过验证码_第3张图片
9、语音验证码

10、短信验证码

二、使用selenium手动打码

selenium配置ie浏览器教程:https://www.cnblogs.com/misswjr/p/9453566.html

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait # 显示等待对象
from selenium.webdriver.support import expected_conditions as EC # 【某些条件为止】
from selenium.webdriver.common.by import By # 帮我们找【某个页面元素】--定义【定位器】的主要东西


def open():
    '''
    打开链接输入发票信息
    :return:
    '''
    # 1请求url
    driver.get('https://inv-veri.chinatax.gov.cn/')
    # 2输入
    # 技术点:使用显示等待做输入。
    # 发票代码
    wait.until(EC.presence_of_element_located((By.ID, 'fpdm'))).send_keys('044031800311')
    # 发票号码
    wait.until(EC.presence_of_element_located((By.ID, 'fphm'))).send_keys('08744657')
    # 开票日期
    wait.until(EC.presence_of_element_located((By.ID, 'kprq'))).send_keys('20191105')
    # 校验码
    wait.until(EC.presence_of_element_located((By.ID, 'kjje'))).send_keys('859257')


def main():
    # 1、输入发票信息
    open()
    # 2、点击图片加载验证码
    wait.until(EC.presence_of_element_located((By.XPATH, '//td[@id="imgarea"]/div/a'))).click()
    # 技术点二
    yzm = input('请输入验证码')  # 阻塞
    # 3、填入进去yzm
    wait.until(EC.presence_of_element_located((By.ID, 'yzm'))).send_keys(yzm)
    # 4、点击checkfp
    wait.until(EC.element_to_be_clickable((By.ID, 'checkfp'))).click()


if __name__ == '__main__':
    driver = webdriver.Ie()
    # 1、显示等待的对象
    # driver:等待对象监听哪个浏览器
    # 20:最大等待时长
    wait = WebDriverWait(driver, 20)
    main()

三、打码平台

程序将验证码传给打码平台的识别接口,打码平台将验证码发给后端的“佣工”进行识别,并获取识别结果。这样基于此类的人工打码平台,即可实现程序的自动化

超级鹰打码平台: http://www.chaojiying.com/

参照文档调用接口:

import hashlib
import requests


class Chaojiying(object):

    def __init__(self, user, password, soft_id='903750'):
        self.base_data = {
     
            'user': user,
            'pass2': str(hashlib.md5(bytes(password, encoding='utf-8')).hexdigest()),
            'softid': soft_id,
        }
        self.headers = {
     
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
            'Connection': 'keep-alive',
        }

    def post_img(self, im, code_type):
        '''
        调用web接口,获取验证码图片内容
        :param im: 图片的二进制流
        :param code_type:验证码类型
        :return:
        '''
        base_url = 'http://upload.chaojiying.net/Upload/Processing.php'
        data = {
     
            'codetype': code_type,
            # 'file_base64':base64.b64decode(im),
        }
        files = {
     
            'userfile': ('ccc.jpg', im),
        }
        self.base_data.update(data)
        response = requests.post(base_url, data=self.base_data, headers=self.headers, files=files)
        # print(response.json())
        return response.json()['pic_str']

    def post_error(self, pic_id):
        '''
        提交错误,返回题分接口
        :param pic_id: 图片id,从打码平台返回的接口中获取。
        :return:
        '''
        base_url = 'http://upload.chaojiying.net/Upload/ReportError.php'
        data = {
     
            'id': pic_id,
        }
        self.base_data.update(data)
        response = requests.post(base_url, headers=self.headers, data=self.base_data)
        return response.json()['err_str']


if __name__ == '__main__':
    # fp = open('../CheckCode.png','rb')
    fp = open('../code.png', 'rb')
    c = Chaojiying('13016031459', 'Abc1234%')
    # c.post_img(fp,1004)
    c.post_img(fp, 5000)

四、综合项目:RPA 财务机器人之发票真伪验证

RPA简介:

全称为机器人流程自动化(Robotic Process Automation),是一款软件产品

可模拟人在电脑上的不同系统之间操作行为,替代人在电脑前执行具有规律与重复性高的办公流程

对于RPA,也有人将它称为数字劳动力(Digital Labor),因为它擅长把工作流程中的重复操作 进行自动化。繁琐流程自动化是企业数字化转型的重要环节,RPA 能够有效优化传统办公 流程,提升工作效率,间接优化企业劳动资源配置,助力企业数字化升级

RPA价值有哪些?

(1)降低人力资源花费,人力成本节省 30%

(2)解决了繁杂的运行和业务逻辑,可以合理地回应单位专业知识基本建设的必须,解决工作人员变化的风险性

(3)让职工从繁杂、低价值的劳动者中摆脱出去,从业高些价值、创造力的工作中

(4)RPA 机器人可以二十四小时工作,提升单位的服务能力

项目描述:

RPA 财务机器人可以对收付款、审批、纳税申报、对账等多个环节实现 RPA 作业,该 项目主要实现发票真伪验证这个子功能的实现,该功能主要调用百度 AI 财务机器人接口实 现对发票信息的提取,在使用 selenium 进入发票真伪检验的网站对发票真伪进行验证

技术要点:

1、结合第三方平台(百度 AI)进行发票内容识别

2、使用 selenium 进入发票真伪检验的网站对发票真伪进行验证

3、使用打码平台进行发票真伪验证码的识别

实现步骤:

百度 AI 开发平台 URL: https://ai.baidu.com/

步骤一:登录百度 AI 开方平台,输入用户名和密码并登录

再依次选择产品服务—>人工智能—>文字识别

创建应用—>填写应用名称—>选择应用类型—>接口选择(不用选,默认即可)—>文字识别报名(默认的即可)—>填写应用描述—>点击立即创建

创建之后点击技术文档

选择调用方式,根据调用方式获取 access_token,具体参照文档实现

步骤二:在百度 AI 网站找到发票识别的接口信息

(1)创建文字识别应用,通过代码获取 token 和查验发票需要的值

(2)使用 selenium+Chrome 登录发票查验平台,输入上一步获取的数据,查验发票即可

代码实现:

import requests
import base64
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys


def get_token():
    '''
    获取acess_tooken
    :return:
    '''
    # client_id 为官网获取的AK, client_secret 为官网获取的SK
    host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=GHwkcgi0b4m0dlTwYy9xYcTm&client_secret=vm6EeSPe2a4EbhgFyt8wgwHmkLkAQMO9'
    response = requests.get(host)
    if response:
        return response.json()['access_token']


def sb_fapiao():
    '''
    增值税发票识别
    :return:
    '''

    request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/vat_invoice"
    # 二进制方式打开图片文件
    f = open('fapiao2.png', 'rb')
    img = base64.b64encode(f.read())

    params = {
     "image": img}
    access_token = get_token()
    request_url = request_url + "?access_token=" + access_token
    headers = {
     'content-type': 'application/x-www-form-urlencoded'}
    response = requests.post(request_url, data=params, headers=headers)
    if response:
        # print(response.text)
        json_data = response.json()['words_result']
        # 发票代码:InvoiceCode
        InvoiceCode = json_data['InvoiceCode']
        # 发票号码:InvoiceNum
        InvoiceNum = json_data['InvoiceNum']
        # 开票日期:InvoiceDate
        InvoiceDate = json_data['InvoiceDate'].replace('年', '').replace('月', '').replace('日', '')
        # 校验码:CheckCode
        CheckCode = json_data['CheckCode'][-6:]
        # 金额
        AmountInFiguers = json_data['AmountInFiguers']
        return (InvoiceCode, InvoiceNum, InvoiceDate, CheckCode, AmountInFiguers)


def verify_fapiao(infos):
    '''
    验证发票
    :param infos: (InvoiceCode,InvoiceNum,InvoiceDate,CheckCode)
    :return:
    '''
    driver.get('https://inv-veri.chinatax.gov.cn/')
    # 2输入
    # 技术点:使用显示等待做输入。
    # 发票代码
    wait.until(EC.presence_of_element_located((By.ID, 'fpdm'))).send_keys(infos[0])
    # 发票号码
    wait.until(EC.presence_of_element_located((By.ID, 'fphm'))).send_keys(infos[1])
    # 开票日期
    wait.until(EC.presence_of_element_located((By.ID, 'kprq'))).send_keys(infos[2])
    # 校验码
    wait.until(EC.presence_of_element_located((By.ID, 'kjje'))).send_keys(infos[3])
    # 2、点击图片加载验证码
    wait.until(EC.presence_of_element_located((By.XPATH, '//td[@id="imgarea"]/div/a'))).click()
    while True:
        # 清空错误内容
        wait.until(EC.presence_of_element_located((By.ID, 'yzm'))).send_keys(Keys.CONTROL, 'a')
        wait.until(EC.presence_of_element_located((By.ID, 'yzm'))).send_keys(Keys.CONTROL, 'x')
        # 技术点二
        yzm = input('请输入验证码,输入exit继续程序')  # 阻塞
        if yzm == 'exit':
            break
        # 3、填入进去yzm
        wait.until(EC.presence_of_element_located((By.ID, 'yzm'))).send_keys(yzm)
        # 4、点击checkfp
        wait.until(EC.element_to_be_clickable((By.ID, 'checkfp'))).click()

    if infos[-1] in driver.page_source:
        print('发票为正!')
    else:
        print('发票有误!')


if __name__ == '__main__':
    driver = webdriver.Ie()
    wait = WebDriverWait(driver, 20)
    # 调用百度ai接口识别发票
    infos = sb_fapiao()
    # 进行税务平台验证
    verify_fapiao(infos)

五、通过滑动验证码

分析问题:

要点一:滑动多远----就是滑动距离如何计算

从下述图中看出,可以通过测量来进行距离的选择
爬虫通过验证码_第4张图片

要点二:人的滑动操作,先加速后减速的过程

计算机如何做移动:

​ 只需要告诉坐标点位置,计算机只需要在对应点的位置改变起像素点的值即可显示,就是瞬移的

模拟先加速后减速过程:
爬虫通过验证码_第5张图片

(1)、案例:豆瓣登录
import time

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains


def get_tracks(distance):
    '''
    通过加速减速物理模型,讲一个距离划分距离片段。
    :param distance: 距离
    :return: 【1,2,3,4,6,9,6,4,2,1】
    '''
    # 速度:当前速度
    v = 0
    # 定义时间间隔
    # 像素是没有小数。
    t = 0.3
    tracks = []
    # 当前距离:当前已经移动了多少
    current = 0
    mid = 0.6 * distance
    while current < distance:
        # 循环移动
        v0 = v
        if current < mid:
            a = 3
        else:
            a = -2
        s = v0 * t + 0.5 * a * t * t
        tracks.append(round(s))
        current += s
        v = v0 + a * t
    return tracks


def slider_code(driver):
    '''
    通过滑动验证码
    :param driver: 带有滑动验证码的dirver
    :return:
    '''

    print('-----开始处理验证码!------')
    # 切入frame
    driver.switch_to.frame(0)
    # 1、找到滑块
    slider = driver.find_element_by_xpath('//*[@id="tcaptcha_drag_thumb"]')
    print(slider)
    while True:
        # 2、使用鼠标操作点住滑块并且使鼠标悬浮
        # perform:鼠标悬浮
        # click_and_hold:点住并且保持。
        ActionChains(driver).click_and_hold(on_element=slider).perform()
        # 3、计算移动的距离
        # 235
        # move_by_offset:通过偏移量来移动
        ActionChains(driver).move_by_offset(xoffset=100, yoffset=0).perform()
        # 4、移动的过程使用先加速后减速的过程
        tracks = get_tracks(135)
        print(tracks)
        for s in tracks:
            ActionChains(driver).move_by_offset(xoffset=s, yoffset=0).perform()
        # 5、移动到目标位置之后释放鼠标(悬浮释放)
        ActionChains(driver).release().perform()
        # 是否登录成功
        if not driver.title == '登录豆瓣':
            break
        # 点击刷新
        driver.find_element_by_id('reload').click()
        time.sleep(1)
    return True


def main():
    # 1、请求豆瓣登录页面
    driver.get('https://accounts.douban.com/passport/login')
    # 2、点击密码登录
    # 问题:找不到密码登录
    # 原因:有iframe标签
    # 解决:切入iframe
    # driver.switch_to.frame(0)
    wait.until(
        EC.element_to_be_clickable((By.XPATH, '//*[@id="account"]/div[2]/div[2]/div/div[1]/ul[1]/li[2]'))).click()
    # 3、输入用户名和密码
    wait.until(EC.presence_of_element_located((By.ID, 'username'))).send_keys('17673277948')
    wait.until(EC.presence_of_element_located((By.ID, 'password'))).send_keys('zsc17673277948')
    # 4、点击登录
    wait.until(
        EC.element_to_be_clickable((By.XPATH, '//*[@id="account"]/div[2]/div[2]/div/div[2]/div[1]/div[4]/a'))).click()
    time.sleep(2)
    if driver.title == '登录豆瓣':
        # 有验证码
        if slider_code(driver):
            print('登录成功!')
        else:
            print('登录失败!')
    else:
        print('登录成功!')


if __name__ == '__main__':
    driver = webdriver.Chrome()
    wait = WebDriverWait(driver, 20)
    # 最大化
    driver.maximize_window()
    main()
(2)、博客园登录

案列分析:

通过像素对比找到定位:
爬虫通过验证码_第6张图片

如何对比像素点:
爬虫通过验证码_第7张图片

代码实现:

import time
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from PIL import Image


def get_tracks(distance):
    '''
    通过加速减速物理模型,讲一个距离划分距离片段。
    :param distance: 距离
    :return: 【1,2,3,4,6,9,6,4,2,1】
    '''
    # 速度:当前速度
    v = 0
    # 定义时间间隔
    # 像素是没有小数。
    t = 0.3
    tracks = []
    # 当前距离:当前已经移动了多少
    current = 0
    mid = 0.6 * distance
    while current < distance:
        # 循环移动
        v0 = v
        if current < mid:
            a = 2
        else:
            a = -2
        s = v0 * t + 0.5 * a * t * t
        tracks.append(round(s))
        current += s
        v = v0 + a * t
    return tracks


def open():
    '''
    打开浏览器进行用户名和密码填充,出现验证码
    :return:
    '''
    driver.get('https://account.cnblogs.com/signin?returnUrl=https:%2F%2Fwww.cnblogs.com%2F')
    # 填充用户名和密码
    wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="mat-input-0"]'))).send_keys('markshui')
    wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="mat-input-1"]'))).send_keys('zsc17673277948')
    # 点击登录按钮
    wait.until(EC.element_to_be_clickable((By.XPATH,
                                           '/html/body/app-root/div/mat-sidenav-container/mat-sidenav-content/div/div/app-sign-in/app-content-container/mat-card/div/form/div/button'))).click()
    time.sleep(5)


def is_similar(x, y, image1, image2):
    '''
    判断image1和image2在(x,y)位置的像素点是否一致。
    :param x:
    :param y:
    :param image1:
    :param image2:
    :return:
    '''
    pixel1 = image1.getpixel((x, y))
    pixel2 = image2.getpixel((x, y))
    # print(pixel1,pixel2)#(149, 177, 145, 255) (149, 177, 145, 255)
    if abs(pixel1[0] - pixel2[0]) >= 30 and abs(pixel1[1] - pixel2[1]) >= 30 and abs(pixel1[2] - pixel2[2]) >= 30:
        print(pixel1, pixel2)
        return False
    return True


def calculate_distance(image1, image2):
    '''
    通过两张图片,计算起计算点的差异。
    :param image1:
    :param iamge2:
    :return: (x,y)
    '''
    for i in range(190):
        for j in range(150):
            if is_similar(i, j, image1, image2) == False:
                return (i, j)
    return -1


def get_distance():
    '''
    获取滑动的距离
    :return:
    '''
    # 1、全局截屏
    driver.save_screenshot('total_1.png')
    # 2、找到抠图的参数
    yz_element = driver.find_element_by_xpath('/html/body/div[4]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]')
    size = yz_element.size
    location = yz_element.location
    # print(size)#{'height': 160, 'width': 260}
    # print(location)#{'x': 544.5, 'y': 176.984375}
    params_crop = (
        location['x'] + 65, location['y'] + 5, location['x'] + size['width'] - 5, location['y'] + size['height'] - 5)
    # 3、抠图--有缺口局部图片--image_part1.png
    image_t1 = Image.open('total_1.png')
    image_part1 = image_t1.crop(params_crop)
    image_part1.save('image_part1.png')

    # 4、更改js,出现原图--截图得到无缺的图片:image_part2.png
    driver.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].style="display: block"')
    driver.save_screenshot('total_2.png')
    image_t2 = Image.open('total_2.png')

    image_part2 = image_t2.crop(params_crop)
    image_part2.save('image_part2.png')
    driver.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].style="display: none"')

    x, y = calculate_distance(image_part1, image_part2)
    return x + 60


def slider_code():
    '''
    处理滑动验证码
    :return:
    '''
    print('----开始处理验证码------')
    # 1、找到滑块
    slider = wait.until(
        EC.presence_of_element_located((By.XPATH, '/html/body/div[4]/div[2]/div[6]/div/div[1]/div[2]/div[2]')))
    # slider = driver.find_element_by_xpath('/html/body/div[4]/div[2]/div[6]/div/div[1]/div[2]/div[2]')
    print(slider)
    while True:
        # 2、使用鼠标点出滑块并且保持悬浮
        ActionChains(driver).click_and_hold(on_element=slider).perform()
        # 3、开始滑动--长度需要计算---计算滑动的距离
        distance = get_distance()
        print(distance)
        # 4、按照距离进行滑动(先加速后减速)
        ActionChains(driver).move_by_offset(xoffset=distance * 0.2, yoffset=0).perform()
        tracks = get_tracks(distance * 0.8)
        print(tracks)
        for s in tracks:
            ActionChains(driver).move_by_offset(xoffset=s, yoffset=0).perform()
        # #5、释放鼠标。
        time.sleep(1)
        ActionChains(driver).release().perform()
        time.sleep(3)
        if not '用户登录' in driver.title:
            break

        # 点击刷新验证码
        driver.find_element_by_xpath('//a[@class="geetest_refresh_1"]').click()
        time.sleep(2)
    return True


def main():
    # 打开浏览器进行用户名和密码填充,出现验证码
    open()
    # 处理滑动验证码
    if '用户登录' in driver.title:
        if slider_code():
            print('登录成功!')


if __name__ == '__main__':
    driver = webdriver.Chrome()
    driver.maximize_window()
    wait = WebDriverWait(driver, 20)
    main()

你可能感兴趣的:(网络爬虫,python)