使用 selenium 和代理获取请求 body
Get requests body using selenium and proxies
我希望能够使用代理后面的 selenium 获得特定子请求的 body。
现在我正在使用 python + selenium + chromedriver。通过日志记录,我能够获得每个子请求的 headers 但不是 body。我的日志记录设置:
caps['loggingPrefs'] =
{'performance': 'ALL',
'browser': 'ALL'}
caps['perfLoggingPrefs'] = {"enableNetwork": True,
"enablePage": True,
"enableTimeline": True}
我知道有几种方法可以用 selenium 形成 HAR:
- 使用 geckodriver 和 har-export-trigger。我尝试使用以下代码使其工作:
window.foo = HAR.triggerExport().then(harLog => { return(harLog); });
return window.foo;
遗憾的是,我没有在返回数据中看到响应的 body。
- 使用 browsermob 代理。该解决方案似乎完全没问题,但我没有找到让 browsermob 代理在代理后面工作的方法。
所以问题是:在使用 selenium 下载网页并使用代理的过程中,如何获得特定网络响应的 body。
UPD:实际上,har-export-trigger 我得到了响应体,但不是全部:我需要的响应 body 在 json 中,它的 MIME 类型是 'text/html; charset=utf-8' 而我生成的 HAR 文件中缺少它,因此仍然缺少解决方案。
UPD2:经过进一步调查,我意识到当 har-export-trigger add-on 打开时,即使在我的桌面 firefox 上也缺少响应 body,所以这个解决方案可能是dead-end(问题 Github)
UPD3:只有最新版本的 har-export-trigger 才能看到此错误。随着版本 0.6.0。一切正常。
因此,对于未来的 google 员工:您可以使用 har-export-trigger v. 0.6.0。或已接受答案的方法。
我实际上刚刚完成了使用您在问题中提到的工具实现的 selenium HAR 脚本。从 har-export-trigger 和 BrowserMob 获取的 HAR 均已使用 Google HAR 分析器进行验证。
A class 使用 selenium、gecko 驱动程序和 har-export-trigger:
class MyWebDriver(object):
# a inner class to implement custom wait
class PageIsLoaded(object):
def __call__(self, driver):
state = driver.execute_script('return document.readyState;')
MyWebDriver._LOGGER.debug("checking document state: " + state)
return state == "complete"
_FIREFOX_DRIVER = "geckodriver"
# load HAR_EXPORT_TRIGGER extension
_HAR_TRIGGER_EXT_PATH = os.path.abspath(
"har_export_trigger-0.6.1-an+fx_orig.xpi")
_PROFILE = webdriver.FirefoxProfile()
_PROFILE.set_preference("devtools.toolbox.selectedTool", "netmonitor")
_CAP = DesiredCapabilities().FIREFOX
_OPTIONS = FirefoxOptions()
# add runtime argument to run with devtools opened
_OPTIONS.add_argument("-devtools")
_LOGGER = my_logger.get_custom_logger(os.path.basename(__file__))
def __init__(self, log_body=False):
self.browser = None
self.log_body = log_body
# return the webdriver instance
def get_instance(self):
if self.browser is None:
self.browser = webdriver.Firefox(capabilities=
MyWebDriver._CAP,
executable_path=
MyWebDriver._FIREFOX_DRIVER,
firefox_options=
MyWebDriver._OPTIONS,
firefox_profile=
MyWebDriver._PROFILE)
self.browser.install_addon(MyWebDriver._HAR_TRIGGER_EXT_PATH,
temporary=True)
MyWebDriver._LOGGER.info("Web Driver initialized.")
return self.browser
def get_har(self):
# JSON.stringify has to be called to return as a string
har_harvest = "myString = HAR.triggerExport().then(" \
"harLog => {return JSON.stringify(harLog);});" \
"return myString;"
har_dict = dict()
har_dict['log'] = json.loads(self.browser.execute_script(har_harvest))
# remove content body
if self.log_body is False:
for entry in har_dict['log']['entries']:
temp_dict = entry['response']['content']
try:
temp_dict.pop("text")
except KeyError:
pass
return har_dict
def quit(self):
self.browser.quit()
MyWebDriver._LOGGER.warning("Web Driver closed.")
一个子class 添加 BrowserMob 代理供您参考:
class MyWebDriverWithProxy(MyWebDriver):
_PROXY_EXECUTABLE = os.path.join(os.getcwd(), "venv", "lib",
"browsermob-proxy-2.1.4", "bin",
"browsermob-proxy")
def __init__(self, url, log_body=False):
super().__init__(log_body=log_body)
self.server = Server(MyWebDriverWithProxy._PROXY_EXECUTABLE)
self.server.start()
self.proxy = self.server.create_proxy()
self.proxy.new_har(url,
options={'captureHeaders': True,
'captureContent': self.log_body})
super()._LOGGER.info("BrowserMob server started")
super()._PROFILE.set_proxy(self.proxy.selenium_proxy())
def get_har(self):
return self.proxy.har
def quit(self):
self.browser.quit()
self.proxy.close()
MyWebDriver._LOGGER.info("BroswerMob server and Web Driver closed.")
我希望能够使用代理后面的 selenium 获得特定子请求的 body。
现在我正在使用 python + selenium + chromedriver。通过日志记录,我能够获得每个子请求的 headers 但不是 body。我的日志记录设置:
caps['loggingPrefs'] = {'performance': 'ALL', 'browser': 'ALL'}
caps['perfLoggingPrefs'] = {"enableNetwork": True, "enablePage": True, "enableTimeline": True}
我知道有几种方法可以用 selenium 形成 HAR:
- 使用 geckodriver 和 har-export-trigger。我尝试使用以下代码使其工作:
window.foo = HAR.triggerExport().then(harLog => { return(harLog); }); return window.foo;
遗憾的是,我没有在返回数据中看到响应的 body。
- 使用 browsermob 代理。该解决方案似乎完全没问题,但我没有找到让 browsermob 代理在代理后面工作的方法。
所以问题是:在使用 selenium 下载网页并使用代理的过程中,如何获得特定网络响应的 body。
UPD:实际上,har-export-trigger 我得到了响应体,但不是全部:我需要的响应 body 在 json 中,它的 MIME 类型是 'text/html; charset=utf-8' 而我生成的 HAR 文件中缺少它,因此仍然缺少解决方案。
UPD2:经过进一步调查,我意识到当 har-export-trigger add-on 打开时,即使在我的桌面 firefox 上也缺少响应 body,所以这个解决方案可能是dead-end(问题 Github)
UPD3:只有最新版本的 har-export-trigger 才能看到此错误。随着版本 0.6.0。一切正常。
因此,对于未来的 google 员工:您可以使用 har-export-trigger v. 0.6.0。或已接受答案的方法。
我实际上刚刚完成了使用您在问题中提到的工具实现的 selenium HAR 脚本。从 har-export-trigger 和 BrowserMob 获取的 HAR 均已使用 Google HAR 分析器进行验证。
A class 使用 selenium、gecko 驱动程序和 har-export-trigger:
class MyWebDriver(object):
# a inner class to implement custom wait
class PageIsLoaded(object):
def __call__(self, driver):
state = driver.execute_script('return document.readyState;')
MyWebDriver._LOGGER.debug("checking document state: " + state)
return state == "complete"
_FIREFOX_DRIVER = "geckodriver"
# load HAR_EXPORT_TRIGGER extension
_HAR_TRIGGER_EXT_PATH = os.path.abspath(
"har_export_trigger-0.6.1-an+fx_orig.xpi")
_PROFILE = webdriver.FirefoxProfile()
_PROFILE.set_preference("devtools.toolbox.selectedTool", "netmonitor")
_CAP = DesiredCapabilities().FIREFOX
_OPTIONS = FirefoxOptions()
# add runtime argument to run with devtools opened
_OPTIONS.add_argument("-devtools")
_LOGGER = my_logger.get_custom_logger(os.path.basename(__file__))
def __init__(self, log_body=False):
self.browser = None
self.log_body = log_body
# return the webdriver instance
def get_instance(self):
if self.browser is None:
self.browser = webdriver.Firefox(capabilities=
MyWebDriver._CAP,
executable_path=
MyWebDriver._FIREFOX_DRIVER,
firefox_options=
MyWebDriver._OPTIONS,
firefox_profile=
MyWebDriver._PROFILE)
self.browser.install_addon(MyWebDriver._HAR_TRIGGER_EXT_PATH,
temporary=True)
MyWebDriver._LOGGER.info("Web Driver initialized.")
return self.browser
def get_har(self):
# JSON.stringify has to be called to return as a string
har_harvest = "myString = HAR.triggerExport().then(" \
"harLog => {return JSON.stringify(harLog);});" \
"return myString;"
har_dict = dict()
har_dict['log'] = json.loads(self.browser.execute_script(har_harvest))
# remove content body
if self.log_body is False:
for entry in har_dict['log']['entries']:
temp_dict = entry['response']['content']
try:
temp_dict.pop("text")
except KeyError:
pass
return har_dict
def quit(self):
self.browser.quit()
MyWebDriver._LOGGER.warning("Web Driver closed.")
一个子class 添加 BrowserMob 代理供您参考:
class MyWebDriverWithProxy(MyWebDriver):
_PROXY_EXECUTABLE = os.path.join(os.getcwd(), "venv", "lib",
"browsermob-proxy-2.1.4", "bin",
"browsermob-proxy")
def __init__(self, url, log_body=False):
super().__init__(log_body=log_body)
self.server = Server(MyWebDriverWithProxy._PROXY_EXECUTABLE)
self.server.start()
self.proxy = self.server.create_proxy()
self.proxy.new_har(url,
options={'captureHeaders': True,
'captureContent': self.log_body})
super()._LOGGER.info("BrowserMob server started")
super()._PROFILE.set_proxy(self.proxy.selenium_proxy())
def get_har(self):
return self.proxy.har
def quit(self):
self.browser.quit()
self.proxy.close()
MyWebDriver._LOGGER.info("BroswerMob server and Web Driver closed.")