vieyahn2017 / iBlog

44 stars 0 forks source link

10.20 selenium自动化使用 #366

Closed vieyahn2017 closed 3 months ago

vieyahn2017 commented 3 years ago

下载chromedriver,放在比如C:\Python27\Scripts 安装pip install selenium

vieyahn2017 commented 3 years ago

初始化 options = webdriver.ChromeOptions() options.add_argument('ignore-certificate-errors') browser = webdriver.Chrome(chrome_options=options)

登录 browser.find_element_by_name('username').send_keys(username) browser.find_element_by_name('password').send_keys(password) browser.find_element_by_name('Submit').click()

获取元素 browser.find_element_by_name browser.find_element_by_xpath

内嵌在iframe的数据 browser.switch_to.frame('x-URS-iframe') browser.switch_to.parent_frame() browser.switch_to.default_content()

vieyahn2017 commented 3 years ago

Selenium用法笔记(解决动态渲染页面)

https://blog.csdn.net/q1694222672/article/details/82836315

这个讲的比较全。 里面的 【交互动作,动作链 执行JavaScript Cookies 】 应该也是某些场合会用到的

vieyahn2017 commented 3 years ago

Selenium 遇到的问题

https://www.cnblogs.com/zi-yao/p/6178519.html

摘录部分:

  1. How to Resolve Stale Element Reference Exception?

2.输入框输入字后需要点击一下屏幕其他地方触发数据校验 怎么实现?   比如我在一个输入框书写一个名字后 需要点击屏幕空白地区 来确认我输入的没问题   需要这样操作的话,可以不一定非得要点击空白区域,因为空白区域对应selenium来说没法操作。可以点击一个没有连接的静态图片或者文字,也是一样的效果

  1. 在指定的当前节点下搜索满足要求的节点

在通过selenium使用xpath选择节点的时候,可能会遇到这么一种情况:在指定的当前节点下搜索满足要求的节点

node = driver.find_element_by_xpath("//div[@class='WB_cardwrap S_bg2 clearfix']")
BZNC = node.find_element_by_xpath("//div[@class='feed_content wbcon']/a[@class='W_texta W_fb']").text
BZZY = node.find_element_by_xpath("//div[@class='feed_content wbcon']/a[@class='W_texta W_fb']").get_attribute("href")

以上代码有什么错误吗?貌似没有,一切都很完美。 先拿到node节点,然后在node节点的子节点中搜索满足条件的节点并取出text及属性。 but!运行的结果却是把整个html中所有满足条件的节点都找出来了,而并非是node节点下的!!!仔细想一想,"//div"貌似就是搜索整个html下的div,即使是node下的find_element_by_xpath方法! 所以,只需要在”//”前面加上表示当前路径的"."既可,也就是node.find_element_by_xpath(“.//div”)

vieyahn2017 commented 3 years ago

Selenium六 find_element_by_xpath()的几种方法

https://blog.csdn.net/u012941152/article/details/83011110

史上最全!Selenium元素定位的30种方式

https://blog.csdn.net/qq_32897143/article/details/80383502?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param

js定位

search_js = "document.getElementsByName('wd')[0].value='selenium';"
search_js2 = "document.querySelectorAll('.s_ipt')[0].value='selenium';"
button_js = "document.getElementById('su').click();"
button_js2 = "document.getElementsByClassName('s_btn')[0].click()"
driver.execute_script(search_js2)
driver.execute_script(button_js2)

jQuery定位

search_jq = "$('#kw').val('selenium')"
button_jq = "$('.s_btn').click()"
driver.execute_script(search_jq)
driver.execute_script(button_jq)

正好把定位,和执行js结合起来了。

vieyahn2017 commented 3 years ago

Js使用xpath和selector定位元素

https://vonsdite.github.io/posts/cb216d2c.html

使用selector定位元素 querySelector和querySelectorAll方法是W3C Selectors API规范中定义的。 document.querySelector('*[name="username"]')

根据xpath定位元素


function find_element_by_xpath(STR_XPATH) {

    var xresult = document.evaluate(STR_XPATH, document, null, XPathResult.ANY_TYPE, null);
    var xnodes = [];
    var xres;
    while (xres = xresult.iterateNext()) {
        xnodes.push(xres);
    }

    return xnodes;
}

find_element_by_xpath("/html/body/div/div[2]/div/div/ul/li[10]/div/span[2]/span/span")

vieyahn2017 commented 3 weeks ago

idp.py


# -*- coding: utf-8 -*-

import os
import sys
import time
import traceback
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.common.exceptions import NoSuchElementException

USERNAME = "-----"
PASSWORD = "-------------"

CHAPTER_INDEX = 10
# 这边爬取第10小节【录像管理接口】的api

reload(sys)
sys.setdefaultencoding( "utf-8" )

options = webdriver.ChromeOptions()
options.add_argument('ignore-certificate-errors')
browser = webdriver.Chrome(chrome_options=options)

RESTFUL_API_URL = "https://..."
API_IFRAME_ID = "iframe-ZH-CN_BOOKMAP_0237887941"

def log_w3(username, password):
    base_url = "https://..."
    # 隐式等待
    browser.implicitly_wait(5)
    ##跳过安全认证
    options = webdriver.ChromeOptions()
    options.add_argument('ignore-certificate-errors')
    ##登录
    browser.get(base_url)
    # js:  document.querySelector('*[name="uid"]')
    browser.find_element_by_name('uid').send_keys(username)
    browser.find_element_by_name('password').send_keys(password)
    browser.find_element_by_name('Submit').click()
    time.sleep(30)

# log_w3(USERNAME, PASSWORD)
log_w3("xxx", "ppp")

def getLeftFrame(initing=True):
    if initing:
        browser.get(RESTFUL_API_URL)
        time.sleep(60)
    else:
        browser.switch_to.default_content()
        time.sleep(10)
    browser.switch_to.frame(API_IFRAME_ID)
    time.sleep(10)
    browser.switch_to.frame('appFrame')
    time.sleep(10)
    browser.switch_to.frame('manualtree')
    time.sleep(10)

def getRightFrame():
    browser.get(RESTFUL_API_URL)
    time.sleep(60)
    # browser.switch_to.default_content()
    time.sleep(10)
    browser.switch_to.frame('iframe-ZH-CN_BOOKMAP_0237887941')
    time.sleep(10)
    browser.switch_to.frame('appFrame')
    time.sleep(10)

def parse_log(method, url, title):
    # DELETE_RM_ORG_DEL("DELETE_/RM/Org/Del", 990402, "orgCode", "删除设备组")
    # PUT_VIDEO_GRUISE_PLAN_V10("PUT_/video/gruisePlan/v1.0", 990513, "cameraCode", "设置巡航计划")
    if "?" in url:
        url = url.split("?")[0]
    url_filter = url.replace("/", "_").replace(".", "").replace("{", "").replace("}", "").upper()
    # ? url的{}再怎么处理,暂时直接去除占位符,保留其中的字母
    title = title.split(" ")[-1] if " " in title else title
    return "{}{}(\"{}_{}\", 999999, \"xxxCode\", \"{}\"".format(method.upper(), url_filter, method.upper(), url, title)

# 最初的思路,getLeftFrame(),拿到所有topic的id,然后再getRightFrame(),在右边遍历。但是右边的数据默认并未加载出来,这个方法不可行
# 还是得左右配合:左边点击目录树才能加载右边

def get_part_i(index):
    ### 获取某个章节的内容
    # 观察,第9个,第10个,分别是
    # /html/body/div[1]/div[2]/div/div/ul/li[9]/div/span[2]/span/span
    # /html/body/div[1]/div[2]/div/div/ul/li[10]/div/span[2]/span/span

    # api的二级目录(左)路径为:
    # /html/body/div[1]/div[2]/div/div/ul/li[10]/ul/li[44]/div/span/span/span

    """
    # api的xpath
    /html/body/table/tbody/tr[3]/td[2]/div/div[1]/div[1]/div/div[1]/div[162]/article/div/p[1]  # 接口描述标题
    /html/body/table/tbody/tr[3]/td[2]/div/div[1]/div[1]/div/div[1]/div[162]/article/div/p[2]  # 接口描述

    /html/body/table/tbody/tr[3]/td[2]/div/div[1]/div[1]/div/div[1]/div[162]/article/div/p[4]  # 使用说明标题
    # 使用说明
    /html/body/table/tbody/tr[3]/td[2]/div/div[1]/div[1]/div/div[1]/div[162]/article/div/table[1]/tbody/tr[1]/td[2]/p
    /html/body/table/tbody/tr[3]/td[2]/div/div[1]/div[1]/div/div[1]/div[162]/article/div/table[1]/tbody/tr[2]/td[2]/p
    /html/body/table/tbody/tr[3]/td[2]/div/div[1]/div[1]/div/div[1]/div[162]/article/div/table[1]/tbody/tr[3]/td[2]/p

    /html/body/table/tbody/tr[3]/td[2]/div/div[1]/div[1]/div/div[1]/div[162]/article/div/p[7]  # 示例 DELETE /record/recordplan/v1.0 HTTP/1.1

    # 参数描述 标题占第一行
    /html/body/table/tbody/tr[3]/td[2]/div/div[1]/div[1]/div/div[1]/div[162]/article/div/table[2]/tbody/tr[1]/td[2]/p

    /html/body/table/tbody/tr[3]/td[2]/div/div[1]/div[1]/div/div[1]/div[162]/article/div/table[2]/tbody/tr[2]/td[2]/p
    /html/body/table/tbody/tr[3]/td[2]/div/div[1]/div[1]/div/div[1]/div[162]/article/div/table[2]/tbody/tr[4]/td[2]/p

    """

    getLeftFrame()

    # XPath中的索引从1开始而不是0
    part_i_xpath = "/html/body/div/div[2]/div/div/ul/li[{}]/div/span[2]/span/span".format(index)
    part_i_xpath1 = "/html/body/div[1]/div[2]/div/div/ul/li[{}]/div/span[2]/span/span".format(index)
    # 这两是一样的
    # print(part_i_xpath)
    # print(part_i_xpath1)
    for i in range(3):
        try:
            browser.find_element_by_xpath(part_i_xpath)
            break
        except:
            time.sleep(30)
    else:
        print("cannot load, exit.")
        return

    browser.find_element_by_xpath(part_i_xpath).click()
    # 定位到父章节,并获得其中所有子元素,这边是li。判断个数
    parent_li = browser.find_element_by_xpath("/html/body/div[1]/div[2]/div/div/ul/li[{}]/ul".format(index))
    rows = parent_li.find_elements_by_tag_name('li')
    api_numbers = len(rows)
    print(api_numbers)

    child_li_id = "000"
    endl = "\n"  # api部分每个p子元素的span带有一个好像换行符的东西,影响p元素的text取值。 见循环中i==1的部分

    is_except_occur = False

    for i in range(1, 1 + api_numbers):
        if i == 1:
            # 第一个有时候找不到,大概是还未加载
            time.sleep(30)
        if is_except_occur:
            # 不确定出异常是在左侧还是右侧,iframe层级不同,因此,只好每次出异常,回最顶端。网上介绍的方法find_elements_by_tag_name("iframe") 不可行,大概只有在最顶端才可以执行这个查询iframe子元素。我们希望的是查询当前的父元素iframe
            getLeftFrame(False)
        is_except_occur = False

        # 网上介绍的方法find_elements_by_tag_name("iframe") 不可行,大概只有在最顶端才可以执行这个查询iframe子元素。我们希望的是查询当前的父元素iframe
        # iframe = browser.find_elements_by_tag_name("iframe")
        # print(iframe.get_attribute("id"))

        child_li_xpath = "/html/body/div[1]/div[2]/div/div/ul/li[{}]/ul/li[{}]/div/span/span/span".format(index, i)
        try:

            child_li = browser.find_element_by_xpath(child_li_xpath)
            child_li_id_raw = child_li.get_attribute("id")    # such as  896619110#topic#ZH-CN_TOPIC_0237887792
            child_li_id = child_li_id_raw.strip().split("#")[-1].strip()
            # print(child_li_id)
            article_title = child_li.text.strip()
            child_li.click()
            time.sleep(10)
            # 以上代码,左边目录加载并获取topic的id,点击后,加载右侧数据

            # 右侧,获取api数据
            browser.switch_to.parent_frame()
            time.sleep(5)
            article = browser.find_element_by_xpath("//article[@data-hd-id='{}']".format(child_li_id))
            # print(article.text)

            if i == 1:
                endl = article.find_element_by_xpath(".//div/p[2]/span").text

            article_info = article.find_element_by_xpath(".//div/p[2]").text.strip().replace(endl, "")
            article_method = article.find_element_by_xpath(".//div/table[1]/tbody/tr[1]/td[2]/p").text.strip().replace(endl, "")
            article_url = article.find_element_by_xpath(".//div/table[1]/tbody/tr[2]/td[2]/p").text.strip().replace(endl, "")
            article_example = article.find_element_by_xpath(".//div/p[7]").text.strip().replace(endl, "")
            # print(article_title)
            # print(article_info)
            # print(article_method)
            # print(article_url)
            # print(article_example)

            print(parse_log(article_method, article_url, article_title))

            # 下一次循环回左侧,需要多进入一层ifrmae
            browser.switch_to.frame('manualtree')
            time.sleep(5)

        except Exception as e:
            print(child_li_id)
            print(e)
            is_except_occur = True
            continue

# get_part_i(CHAPTER_INDEX)
get_part_i(7)

print("done.")
# browser.quit()