最大的问题就是解决登录和验证码,登录之后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)