提问人:MandyShaw 提问时间:11/16/2023 最后编辑:MandyShaw 更新时间:11/19/2023 访问量:77
seleniumbase(未检测到的 Chrome 驱动程序):如何设置请求头?
seleniumbase (undetected Chrome driver): how to set request header?
问:
我正在将 seleniumbase 与 Driver(uc=True) 一起使用,它适用于我的特定抓取用例(并且似乎是唯一一个对我来说始终未被检测到的驱动程序)。
对于不需要特定标头设置的所有内容都可以。
对于一种特定类型的抓取,我需要设置请求标头(Accept -> application/json)。
这工作正常,并且始终如一,通过 Requestly 扩展程序在 Chrome 中手动完成,但我无法弄清楚如何将其用于 seleniumbase 未检测到的 Chrome。
我尝试将execute_cdp_cmd与Network.setExtraHTTPHeader一起使用(首先使用Network.enable):这运行没有错误,但请求似乎忽略了它。(我不相信uc=True支持正确处理了此功能,因为它似乎没有完整的Chromium驱动程序功能。
Requestly 有一个 selenium Python 机制,但它有自己的驱动程序,我看不出它如何与 seleniumbase 未检测到的 Chrome 集成。
据我所知,内置的 seleniumbase wire=True 支持不会与 uc=True 共存。
selenium-requests 可以选择搭载现有的驱动程序,但这(老实说)超出了我萌芽的 Python 技能(尽管如果我知道如何将其落实到位,确实感觉这可能是答案)。
我的抓取需要初始登录,因此在抓取会话过程中,我无法真正从一个驱动程序切换到另一个驱动程序。
答:
似乎您正在处理一个特定的用例,您希望将 SeleniumBase 与未检测到的 Chrome 驱动程序 () 一起使用,并修改特定类型的抓取的请求标头。不幸的是,由于未检测到的 Chrome 驱动程序的限制,将 Selenium 的某些功能与未检测到的 Chrome 相结合可能具有挑战性。uc=True
这是一个潜在的解决方案,涉及使用库修改请求标头,同时仍将 SeleniumBase 与未检测到的 Chrome 驱动程序一起使用:selenium-requests
from seleniumbase import BaseCase
from seleniumrequests import Chrome
class MyTest(BaseCase):
def run_test(self):
# Use SeleniumBase with undetected Chrome driver
with Chrome() as driver:
# Perform your initial login actions
# Modify request headers using selenium-requests
driver.header_overrides = {
'Accept': 'application/json',
# Add other headers as needed
}
# Continue with your scraping logic using SeleniumBase
driver.get("https://example.com")
# ... rest of your scraping code
在此示例中,我们将 SeleniumBase 用于未检测到的 Chrome 驱动程序,并使用 selenium-requests 来修改请求标头。Chrome 驱动程序中的属性用于设置自定义标头。header_overrides
请注意,此解决方案假定您熟悉 selenium-requests 库及其使用方法。如果尚未安装,可以使用以下方法进行安装:
pip install selenium-requests
请记住,组合不同的库和驱动程序可能会有一些限制,并且可能无法涵盖所有方案。如果遇到问题或需要更高级的功能,则可能需要考虑替代方法,或者可能修改库的源代码以更好地满足您的要求。
评论
我终于找到了一个简单且非常有效的解决方案,通过此处提供的 javascript 正确使用 uc=True:https://github.com/ultrafunkamsterdam/undetected-chromedriver/issues/871。
代码片段:
from seleniumbase import Driver
driver = Driver(uc=True)
login()
response = driver.execute_async_script("var callback = arguments[arguments.length - 1]; fetch('" + url + "', {method: 'GET', headers: {'Accept' : 'application/json'}}).then((response) => response.text().then((text) => callback({'status': response.status, 'text': text})))")
print(url + ':' + str(response['status']))
if response['status'] == 200:
with io.open(outfile, 'w', encoding='utf8', newline='\n') as f:
f.write(response['text'])
return response['status']
这对于我的特定用例非常有效,它只涉及通过 Get 调用 API 并获取 JSON 内容(一遍又一遍地重复)。
这也使我能够获得响应状态,这使得整个事情更具弹性。
最后,性能非常棒 - 考虑到更短的代码路径,我想这并不奇怪。
尝试将 selenium-wire 与您的 SeleniumBase 设置集成以修改请求标头,如下所示:
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from seleniumwire.undetected_chromedriver.v2 import Chrome, ChromeOptions
chrome_options = ChromeOptions()
chrome_options.add_argument('--headless')
service = Service(executable_path='path_to_your_undetected_chromedriver')
driver = webdriver.Chrome(service=service, seleniumwire_options={'options': chrome_options})
driver.header_overrides = {
'Accept': 'application/json',
}
评论