总结:第一次写一个从登陆到模拟观看视频过程,才知道自己基础有多差,涉及的东西又多,有时一个小小 简单问题,困扰很久。把想得起来的过程全记录,算是为下次少点弯路。
新问题 明明软件里面有登陆的COOKIE ,但今天有两个新号来测试,登陆成功,也能打印出来COOKIE ,但在播放时,就显示没有权限观看 ,以为程序被我又改乱了,先试试浏览器看看用户有没有问题,可以正常观看 ,重新用软件试试哪里有问题,结果软件可以模拟了,另外一个新号,没先登陆一下浏览器,也不能播放,但我用的是360的浏览器登陆,软件 里面用的是谷歌的浏览器,照理cookie不可能会共享。想不通想不通,一个课程还要登陆一次。
还差图形化界面,看到wxpython,才发现,之前易语言拖拖控件就组装好一个界面,是多么的方便。
记点小知识:
一. 将selenium的cookies转换成requests的字符串cookies
1.selenium的cookies改成requests字符串cookies
get_cookies = [{'domain': '.learning.mhtall.com', 'httpOnly': False, 'name': 'aa', 'path': '/', 'secure': False, 'value': '1603380434'}, {'domain': '.learning.mhtall.com', 'expiry': 1634916433, 'httpOnly': False, 'name': 'bb', 'path': '/', 'secure': False, 'value': '1603380434'}, {'domain': 'learning.mhtall.com', 'httpOnly': False, 'name': 'cc', 'path': '/', 'secure': False, 'value': '35252325325235'}]
#样式1,取需要的值拼接成name-value,的列表
cookie1 = [item['name'] + "=" + item['value'] for item in get_cookies]
print(cookie1)
#样式2,用 ; 拼接成网站cookie模式,可以直接提交
cookies = '; '.join(item for item in [item["name"] + "=" + item["value"] for item in get_cookies])
print(cookies)
打印结果 :
['aa=1603380434', 'bb=1603380434', 'cc=35252325325235']
aa=1603380434; bb=1603380434; cc=35252325325235
这是学习中找到的知识点,记录一下,网站得到的是如上面get_cookies相似的cookies,这时候我们要带上cookie给网站时,要转换为网站相同的方式。
利用列表推导式,遍历里面的字典,之前一直以为写法是key,value for i in dict.items():
2.selenium的cookies写入json文件
with open('cookies.json','w') as f:
f.write(json.dumps(wd.get_cookies()))
二、 lambda用法
#以下写法是统计某json接口字典里面grade的个数
def _number(slef,sorted_x,value):
x=lambda sorted_x,value: [countx['Grade'] for countx in sorted_x].count(value)
return x(sorted_x,value)
三、一行代码将字符串cokies转成字典
cookies = dict([l.split("=", 1) for l in cookies.split("; ")])
selenium测试教程网
http://www.testclass.net/selenium_python/find-element
四、新版本无头浏览及取消正受到自动测试软件的控制
from selenium import webdriver
# 加载启动项,新版本关闭正受到自动测试软件的控制
option = webdriver.ChromeOptions()
option.add_experimental_option("excludeSwitches", ['enable-automation'])
option.add_argument('headless') # 设置option不打开浏览器
#打开浏览器
wd = webdriver.Chrome(chrome_options=option)# 调用带参数的谷歌浏览器
五、输入框输入,鼠标点击,获取值
#浏览器选择元素,复制xpath,替换'//'里面的内容,send.keys(写你需要输入的内容)
wd.find_element_by_xpath('//*[@id="txtLoginName"]').send_keys(student_name)
wd.find_element_by_xpath('//*[@id="txtPassword"]').send_keys(student_password)
# 一样复制xpan,点击学生按键
wd.find_element_by_xpath('//*[@id="rdoUserType3"]').click()
# 点击登陆
wd.find_element_by_xpath('//*[@id="login_button"]').click()
#隐性等待3秒,方便浏览器加载
wd.implicitly_wait(3)
#返回网页源代码,返回的是浏览器登陆后加载的网页
html = wd.page_source
#这里使用正则匹配,因为网页有些地方使用了script生成,造成在浏览器查看的源代码,跟python打印的不一样。在浏览器用xpath取值,会找不到
name = re.findall(r".*?sysUserName: '(.*?)',", html)
number = re.findall(r".*?sysStudentNo: '(.*?)',", html)
六、获取cookie
# 进入课程选择界面,网页登陆后包含有选择界面,但实际源代码只有左边一些菜单代码,中间课程选择的部分是另外一个网址。
wd.get('https://se.mhtall.com/stuedu/rs/roll_course')
# 随便选个课程进去,这里是14课的按键位置
wd.find_element_by_xpath('//*[@id="app"]/div[2]/div[3]/table/tbody/tr[11]/td[4]/div/button/span').click()
# 重新访问到课程要播放的界面,这样取得cookie
wd.get('https://learning.mhtall.com/play/course_detail.html?course_id=11253')
wd.implicitly_wait(2)
# selenium得到的cookie转化为requests字符串,下面代码直接name=value;拼接,方便。拼接的参数位置跟网页显示的cookie排列位置不同,但不影响。
cookie = '; '.join(item for item in [item["name"] + "=" + item["value"] for item in wd.get_cookies()])
#关闭浏览器
wd.quit()
#关闭第一个打开的窗口
#wd.close()
记录一:
headers = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
'Referer': 'https://learning.mhtall.com/play/player.html?course_id=11253&course_uuid=d99f5205-88be-4e33-9001-8372163efeec&course_code=null&lesson_id=146026',
}
#登陆界面
url_login = "https://se.mhtall.com/stuedu/student/login.jsp"
#登陆后主页
url_index = "https://se.mhtall.com/stuedu/rs/index"
formDate = {
"txtLoginName": student_number,
"txtPassword": student_password
}
cookie_list1 = []
#下面两行是登陆界面未定向的网址,得到cookie值
s = requests.session()
html = s.post(url = url_login,data = formDate,headers = headers,allow_redirects = False)
#下面是登陆成功后的主界面,用来判断是否登陆成功
respose = s.get(url = url_index,headers = headers).text
问题:这一块主要是登陆界面会set很多cookie,但网页是302,直接获取只能得到第一个cookie的值 ,
解决:需要post时,带上allow_redirects = False,禁止重定向,获取完整cookie访问登陆后界面,后面因为播放界面又生成新cookie,登陆cookie无法直接进入(应该是技术不行,不知道怎么重新得到新生成cookie),改用selenium模拟 从登陆到播放界面取cookie.
记录二:
# 视频播放网址
url_wacth = "https://learning.mhtall.com/rest/user/course/lesson/onexit?course_id="
#lesson_id课程的id,lesson_start,lesson_end为课程小节的id,循环播放各小节,达到模拟完整播放
for lesson_id in range(lesson_start, lesson_end + 1):
result_new = 0
for y in range(10, 2000, 10):
response =s.get(
url=url_wacth + str(course_id) + "&lesson_id=" + str(lesson_id) + '&finish_len=' + str(y),
headers=headers)
time.sleep(4)
# 服务器每次得到get,用len后面增加的数,来判断是否时间间隔,太快会返回观看时间太短,成功会用result返回一个数字
# 当result返回的数相同时,代表视频已经观看完成。重新观看这个数字也不会变。
result = response.json()['data']
# message会显示操作成功
result1 = response.json()['message']
# 利用result是否相同来判断视频是否已经看完
if result_new == result:
print(f"已完成第{lesson_id}课")
print(time.strftime('%Y-%m-%d %H:%M:%S'))
break
print(result1, result)
result_new = result
问题: 会有这一段代码,就是因为这个自学网,之前直接可以用360浏览器小窗口,拖拉视频到结束,完成课程的观看。现在改成无法快进,也无法多窗口观看,每10秒,会向服务器提交一次,服务从提交的值即len= 后面数字的增加,来判断用户是否一直在观看视频,如果提交时间太短,测试了少于4秒,会提示大概意思是时间过短,不通过啥的。一直性把len的值加到几千,也只增加几秒的播放时间,服务器应该是分时段来验证提交数字 的有效性。一步一脚印,想一步登天骗不过服务器。
解决: 利用time.sleep,模拟4秒向服务器网页get 一次,让服务器以为在正常观看。
并返回一个自增的data,当返回的data值不再增加时,代表视频已经观看完成。就算重进重播,服务器也会返回data最大值,代表服务器已经记录你这一节视频 已经看过。
学到: 视频播放时,返回的是
{"success":1,"code":"","message":"操作成功","data":619}
{"success":1,"code":"","message":"操作成功","data":639}
可以result = response.json()['data'] 转为字典格式,直接取值。