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。

posted @ 2022-06-15 17:41  阿飞飞啊飞  阅读(139)  评论(0编辑  收藏  举报