selenium实战
当有些网页是用js生成的,用requests获取到的网页里面啥都没有怎么办呢。这个时候最简单的方法就是用selenium模拟页面渲染,当页面渲染完成之后再去根据标签或者xpath就可以获取到自己想要的东西了。
这里只讲实战,关于粉笔答题页面的学习。本来无聊的时候想写个脚本,不用打开网页在命令行里答题,这里记录一下,ps,最后没有成功,所以本文以selenium使用为主
遇到的坑
前排记录下使用selenium时遇到的坑
- 关闭chrome的自动更新,不然chromedriver的版本跟不上
- add_experimental_option('w3c', True),为false时有些element会返回dict类型
- cookie中"sameSite"为"unspecified"的时候,直接删掉这个选项
- 需要等js渲染完成之后去获取element,不然会为空。driver.implicitly_wait(5)和WebDriverWait两种方法
- ActionChains(driver).move_to_element(label).click().perform() 需要页面可见
实战开始
等待页面渲染完成
以粉笔为例,查看他的网页源代码如下:
可以看到,html中是无法获取到自己想要的内容的,但是右键检查是可以看到内容的。此时我们就需要等页面渲染完成。
最简单的方法就是加个sleep,停个五六秒,但是这样很慢。这个时候就有了上面提到的driver.implicitly_wait(5)和WebDriverWait两种方法,想要深入了解的可以去搜一下隐形等待和显性等待。等待页面渲染完成之后就可以获取到element了。
登陆问题
以粉笔网页为例,你会发现自己在chrome中打开是不需要登陆的,但是用selenium打开页面却是登陆页面了。
有两种解决方案,一种是老老实实的在页面中填入对应元素。但是有人机验证的问题,有些图形验证码不是很好点。另一种就是用cookie登陆,现在网页里登陆,然后导出cookie,给driver添加cookie,然后再打开想要打开的页面,你会发现不会跳转登陆页面了。代码如下
driver.add_cookie(item)
获取子节点
利用获取到的element,可以看到有个find_element,可以利用它获取到子节点。那遇到ul里一堆li都需要的情况呢,只需要调用find_elements即可,返回的是符合条件的element数组。比方说可以利用一下代码,获取question这个element下面的article标签。
article = question.find_element(By.TAG_NAME,'article')
使用下面的代码可以获取该节点下所有element
answers = answers.find_elements(By.XPATH,"*")
代码环节
贴一下我这次的代码,也方便理解。我想要通过在命令行的输入,完成对粉笔题库的答题,结果在点击答案时遇到了问题。当被点击的选项没显示的时候,执行click会报错,让选项直接划到页面的时候也会,还存在各种问题,尝试多次无果,遂放弃。
from ctypes import pointer
from lib2to3.pgen2 import driver
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.support.wait import WebDriverWait#引入 WebDriverWait对象
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
import time
import requests
import json
import re
def getUrl():
global driver
d = DesiredCapabilities.CHROME
d['loggingPrefs'] = { 'performance':'ALL' }
chrome_options = Options()
# 解决方法
chrome_options.add_experimental_option('w3c', False)
driver = webdriver.Chrome(desired_capabilities=d, options=chrome_options)
#主页链接
homePageUrl = "https://spa.fenbi.com/tiku/guide/catalog/xingce?prefix=xingce"
driver.implicitly_wait(5)
driver.get(homePageUrl) #加载cookie
cookies = [
]
for item in cookies:
driver.add_cookie(item)
driver.get(homePageUrl)
keyPointTreeXpath = '//*[@id="calalog-page"]/main/div[1]/div[2]/app-keypoint-catalog/div/div[2]/ul'
keyPointTree = driver.find_element(By.XPATH,keyPointTreeXpath)
print(type(keyPointTree))
# 获取子节点
keyPoints = keyPointTree.find_elements(By.XPATH,'*')
for keyPoint in keyPoints:
print(keyPoint.text)
choose = input()
choosePoint = keyPoints[int(choose)]
choosePoint.click()
pointTree = choosePoint.find_elements(By.XPATH,'*')
points = pointTree[1].find_elements(By.XPATH,'*')
for point in points:
detailText = point.find_elements(By.TAG_NAME,'p')
print(detailText[0].text,detailText[1].text)
choose = input()
divs = points[int(choose)].find_elements(By.TAG_NAME,'div')
divs[1].click()
wait = WebDriverWait(driver,10)
allQuestionsXpath = '//*[@id="app-practice"]/main/section'
allQuestions = wait.until(EC.presence_of_element_located((By.XPATH,allQuestionsXpath)))
questions = allQuestions.find_elements(By.XPATH,'*')
for question in questions:
article = question.find_element(By.TAG_NAME,'article')
print(article.text)
answers = question.find_element(By.TAG_NAME,'ul')
answers = answers.find_elements(By.XPATH,"*")
for answer in answers:
print(answer.text)
choose = input()
label = answers[int(choose)].find_element(By.TAG_NAME,'p')
driver.execute_script("arguments[0].scrollIntoView();", label)
label.click()
# print(type(label))
# element = driver.find_element()
# # label = driver.find_element(By.XPATH,xpath) 1
# request_log = driver.get_log('performance')
# for log in request_log:
# msg = json.loads(log['message'])
# request = msg['message']['params'].get('request')
# if(request is None):
# continue
# url = request.get('url')
# questionUrl = 'https://tiku.fenbi.com/api/xingce/questions'
# if(questionUrl in url):
# print(url)
# driver.get(url)
# source = etree.HTML(driver.page_source)
# test = source.xpath('/html/body/pre/text()')[0]
# print('========================================')
# 2
# data = json.loads(test)
# for item in data:
# str = item['content']
# str = str.replace('<u>','')
# str = str.replace('</u>','')
# str = str.replace('<p>','')
# str = str.replace('</p>','')
# str = str.replace(' ','')
# print(str)
# answer = item['accessories']
# options = answer[0]['options']
# index = 0
# for option in options:
# print(index,"."+option)
# index += 1
# x = input()
# correctAnswer = item['correctAnswer']
# if(x==correctAnswer['choice']):
# print("right!")
# else:
# print("false!正确答案是:",correctAnswer['choice'])
if '_main_':
getUrl()
如果想看看效果,填入自己的cookie即可。
直接获取数据
当我想模拟页面点击失效后,我就换了个思路,直接去获取页面加载的接口。
使用如下方法获取到所有接口,然后根据自己观察,找到匹配的接口。直接打开接口页面获取数据。
driver.get_log('performance')
不过我观察了下粉笔的网站,原本有数据那个接口,现在返回为空,具体原因不清楚了。
ps,要调用上面的方法,上面说的w3c属性要改成false。