前言
前面已經介紹了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()