selenium调用Chrome Devtools Protocol实现模拟定位

最近在做关于自动化养号这一块,调研了一番某海外社交媒体,发现其账号的属性跟IP地址和定位相关,于是就打算用selenium去撸一段养号的脚本,同时实现在养号过程中使用代理IP和模拟定位.

踩过的坑

  • chromedriver中修改profile.default_content_setting_values来开启浏览器模拟定位,但其实是配置文件中没有该配置选项
  • chromedriver初始化的时候,调用manual geolocation插件,在浏览器启动时能够在sensor中加载定位,但是无法激活overwrite

解决办法

通过CDP,可以直接在ChromeDriver上操作开发者工具(也就是F12),在webserver.Chrome().execute_cdp_cmd的方法内执行CDP命令,将经纬度放在一个dict里面传入该方法,即可完成模拟定位

CHROME_PATH = ""  # your chromedriver's path
chrome_opt = webdriver.ChromeOptions()
# chrome_opt.add_argument("proxy-server=http://127.0.0.1:1087")  # 加载代理IP
prefs = {
    'profile.default_content_setting_values':
        {
            'notifications': 1,  # 允许通知
            'geolocation': 1  # 允许定位
        },
}
chrome_opt.add_experimental_option('prefs', prefs)
self.driver = webdriver.Chrome(executable_path=CHROME_PATH, desired_capabilities=chrome_opt.to_capabilities())
self.driver.execute_cdp_cmd("Emulation.setGeolocationOverride", cmd_args={'latitude': 37.871093, 'longitude': -122.281604,  'accuracy': 100})

改进

看了官方文档案例用的是Remote的链接方式,其好处是每次启动chromedriver,都是通过remote的方式去连接到共用的chromedriver(开放9515端口),这样子能够节省很多服务器的资源;而直接用webserver.Chrome的方式连接chromedriver,在每次启动的时候都会实例化启动一个对应的server,这样子不卡才怪~

于是乎果断把连接chromedriver的方式改为Remote,并启动chromedriver服务
$ ./chromedriver

13806270-827e8b4440fd8929.png
启动chromedriver

那么问题来了,Remote的连接方式并没有提供像Chrome连接方式的execute_cdp_cmd()方法.既然不提供,那么就去源码看看是怎么肥四,然后再生撸一段代码了...

execute_cdp_cmd()源码中发现,其实这个方法是直接返回了self.execute()['value']

13806270-3937f0188c3d47f4.png
execute_cdp_cmd

self.execute()['value']方法是在remote/webserver中的class WebDriver(object)声明,Chrome连接方式也是集成了这个类 (似乎有点头绪了)

回来看Chrome连接方式的源码,发现其中init方式在重写了class WebDriver(object)里面的RemoteConnection

13806270-8e3018336fe79e78.png
Chrome.__init__

13806270-7a346fdd2be55aed.png
ChromeRemoteConnection

原来Chrome连接方式在实例化的时候声明了cdp的入口,所以才有了之前的execute_cdp_cmd()

self._commands['executeCdpCommand'] = ('POST', '/session/$sessionId/goog/cdp/execute')

那么我们在Remote连接方式实例化的时候再声明一遍cdp的入口就完事了

class NewRemoteConnection(RemoteConnection):
    """
    重写RemoteConnection,加入CDP支持
    """
    def __init__(self, remote_server_addr, keep_alive=True):
        RemoteConnection.__init__(self, remote_server_addr, keep_alive)
        self._commands['executeCdpCommand'] = ('POST', '/session/$sessionId/goog/cdp/execute')


class FacebookAutoAccount(object):
    """
    Chrome初始化
    """
    def __init__(self):
        chrome_opt = webdriver.ChromeOptions()
        # chrome_opt.add_argument("proxy-server=http://127.0.0.1:1087")  # 加载代理IP
        prefs = {
            'profile.default_content_setting_values':
                {
                    'notifications': 1,  # 允许通知
                    'geolocation': 1  # 允许定位
                },
        }
        chrome_opt.add_experimental_option('prefs', prefs)
        remote_url = 'localhost:9515'  # 远端调试地址
        self.driver = webdriver.Remote(remote_url, desired_capabilities=chrome_opt.to_capabilities())
        self.driver.command_executor = NewRemoteConnection(remote_url, keep_alive=False)  # 加入executeCdpCommand的支持

参考文档

CDP官方文档
Chrome remote debugging protocol在自动化测试中的应用和实践
chrome devtools protocol——Web 性能自动化实践介绍
ChromeOptions

猜你喜欢

转载自blog.csdn.net/weixin_34364135/article/details/90822487