将cookies加载到Python请求会话中时出现错误

5

我正在尝试从Selenium导出的cookies中加载Cookies到Python请求会话中,但是这样做会返回以下错误:“'list'对象没有属性'extract_cookies'”。

def load_cookies(filename):
    with open(filename, 'rb') as f:
        return pickle.load(f)

initial_state= requests.Session()
initial_state.cookies=load_cookies(time_cookie_file)
search_requests = initial_state.get(search_url)

我在许多地方看到这段代码应该可以运行,但是我的cookies是一个字典列表,这也是我理解所有cookies的方式,并且这也是我假设它在Selenium中能够工作的原因。但是由于某些原因,在使用requests时它却不起作用,希望能得到任何帮助,谢谢!感觉像是我漏掉了一些非常显然的东西。

Selenium使用以下命令将cookies导出:

with open("Filepath.pkl", 'wb') as f:
    pickle.dump(driver.get_cookies(), f)

一个 cookie 的例子(稍作混淆)如下:
[{'domain': '.website.com',
  'expiry': 1640787949,
  'httpOnly': False,
  'name': '_ga',
  'path': '/',
  'secure': False,
  'value': 'GA1.2.1111111111.1111111111'},
 {'domain': 'website.com',
  'expiry': 1585488346,
  'httpOnly': False,
  'name': '__pnahc',
  'path': '/',
  'secure': False,
  'value': '0'}]

我现在已经按下面的答案加载了cookie,但是它们似乎没有被正确加载,因为它们不记得任何内容,但是如果我在Selenium浏览时加载cookie,它们可以正常工作。


你有遇到任何异常吗?因为initial_state.cookies导致了AttributeError - zamir
不,只是一个“list' object ...”的错误,这些cookies已经通过Selenium被转储到了文件中,使用以下代码:with open("Filepath.pkl", 'wb') as f: pickle.dump(driver.get_cookies(), f) - no nein
你能举个例子展示driver.get_cookies()的返回结果吗? - zamir
使用 JSON 存储 cookie。它应该可以正常工作。 - SilentGuy
6个回答

6

Cookie

Cookie HTTP请求头包含了之前由服务器使用Set-Cookie头发送的存储的HTTP cookieHTTP cookie是服务器发送给用户Web浏览器的一小段数据。浏览器可以存储cookie并在下一次请求相同服务器时将其发送回来。通常,用于判断两个请求是否来自同一个浏览器,保持用户登录状态。


使用Selenium演示

为了演示使用Selenium的cookie,我们在用户登录http://demo.guru99.com/test/cookie/selenium_aut.php后,使用存储了cookie。接下来,我们打开同一网站并添加cookie,成功以已登录用户身份登陆。

  • Code Block to store the cookies:

    from selenium import webdriver
    import pickle
    
    options = webdriver.ChromeOptions() 
    options.add_argument("start-maximized")
    options.add_experimental_option("excludeSwitches", ["enable-automation"])
    options.add_experimental_option('useAutomationExtension', False)
    driver = webdriver.Chrome(options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe')
    driver.get('http://demo.guru99.com/test/cookie/selenium_aut.php')
    driver.find_element_by_name("username").send_keys("abc123")
    driver.find_element_by_name("password").send_keys("123xyz")
    driver.find_element_by_name("submit").click()
    pickle.dump( driver.get_cookies() , open("cookies.pkl","wb"))
    
  • Code Block to use the stored cookies for automatic authentication:

    from selenium import webdriver
    import pickle
    
    options = webdriver.ChromeOptions() 
    options.add_argument("start-maximized")
    options.add_experimental_option("excludeSwitches", ["enable-automation"])
    options.add_experimental_option('useAutomationExtension', False)
    driver = webdriver.Chrome(options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe')
    driver.get('http://demo.guru99.com/test/cookie/selenium_aut.php')
    cookies = pickle.load(open("cookies.pkl", "rb"))
    for cookie in cookies:
        driver.add_cookie(cookie)
    driver.get('http://demo.guru99.com/test/cookie/selenium_cookie.php')
    

使用Requests进行演示

为了演示使用来处理cookies,我们访问了https://www.google.com网站,并添加了一个新的cookies字典:

{'name':'my_own_cookie','value': 'debanjan' ,'domain':'.stackoverflow.com'}

接下来,我们使用相同的requests会话发送了另一个请求,成功的响应如下:
  • Code Block:

    import requests
    
    s1 = requests.session()
    s1.get('https://www.google.com')
    print("Original Cookies")
    print(s1.cookies)
    print("==========")
    cookie = {'name':'my_own_cookie','value': 'debanjan' ,'domain':'.stackoverflow.com'}
    s1.cookies.update(cookie)
    print("After new Cookie added")
    print(s1.cookies)
    
  • Console Output:

    Original Cookies
    <RequestsCookieJar[<Cookie 1P_JAR=2020-01-21-14 for .google.com/>, <Cookie NID=196=NvZMMRzKeV6VI1xEqjgbzJ4r_3WCeWWjitKhllxwXUwQcXZHIMRNz_BPo6ujQduYCJMOJgChTQmXSs6yKX7lxcfusbrBMVBN_qLxLIEah5iSBlkdBxotbwfaFHMd-z5E540x02-YZtCm-rAIx-MRCJeFGK2E_EKdZaxTw-StRYg for .google.com/>]>
    ==========
    After new Cookie added
    <RequestsCookieJar[<Cookie domain=.stackoverflow.com for />, <Cookie name=my_own_cookie for />, <Cookie value=debanjan for />, <Cookie 1P_JAR=2020-01-21-14 for .google.com/>, <Cookie NID=196=NvZMMRzKeV6VI1xEqjgbzJ4r_3WCeWWjitKhllxwXUwQcXZHIMRNz_BPo6ujQduYCJMOJgChTQmXSs6yKX7lxcfusbrBMVBN_qLxLIEah5iSBlkdBxotbwfaFHMd-z5E540x02-YZtCm-rAIx-MRCJeFGK2E_EKdZaxTw-StRYg for .google.com/>]>
    

结论

很明显,新添加的cookie字典{'name':'my_own_cookie','value': 'debanjan' ,'domain':'.stackoverflow.com'}在第二个请求中被广泛使用。


将Selenium Cookies传递给Python Requests

如果您的使用情况是将Selenium Cookies传递给Python Requests,您可以使用以下解决方案:

from selenium import webdriver
import pickle
import requests

options = webdriver.ChromeOptions() 
options.add_argument("start-maximized")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe')
driver.get('http://demo.guru99.com/test/cookie/selenium_aut.php')
driver.find_element_by_name("username").send_keys("abc123")
driver.find_element_by_name("password").send_keys("123xyz")
driver.find_element_by_name("submit").click()

# Storing cookies through Selenium
pickle.dump( driver.get_cookies() , open("cookies.pkl","wb"))
driver.quit()

# Passing cookies to Session
session = requests.session()  # or an existing session
with open('cookies.pkl', 'rb') as f:
    session.cookies.update(pickle.load(f))
search_requests = session.get('https://www.google.com/')
print(session.cookies)

有趣的是,如果涉及不同的域名,似乎您答案的最后一部分不能轻易颠倒。从Selenium会话中移动Cookie到WebDriver会话中是不可能的,如果这些Cookie针对不同的域设置,正如一些链接回答和上游错误报告所示:https://github.com/w3c/webdriver/issues/1238 - stefanct
session.cookies.update(pickle.load(f)) 抛出 ValueError: too many values to unpack (expected 2) 异常。 - curious_nustian
补充我的上一个评论,@Jortega 的回答将解决这个问题。 - curious_nustian

3

由于你正在用一个不具备这些属性的列表(list)替换session.cookies(RequestsCookieJar),所以它行不通。

你可以使用以下方式逐个导入这些cookie:

for c in your_cookies_list:
   initial_state.cookies.set(name=c['name'], value=c['value'])

我尝试加载整个cookie,但似乎requests无法识别它们并返回:

TypeError: create_cookie() got unexpected keyword arguments: ['expiry', 'httpOnly']

在IT技术方面,requests接受expires参数,而HttpOnly嵌套在rest参数中。

更新:

我们也可以更改字典键expiryhttpOnly,以便requests正确加载它们,而不是抛出异常,通过使用dict.pop()从字典中删除一个项目,通过key返回已删除keyvalue,然后将其添加为新的key,最后将其解压缩并作为kwargs传递:

for c in your_cookies_list:
    c['expires'] = c.pop('expiry')
    c['rest'] = {'HttpOnly': c.pop('httpOnly')}
    initial_state.cookies.set(**c)

但是,这些 Cookie 是否不包含域名和其他所有度量指标? - no nein
我尝试了 Mashable(一个需要同意 Cookie 的随机网站,因为我在美国以外),但是我加载了 Cookie,但在我的 Selenium 实例中它没有注册我点击“我同意”的操作。有任何想法出了什么问题吗? - no nein
@nonein 我不太明白你想要达到什么目的,能否提供一个可重现的例子来详细说明一下? - zamir
抱歉表述不够清晰。我的意思是想访问需要cookies的网站,例如同意表单、登录等,例如进入我的stackoverflow账户并在我收到帖子通知时发送电子邮件给我。我的想法是使用Selenium创建cookies(同意同意表单,登录到stackoverflow等),然后在拉取页面时重新加载请求中的cookies。如果这样说不清楚,请告诉我,否则我将用更长的解释修改我的答案。 - no nein
2
@nonein 我认为你可以只使用 requests.Session 而不需要使用 selenium 来实现。 - zamir
显示剩余2条评论

0

0

所以requests希望cookie中的所有“值”都是字符串。 “键”可能也是如此。 Cookies还不希望您的函数load_cookies返回列表。 可以使用cookies = requests.utils.cookiejar_from_dict(...为请求工具创建cookie。

假设我使用selenium访问“https://stackoverflow.com/”并像您一样保存cookie。

from selenium import webdriver
import pickle
import requests

#Go to the website
driver = webdriver.Chrome(executable_path=r'C:\Path\\To\\Your\\chromedriver.exe')
driver.get('https://stackoverflow.com/')

#Save the cookies in a file
with open("C:\Path\To\Your\Filepath.pkl", 'wb') as f:
    pickle.dump(driver.get_cookies(), f)

driver.quit()
#you function to get the cookies from the file.
def load_cookies(filename):
  with open(filename, 'rb') as f:
    return pickle.load(f)

saved_cookies_list = load_cookies("C:\Path\To\Your\Filepath.pkl")

#Set request session
initial_state = requests.Session()
#Function to fix cookie values and add cookies to request_session
def fix_cookies_and_load_to_requests(cookie_list, request_session):
    for index in range(len(cookie_list)):
        for item in cookie_list[index]:
            if type(cookie_list[index][item]) != str:
                print("Fix cookie value: ", cookie_list[index][item])
                cookie_list[index][item] = str(cookie_list[index][item])
        cookies = requests.utils.cookiejar_from_dict(cookie_list[index])
        request_session.cookies.update(cookies)
    return request_session

initial_state_with_cookies = fix_cookies_and_load_to_requests(cookie_list=saved_cookies_list, request_session=initial_state)

search_requests = initial_state_with_cookies.get("https://stackoverflow.com/")
print("search_requests:", search_requests)

如果您需要帮助,使键不是字符串,我们也可以处理。 - Jortega

0

您可以获取cookie并仅使用名称/值。您还需要头文件。您可以从开发工具或使用代理获取它们。

基本示例:

driver.get('https://website.com/')

# ... login or do anything

cookies = {}
for cookie in driver.get_cookies():
    cookies[cookie['name']] = cookie['value']
# Write to a file if need or do something
# import json
# with open("cookies.txt", 'w') as f:
#    f.write(json.dumps(cookies))

并用法:

# Read cookies from file as Dict
# with open('cookies.txt') as reader:
#     cookies = json.loads(reader.read())

# use cookies
response = requests.get('https://website.com/', headers=headers, cookies=cookies)

Stackoverflow 的头部示例,有些头部可能是必需的,有些则不是。您可以在 这里这里 找到相关信息。您可以使用开发工具中的网络选项卡获取请求头:

headers = {
    'authority': 'stackoverflow.com',
    'pragma': 'no-cache',
    'cache-control': 'no-cache',
    'dnt': '1',
    'upgrade-insecure-requests': '1',
    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36',
    'sec-fetch-user': '?1',
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    'sec-fetch-site': 'same-origin',
    'sec-fetch-mode': 'navigate',
    'referer': 'https://stackoverflow.com/questions/tagged?sort=Newest&tagMode=Watched&uqlId=8338',
    'accept-encoding': 'gzip, deflate, br',
    'accept-language': 'ru,en-US;q=0.9,en;q=0.8,tr;q=0.7',
}

我从未见过其他人提到除了cookies之外,我还需要headers,你能给我一个它们长什么样子的例子吗? - no nein
你可以在答案更新中找到有关请求头的信息。 - Sers

0
你可以创建一个会话。会话类处理请求之间的 cookie。
s = requests.Session()


login_resp = s.post('https://example.com/login', login_data)
self.cookies = self.login_resp.cookies



cookiedictreceived = {}
cookiedictreceived=requests.utils.dict_from_cookiejar(self.login_resp.cookies)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接