Python+selenium控制PTA滑块验证码登录

最大的问题就是解决登录和验证码,登录之后get东西就简单了
直接上源码:

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import requests
import time
import numpy
import cv2
import os

'''
建议网速好一点执行此程序,否则可能会get不到资源导致程序终端或者get到的题目和答案为空
question_list_url   题目列表链接(只能是编程题的链接,其他题型同理判断一下即可我这里没写)
file_name   要保存的文件名,我使用的markdown格式
access_interval     根据网速自定义设置,访问每到题的时间间隔s,访问太快总会被提示,不过我写了出现提示继续访问的逻辑;
'''
def Programming_questions(question_list_url,file_name,access_interval):
    #创建 WebDriver 对象,指明使用chrome浏览器驱动
    web = webdriver.Chrome(r'C:\Program Files\Google\Chrome\Application\chromedriver.exe')
    web.implicitly_wait(5)
    #调用WebDriver 对象的get方法 可以让浏览器打开指定网址
    web.get('https://pintia.cn/auth/login')
    zh = web.find_element_by_xpath('/html/body/div[1]/div[3]/div/div[2]/form/div[1]/div[1]/div/div/div[1]/input')
    mm = web.find_element_by_xpath('/html/body/div[1]/div[3]/div/div[2]/form/div[1]/div[2]/div/div/div[1]/input')

    #在PTA的账号密码:
    zh.send_keys('[email protected]')
    mm.send_keys('xxxx')
    #找到登录按钮并点击
    web.find_element_by_xpath('/html/body/div[1]/div[3]/div/div[2]/form/div[2]/button/div/div').click()

    for i in range(5):
        #等待一会,时间间隔可根据网速调整,验证码加载完成
        time.sleep(3)

        print('当前url:'+web.current_url)
        #如果当前url没变说明验证未通过,循环5(可修改)次重新验证
        if(web.current_url!='https://pintia.cn/auth/login'):
            break
        #bg背景图片
        bg_img_src = web.find_element_by_xpath(
            '/html/body/div[3]/div[2]/div/div/div[2]/div/div[1]/div/div[1]/img[1]').get_attribute('src')
        #front可拖动图片
        front_img_src = web.find_element_by_xpath(
            '/html/body/div[3]/div[2]/div/div/div[2]/div/div[1]/div/div[1]/img[2]').get_attribute('src')

        #保存图片
        with open("bg.jpg", mode="wb") as f:
            f.write(requests.get(bg_img_src).content)
        with open("front.jpg", mode="wb") as f:
            f.write(requests.get(front_img_src).content)

        #将图片加载至内存
        bg = cv2.imread("bg.jpg")
        front = cv2.imread("front.jpg")

        #将背景图片转化为灰度图片,将三原色降维
        bg = cv2.cvtColor(bg, cv2.COLOR_BGR2GRAY)
        #将可滑动图片转化为灰度图片,将三原色降维
        front = cv2.cvtColor(front, cv2.COLOR_BGR2GRAY)
        front = front[front.any(1)]
        #用cv算法匹配精度最高的xy值
        result = cv2.matchTemplate(bg, front, cv2.TM_CCOEFF_NORMED)
        #numpy解析xy,注意xy与实际为相反,x=y,y=x
        x, y = numpy.unravel_index(numpy.argmax(result), result.shape)
        #找到可拖动区域
        div = web.find_element_by_xpath('/html/body/div[3]/div[2]/div/div/div[2]/div/div[2]/div[2]')
        #拖动滑块,以实际相反的y值代替x
        ActionChains(web).drag_and_drop_by_offset(div, xoffset=y // 0.946, yoffset=0).perform()
        #至此成功破解验证码,由于算法问题,准确率不能达到100%,所以加了循环判断

    #要get的题目集列表
    web.get(question_list_url)
    #获取所以题目行
    trp_problems = web.find_elements_by_xpath('/html/body/div/div[3]/div[3]/div/div[3]/table//tbody/tr')
    #存放所有题目的链接
    problems_href=[]
    for tr in trp_problems:
        problems_href.append(tr.find_element_by_xpath('td[3]/a').get_attribute('href'))

    #count用来方便测试,如果中间程序断掉也可以通过修改count的值和条件判断从上次的地方继续执行
    count = 0
    filePro = open(file_name,'a')
    for problem in problems_href:
        if count>=0:
            #访问太快会被弹出提示页面,所以加个循环一直访问(循环次数自定义)
            for i in range(5):
                try:
                    web.get(problem)
                    time.sleep(access_interval)  # 根据网速设置时间间隔,访问太快也会被提示
                    # 获取题目和答案
                    tm_title = web.find_element_by_css_selector("[class='text-center black-3 text-4 font-weight-bold my-3']").text
                    mycode = web.find_element_by_css_selector('textarea').get_attribute('value')
                    print('题目:' + tm_title)
                    print(mycode)
                    #写入格式是markdown文档:题目和代码
                    filePro.write('**' + tm_title + '**\n' + '```\n' + mycode + '\n```' + os.linesep)
                    break   #全部正常执行完说明没有弹出提示页面,退出即可
                except:
                    continue
        count += 1
        print('--------------------------------完成数量'+str(count)+'---------------------------------------')
    filePro.close()


if __name__ == '__main__':
    Programming_questions('https://pintia.cn/problem-sets/1371739727887736832/problems/type/7','test2.md',2.5)

你可能感兴趣的:(PTA,python)