Redis存储Cookie实现爬虫保持登录 requests | selenium
前言
前面已经介绍了requests和selenium这两种方式的基础知识和模拟登录,但是我们需要每次都进行登录,这明显是很麻烦并且不合理的,所以这次我分享一下怎么可以让我们的程序进行一次登录之后,和普通浏览器一样下次不进行登录直接进行对网站数据的爬取
下面的我分享的内容需要前置知识,如果同志有知识不理解,可以查看我以前写的文章
Python爬虫request三方库实战-CSDN博客
Python爬虫 XPath 三方库lxml-CSDN博客
Python爬虫 模拟登录 requests版-CSDN博客
selenium基础知识 和 模拟登录selenium版本-CSDN博客
目录
保持登录的核心原理
保持登录request版本
保持登录selenium版本
保持登录的核心原理
市面上基本上所有的网站都把登录的信息存储到浏览器的Cookie里面了。
无论他使用什么方式进行登录,基本上都要先拿到浏览器的请求头Cookie信息作为依据给出登录状态的响应。
当然也有极少数的网站选择请求头Authorization信息作为依据给出登录状态的响应。
如果Cookie不可以,可以往这方面排查。
所以我们的核心操作就是在第一次模拟登录的时候对Cookie进行存储,然后以后对这个网站进行请求的时候带上我们在第一次模拟登录的时候获取的请求头。
请求头Authorization信息也是同样的思路,只是存储和获取的请求头不一样,原理是相通的。
我下面把Cookie存储到redis为例,给出代码示例和详细操作流程。
保持登录request版本
在没有反爬机制的情况下,我们直接拿到请求登录接口返回的Cookie值,把它保存到一个地方
然后在我们请求这个网站的网址的时候带上这个Cookie值就保证了登录状态了
因为请求登录接口返回的Cookie值是一个对象,所以我们要进行二进制的序列化进行存储
我存储到Redis中为例
对redis数据库进行链接
import redis#链接redis
redis_client = redis.StrictRedis(host='redis数据库的IP',port=端口号,db=0,password='redis密码', # 添加密码参数decode_responses=False # 禁止自动解码返回值为字符串,因为存储是pickle序列化之后的二进制数据
)
将请求接口返回的Cookie值存储到Redis中
import pickle# loginResponse是requests请求登录接口的响应对象
# 因为loginResponse.cookie一个RequestsCookieJar类型,需要使用pickle进行序列化存储到redis
# 存储的时候使用pickle做一个序列化转化为二进制进行存储
redis_client.setex("Cookie", 86400, pickle.dumps(loginResponse.cookies))
从Redis中取出Cookie,请求网站网址的时候请求头加上Cookie保持登录
import pickle#尝试从redis进行获取Cookie
Cookie = redis_client.get("Cookie")#redis存储的cookie是序列化的,所以要进行反序列化才能使用
Cookie = pickle.loads(Cookie)
完整示例
对某车市网站进行爬取
import requests
from lxml import etree
import pickle
import redis#链接redis
redis_client = redis.StrictRedis(host='redis数据库的IP',port=redis数据库端口号,db=0,password='redis数据库密码', # 添加密码参数decode_responses=False # 禁止自动解码返回值为字符串,因为存储是pickle序列化之后的二进制数据
)url = "目标请求网址"headers = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
}#尝试从redis进行获取cheshiCookie
cheshiCookie = redis_client.get("cheshiCookie")if cheshiCookie:#redis存储的cookie是序列化的,所以要进行反序列化才能使用cheshiCookie = pickle.loads(cheshiCookie)#redis存储的cookie是序列化的,所以要进行反序列化才能使用cheshiCookie = pickle.loads(cheshiCookie)res1 = requests.get(url, headers=headers, cookies=cheshiCookie)
else:res1 = requests.get(url, headers=headers)datas = etree.HTML(res1.text)
#获取页面是否有登录页面的特征,我这里使用XPath定位《账号登录》这个文本是否可以获取到来判断这个页面是不是登录页面
loginName = datas.xpath('//div[@class="userlogin"]//span[2]/text()')#这个页面可以获取账号登录这个文本,说明是登录页面,需要进行登录
if loginName and loginName[0] == "账号登录":loginUrl = "登录接口"loginData = {"key1": "value1","key2": "value2","key3": "value3"}loginResponse = requests.post(loginUrl, data=loginData, headers=headers)# 因为loginResponse.cookie一个RequestsCookieJar类型,需要使用pickle进行序列化存储到redisredis_client.setex("cheshiCookie", 86400, pickle.dumps(loginResponse.cookies))#再次请求需要登录的请求地址,加上Cookie,此时就是登录状态了res2 = requests.get(url, headers=headers,cookies=loginResponse.cookies)print(res2.text)
else:print(res1.text)
如果网址的Cookie不是从登录接口响应的时候直接给你的,给一些原材料进行加密处理,这个时候要进行自行探索了,原理就是得到Cookie存储起来,下次请求网址的时候带上,保持登录状态进行请求
保持登录selenium版本
因为Requests方式进行保持登录,网站登录接口稍微有点加密就基本上搞不了了。
所以我们还有一种简单粗暴的方式,控制浏览器,进行登录,登录完成之后会跳转登录之后的页面,把登录之后的页面上的Cookie直接存储到Redis中。
就跟真人取浏览器上面登录状态网站的Cookie是一样的
因为是直接从浏览器的网址上面拿到的Cookie,所以是一个JSON字符串,需要序列化成JSON字符串进行存储到Redis
对Redis数据库进行链接
import redis#链接redis
redis_client = redis.StrictRedis(host='redis数据库的IP',port=端口号,db=0,password='redis密码', # 添加密码参数decode_responses=True # 禁止自动解码返回值为字符串,因为存储是pickle序列化之后的二进制数据
)
将拿到的Cookie序列化成JSON字符串存储到Redis中
# 序列化成 JSON 字符串并存入 Redis
redis_client.set("Cookie", json.dumps(cookies))
从Redis中取Cookie并还原成JSON字符串,并注入到当前selenium浏览器驱动driver中
一定要先打开请求网址再注入Cookie,注入的Cookie是指对当前页面进行Cookie注入
import json#获取redis里面存储cookie的json字符串
Cookie = redis_client.get("Cookie")
cookies = json.loads(Cookie)
# 逐个注入 Cookie
for cookie in cookies:driver.add_cookie(cookie)
完整示例
对某淘网站的商品信息进行爬取
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support import expected_conditions as EC
import redis
import json#链接redis
redis_client = redis.StrictRedis(host='redis数据库IP',port=redis数据库端口,db=0,password='redis数据库密码', # 添加密码参数decode_responses=True # 自动解码返回值为字符串
)
#获取redis里面存储cookie的json字符串
taobaoCookie = redis_client.get("taobaoCookie")# selenium 4的写法
options = Options()
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36")
options.add_argument("--window-size=1920,1080") # 设置窗口大小
options.add_argument("--disable-blink-features=AutomationControlled") # 禁用自动化控制特征
options.add_argument("--disable-infobars") # 禁用提示条
options.add_argument("--no-sandbox") # 解决DevToolsActivePort文件不存在的报错
options.add_argument("--disable-dev-shm-usage") # 禁用共享内存
options.add_argument("--disable-extensions") # 禁用扩展
options.add_argument("--disable-gpu") # 禁用GPU加速
options.add_argument("--disable-javascript") # 禁用JavaScript(根据需求调整)
options.add_argument("--incognito") # 隐身模式
driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager(driver_version="谷歌浏览器版本号").install()),options=options)
driver.get("目标请求网址")
#如果redis获取到taobaoCookie就加上,没有后面登录获取
if taobaoCookie:cookies = json.loads(taobaoCookie)# 逐个注入 Cookiefor cookie in cookies:driver.add_cookie(cookie)#看是否可以获得网站标签来确定网站是否加载完毕
title = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH,'//h1[@class="xM6AVLCbLn--mainTitle--_90838ca f-els-2"]')))#获取一键登录的标签,这里使用了返回集合标签的方法,因为有可能获取不到,返回空集合,不至于报错
loginHTML = driver.find_elements(By.XPATH,'//span[@class="xM6AVLCbLn--loginBtn--_3aec1d3"]')if not loginHTML:#发现没有一键登录标签说明已经登录了pass
else:#有一键登录标签需要登录,并把登录的Cookie信息存储到redis用来下次使用#这一步也可以防止Cookie登录失效,失效了和没有Cookie是一样的也会到这一步actions = ActionChains(driver).click(loginHTML[0]).perform()usern = driver.find_element(By.XPATH,'//input[@id="fm-login-id"]')pwd = driver.find_element(By.XPATH,'//input[@id="fm-login-password"]')loginHb = driver.find_element(By.XPATH,'//button[@class="fm-button fm-submit password-login button-low-light"]')ActionChains(driver).click(usern).pause(1).send_keys('用户名').pause(0.5).perform()ActionChains(driver).click(pwd).pause(1).send_keys('密码').pause(0.5).perform()ActionChains(driver).click(loginHb).perform()resFlag = WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.XPATH,'//div[@class="xM6AVLCbLn--tabDetailWrap--_3622a08"]')))# 获取 Cookies(列表形式)cookies = driver.get_cookies()# 序列化成 JSON 字符串并存入 Redisredis_client.set("taobaoCookie", json.dumps(cookies))#把这个商品的所有颜色和大小搭配全部获取下来
skuColorHTMLList = driver.find_elements(By.XPATH,'//div[@class="xM6AVLCbLn--skuWrapper--e63a4df5"]//div[@class="xM6AVLCbLn--skuItem--_68c0cae"][1]//div[contains(@class,"xM6AVLCbLn--valueItem--ee898cc0")]')
skuSizeHTMLList = driver.find_elements(By.XPATH,'//div[@class="xM6AVLCbLn--skuWrapper--e63a4df5"]//div[@class="xM6AVLCbLn--skuItem--_68c0cae"][2]//div[contains(@class,"xM6AVLCbLn--valueItem--ee898cc0")]')for skuColorHTML in skuColorHTMLList:#先点击颜色分类actions = ActionChains(driver).click(skuColorHTML).perform()for skuSizeHTML in skuSizeHTMLList:#后点击大小分类actions = ActionChains(driver).click(skuSizeHTML).perform()#过滤获取值存储,这里省略#最后关闭浏览器
driver.quit()