signed

QiShunwang

“诚信为本、客户至上”

2021-04-26 Python入门 --- 关于selenium元素定位以及不可交互时的解决方案

2021/4/26 17:22:05   来源:

最近利用Python做了一个模拟操作的应用,以下主要是写一些心得吧

最开始接触到的都是根据正则表达式来获取所有的元素,这是我自己定义的方法:

## html: 根据url传入request传回要解析的页面
## regex:正则表达式
def parse_findall(html, regex):
    pattern = re.compile(regex, re.S)
    items = re.findall(pattern, html)
    return items

后来,因为有一些网页会对页面做加密,所以我选择的方法是利用selenium来模拟浏览器操作。这里我用到的是Google Chrome浏览器,所以下载了相对应的driver,具体搭建环境的操作就不做赘述。下载地址:http://chromedriver.storage.googleapis.com/index.html

然后我又定义了一个初始化浏览器的方法:

def chrome_driver_init():
    chrome_opt = webdriver.ChromeOptions()  # 创建浏览器
    driver = webdriver.Chrome(options=chrome_opt)
    return driver

这样我每次需要进行模拟操作的时候,就可以直接调用该方法来创建一个浏览器的driver。再根据我的需求,定义了一个根据标签和标签上的属性值获取对应属性内容的方法:

## (浏览器driver,xpath定位,定位的标签属性值)
def get_url(driver, xpath, prop):
    url = driver.find_element_by_xpath(xpath).get_attribute(prop)
    return url

再根据需求,定义了一个类似于上个方法的来获取对应属性全部内容

## (浏览器driver,xpath定位,定位的标签属性值)
def get_all_url(driver, xpath, prop):
    _list = driver.find_elements_by_xpath(xpath)
    prop_list = []
    for i in range(len(_list )):
        prop_list.append(_list [i].get_attribute(prop))
    return prop_list

这样的定位基本上不会出错,但是我遇到的情况是页面上存在前一个和后一个的按钮。当当前内容只有一条的时候,我选择的网站会把两个div中的style设置成display: none,现在我有两个方案可以解决该问题:

1.传入的xpath加入 “and @style={display: none;}”

我使用的方法 2.使用selenium.webdriver.support库的expected_conditions和selenium.webdriver.common.by库的By来定位

我选择这个方法的原因是因为页面刷新需要时间,而定位的时候直接调用会导致定位不到,用隐式等待是定一个死的时间。所以我选择了selenium.webdriver.support.wait库的WebDriverWait来显式等待页面的刷新:

def is_has_next(driver, _list):
    xpath = "//div[@class='next' and @style='display: none;']" ## 找到该div
    WebDriverWait(driver, 10).until(expected_conditions.presence_of_all_elements_located((By.XPATH, xpath))) ##(driver, 设置10s响应等待, 0.5s默认请求一次).until(等待所有符合条件的元素都加载)
    #两个()是因为最里面的括号是因为传入的是元组而不是单个单个的参数
    for i in range(9):
        _next = driver.find_element_by_xpath("//div[@class='next' and @style='display: none;']")
        if _next:
            break ## 不存在下一个时跳出
        else:
            _next.click()
            _list.append(get_url(driver, "//div[@class='***']/img", "src"))
    return url_list

此外我还写了两个等待元素加载的方法:

# 按照classname等待
def as_class_name_wait(driver, class_name):
    WebDriverWait(driver, 10, 0.5).until(expected_conditions.element_to_be_clickable((By.CLASS_NAME, class_name)))


# 按照xpath等待
def as_xpath_wait(driver, xpath):
    WebDriverWait(driver, 10, 0.5).until(expected_conditions.element_to_be_clickable((By.XPATH, xpath)))

这样基本上就可以解决我的问题了