[Selenium+Chrome使用总结]加载Flash、禁用JS脚本、滚动页面至元素、缩放页面

前言

前几周做了个使用Selenium的项目,踩了好多好多好多的Selenium的坑,越来越感觉他作为一个第三方库,对于Chrome的操作实在是有局限。另外,推荐大家一个Selenium之外的操作浏览器的选择:puppeteer(https://github.com/GoogleChrome/puppeteer),是来自谷歌的库。它解决了很多在Selenium里很难解决的问题,比如手机页面截全屏。

好了,收回来,Selenium很多难解决的问题,我们要首先想到从JS脚本出发,毕竟Selenium还是支持驱动浏览器运行JS脚本的。

这篇文章的内容主要是Selenium日常开发中会遇到的坑,以Java代码为主,当然Python的小伙伴不用担心,这里所有的解决方案都是可以在Python中通用的。

Selenium

主要参考

Selenium使用总结(Java版本):

https://juejin.im/post/5c13880ef265da610f639c3c

Selenium准备

chromedriver各版本镜像:

https://npm.taobao.org/mirrors/chromedriver/

chromedriver版本与chrome客户端对应支持关系:

https://npm.taobao.org/mirrors/chromedriver/2.46/notes.txt

最新版本截图:

----------ChromeDriver v2.46 (2019-02-01)----------
Supports Chrome v71-73
Resolved issue 2728: Is Element Displayed command does not work correctly with v0 shadow DOM inserts [[Pri-1]]
Resolved issue  755: /session/:sessionId/doubleclick only generates one set of mousedown/mouseup/click events [[Pri-2]]
Resolved issue 2744: Execute Script returns wrong error code when JavaScript returns a cyclic data structure [[Pri-2]]
Resolved issue 1529: OnResponse behavior can lead to port exhaustion [[Pri-2]]
Resolved issue 2736: Close Window command should handle user prompts based on session capabilities [[Pri-2]]
Resolved issue 1963: Sending keys to disabled element should throw Element Not interactable error [[Pri-2]]
Resolved issue 2679: Timeout value handling is not spec compliant [[Pri-2]]
Resolved issue 2002: Add Cookie is not spec compliant [[Pri-2]]
Resolved issue 2749: Update Switch To Frame error checks to match latest W3C spec [[Pri-3]]
Resolved issue 2716: Clearing Text Boxes [[Pri-3]]
Resolved issue 2714: ConnectException: Failed to connect to localhost/0:0:0:0:0:0:0:1:15756. Could not start driver. [[Pri-3]]
Resolved issue 2722: Execute Script does not correctly convert document.all into JSON format [[Pri-3]]
Resolved issue 2681: ChromeDriver doesn't differentiate "no such element" and "stale element reference" [[Pri-3]]

----------ChromeDriver v2.45 (2018-12-10)----------
Supports Chrome v70-72
Resolved issue 1997: New Session is not spec compliant [[Pri-1]]
Resolved issue 2685: Should Assert that the chrome version is compatible [[Pri-2]]
Resolved issue 2677: Find Element command returns wrong error code when an invalid locator is used [[Pri-2]]
Resolved issue 2676: Some ChromeDriver status codes are wrong [[Pri-2]]
Resolved issue 2665: compile error in JS inside of WebViewImpl::DispatchTouchEventsForMouseEvents [[Pri-2]]
Resolved issue 2658: Window size commands should handle user prompts [[Pri-2]]
Resolved issue 2684: ChromeDriver doesn't start Chrome correctly with options.addArguments("user-data-dir=") [[Pri-3]]
Resolved issue 2688: Status command is not spec compliant [[Pri-3]]
Resolved issue 2654: Add support for strictFileInteractability [[Pri-]]

Selenium 滚动至元素

滚动至元素参考:

https://blog.csdn.net/sinat_28734889/article/details/77933401

实现代码片段:

// 获取元素
WebElement element = webDriver.findElement(By.cssSelector(elementsCss));

// 获取元素左上坐标值
Point elementPoint = element.getLocation();
int documentScrollTop = elementPoint.getY();

// 将页面根据元素滚动至合适位置
jsExecutor.executeScript("window.scrollTo(0," + documentScrollTop + ")");

Selenium等待:显示,隐式

参考:

https://huilansame.github.io/huilansame.github.io/archivers/sleep-implicitlywait-wait

强制等待

sleep(3)  # 强制等待3秒再执行下一步

隐性等待

隐形等待是设置了一个最长等待时间,如果在规定时间内网页加载完成,则执行下一步,否则一直等到时间截止,然后执行下一步。注意这里有一个弊端,那就是程序会一直等待整个页面加载完成,也就是一般情况下你看到浏览器标签栏那个小圈不再转,才会执行下一步。

# -*- coding: utf-8 -*-
from selenium import webdriver

driver = webdriver.Firefox()
driver.implicitly_wait(30)  # 隐性等待,最长等30秒
driver.get('https://huilansame.github.io')

print driver.current_url
driver.quit()

需要特别说明的是:隐性等待对整个driver的周期都起作用,所以只要设置一次即可,我曾看到有人把隐性等待当成了sleep在用,走哪儿都来一下…

显性等待

显性等待,WebDriverWait,配合该类的until()和until_not()方法,就能够根据判断条件而进行灵活地等待了。它主要的意思就是:程序每隔xx秒看一眼,如果条件成立了,则执行下一步,否则继续等待,直到超过设置的最长时间,然后抛出TimeoutException。

# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

driver = webdriver.Firefox()
driver.implicitly_wait(10)  # 隐性等待和显性等待可以同时用,但要注意:等待的最长时间取两者之中的大者
driver.get('https://huilansame.github.io')
locator = (By.LINK_TEXT, 'CSDN')

try:
    WebDriverWait(driver, 20, 0.5).until(EC.presence_of_element_located(locator))
    print driver.find_element_by_link_text('CSDN').get_attribute('href')
finally:
    driver.close()

Selenium定位元素后偏差

这是一个奇怪的问题,之所以会出现这个坐标偏差是因为windows系统下电脑设置的显示缩放比例造成的,location获取的坐标是按显示100%时得到的坐标,而截图所使用的坐标却是需要根据显示缩放比例缩放后对应的图片所确定的,因此就出现了偏差。

解决这个问题有三种方法:

1.修改电脑显示设置为100%。这是最简单的方法

2.缩放截取到的页面图片,即将截图的size缩放为宽和高都除以缩放比例后的大小;

3.修改Image.crop的参数,将参数元组的四个值都乘以缩放比例。

Selenium加载Flash

看服务报告pc端截图重构内ChromeUtil.java如何使用

问题答案里提供了很多解决思路:

https://stackoverflow.com/questions/52185371/allow-flash-content-in-chrome-69-running-via-chromedriver

网上方案:

prefs.put("profile.default_content_setting_values.plugins", 1);
prefs.put("profile.content_settings.plugin_whitelist.adobe-flash-player", 1);
prefs.put("profile.content_settings.exceptions.plugins.*,*.per_resource.adobe-flash-player", 1);

经测试Chrome65+无法使用,无效。

方法一

基本思路:通过Selenium自动访问chrome单个网页的设置页,操作元素,始终允许加载flash。

image.png

让Selenium自动选择下面的按钮


image.png

这个操作的Demo代码:

package util;

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.Select;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ChromeUtil {

    /**
     * 格式化url进入该url设置页
     * @param url
     * @return
     */
    private static String _base_url(String url){
        if (url.isEmpty()){
            return url;
        }

        try {
            URL urls = new URL(url);
            return String.format("%s://%s",urls.getProtocol(),urls.getHost());
        }catch (Exception e){
            return url;
        }
    }

    /**
     * 元素选择
     * @param driver
     * @param element
     * @return
     */
    private static WebElement _shadow_root(WebDriver driver, WebElement element){
        return (WebElement)((JavascriptExecutor) driver).executeScript("return arguments[0].shadowRoot", element);
    }

    /**
     * 允许网页的flash运行,chrome67版本可行,75版本提示升级flash
     * @param driver
     * @param url
     */
    public static void allow_flash(WebDriver driver, String url) {
        url = _base_url(url);
        driver.get(String.format("chrome://settings/content/siteDetails?site=%s",url));
        WebElement webele_settings = _shadow_root(driver,(((ChromeDriver)driver).findElementByTagName("settings-ui")));
        WebElement webele_container = webele_settings.findElement(By.id("container"));
        WebElement webele_main = _shadow_root(driver,webele_container.findElement(By.id("main")));
        WebElement showing_subpage = _shadow_root(driver,webele_main.findElement(By.className("showing-subpage")));
        WebElement advancedPage = showing_subpage.findElement(By.id("advancedPage"));
        WebElement settings_privacy_page = _shadow_root(driver,advancedPage.findElement(By.tagName("settings-privacy-page")));
        WebElement pages = settings_privacy_page.findElement(By.id("pages"));
        WebElement settings_subpage = pages.findElement(By.tagName("settings-subpage"));
        WebElement site_details = _shadow_root(driver,settings_subpage.findElement(By.tagName("site-details")));
        WebElement plugins = _shadow_root(driver,site_details.findElement(By.id("plugins")));
        WebElement permission = plugins.findElement(By.id("permission"));
        Select sel = new Select(permission);
        sel.selectByValue("allow");
    }

    /**
     * @param args
     */
    public static void main(String[] args) {

        System.setProperty("webdriver.chrome.driver", Constants.PATH_Dict.DRIVER_PATH.getValue());
        WebDriver webDriver = null;
        try {
            // 初始化webDriver
            ChromeOptions options = new ChromeOptions();
            // options.addArguments("--headless"); // 无头模式
            // options.addArguments("--no-sandbox"); // Linux关闭沙盒模式
            // options.addArguments("--disable-gpu"); // 禁用显卡
            webDriver = new ChromeDriver(options);
            webDriver.manage().window().setSize(new Dimension(1300, 800));
            String url = "https://shanghai.fang.anjuke.com/";

            // 获取重定向后网址再打开Flash权限
            webDriver.get(url);
            allow_flash(webDriver,webDriver.getCurrentUrl());
            webDriver.get(url);
            Thread.sleep(1 * 60 * 1000);


        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            if(webDriver != null) {
                webDriver.quit();
            }
        }
    }
}

方法二

在chrome设置里将所有网站加入flash白名单,但实测selenium会打开新的chrome,不读取通用设置,类似无痕窗口,有空再试试。

总结

  • 全局flash加载的设置按钮在selenium不起作用
  • 使用pref加载也没有用

禁止javascript

禁止运行javascript还是可以通过pref的:

HashMap<String, Object> chromePrefs = new HashMap<>(2);
chromePrefs.put("profile.managed_default_content_settings.javascript", 2);
options.setExperimentalOption("prefs", chromePrefs);

Selenium调整网页缩放大小

运行js

document.body.style.zoom='0.5'
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容