最近在做关于自动化养号这一块,调研了一番某海外社交媒体,发现其账号的属性跟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
那么问题来了,Remote的连接方式并没有提供像Chrome连接方式的execute_cdp_cmd()
方法.既然不提供,那么就去源码看看是怎么肥四,然后再生撸一段代码了...
在execute_cdp_cmd()
源码中发现,其实这个方法是直接返回了self.execute()['value']
self.execute()['value']
方法是在remote/webserver中的class WebDriver(object)
声明,Chrome连接方式也是集成了这个类 (似乎有点头绪了)
回来看Chrome连接方式的源码,发现其中init方式在重写了class WebDriver(object)
里面的RemoteConnection
原来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