seleniumbase(未检测到的 Chrome 驱动程序):如何设置请求头?

seleniumbase (undetected Chrome driver): how to set request header?

提问人:MandyShaw 提问时间:11/16/2023 最后编辑:MandyShaw 更新时间:11/19/2023 访问量:77

问:

赏金将在 5 天后到期。这个问题的答案有资格获得 +50 声望赏金。MandyShaw 希望引起人们对这个问题的更多关注

我正在将 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 技能(尽管如果我知道如何将其落实到位,确实感觉这可能是答案)。

我的抓取需要初始登录,因此在抓取会话过程中,我无法真正从一个驱动程序切换到另一个驱动程序。

python selenium-webdriver http-headers seleniumbase

评论

0赞 MandyShaw 11/20/2023
我终于找到了一个解决方案,通过此处提供的 javascript 正确使用 uc=True:github.com/ultrafunkamsterdam/undetected-chromedriver/issues/...。print(driver.execute_async_script(“var 回调 = 参数[参数.长度 - 1];fetch('“ + url + ”', {method: 'GET', headers: {'Accept' : 'application/json'}}).then((response) => response.text().then((text) => callback({'status': response.status, 'text': text})))“)))。这适用于我的特定用例。
0赞 MandyShaw 11/20/2023
这也让我能够获得响应状态,这是非常有益的。

答:

-1赞 Mark 11/19/2023 #1

似乎您正在处理一个特定的用例,您希望将 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

请记住,组合不同的库和驱动程序可能会有一些限制,并且可能无法涵盖所有方案。如果遇到问题或需要更高级的功能,则可能需要考虑替代方法,或者可能修改库的源代码以更好地满足您的要求。

评论

0赞 MandyShaw 11/20/2023
非常感谢您,但不幸的是,我无法让它与uc=True或未检测到的chromedriver一起使用。我终于找到了一个解决方案,请参阅我对这个问题的评论,但很乐意进一步测试您的问题 - 我认为您的示例可能需要扩展一下?
0赞 MandyShaw 11/21/2023
我只是添加我新确定的解决方案作为答案,因为经过今天的详细批量测试,它确实令人钦佩(而且非常快)地完成了这项工作。如上所述,如果您能建议如何使其在未被发现的环境中工作,仍然很乐意推进您的解决方案。
0赞 MandyShaw 11/25/2023
需要明确的是,我没有对你的回答投反对票,但我不能奖励你赏金,因为你的解决方案对我不起作用。但是,感谢您为此付出的时间和精力。
0赞 MandyShaw 11/21/2023 #2

我终于找到了一个简单且非常有效的解决方案,通过此处提供的 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 内容(一遍又一遍地重复)。

这也使我能够获得响应状态,这使得整个事情更具弹性。

最后,性能非常棒 - 考虑到更短的代码路径,我想这并不奇怪。

1赞 Gabriel Ramuglia 11/24/2023 #3

尝试将 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',
}

评论

1赞 MandyShaw 11/25/2023
一旦我通过 pip 安装了 selenium-wire 和未检测到的 chromedriver,这就可以完美运行。我无法让服务调用工作(我不必手动安装驱动程序可执行文件),但如果没有它,它就可以正常工作。我认为关键是 seleniumwire.undetected_chromedriver.v2,没有其他人建议/提及。非常感谢。
0赞 Gabriel Ramuglia 11/25/2023
伟大!我很高兴听到它奏效了!