菜鳥寫Python實戰:Scrapy完成知乎登入並儲存cookies檔案用於請求他頁面(by Selenium)
一、前言
現在知乎的登入請求越來越複雜了,通過f12調出瀏覽器網路請求情況分析request引數,似乎不再簡單可知了,因為知乎很多請求引數都字元加密顯示了,如下圖,我們很難再知道發起請求時要傳遞什麼引數給它。
二、思路
我們知道知乎一些內容是需要登入才能看到,因此在爬取時的時候要先實現login,並把登入後的Cookies儲存下來,爬取其他頁面時將登入後的cookies一起傳遞過去,就可以已登入狀態請求其他頁面,所以核心在於如何儲存cookie和載入儲存的cookies的方式來記錄使用者的身份資訊。
2.1 利用selenium模擬瀏覽器登入,非常簡單和方便;
2.2 成功登入後,將登入的cookies儲存成檔案(此處通過json儲存)-------------第一步的關鍵步驟;
2.3 之後請求其他頁面時開啟儲存cookies的json檔案,並獲取檔案中的name和value值,構建cookies的字典dict;
2.4 發起請求時,帶上cookies=之間取出的dict型別的cookies。
通過上面的過程,我們就可以實現先通過login,記錄cookies,然後在訪問請求時帶上記錄的cookies訪問即可。
三、程式碼實現
環境:win10+py3.6
工具:Pycharm
關鍵依賴庫:Scrapy+selenium + json +time
通過scrapy構造spider的過程預設熟知,如有疑問可以微信新增:第一行Python程式碼;
詳細程式碼和註釋:
# -*- coding: utf-8 -*- # 匯入依賴包 import scrapy from selenium import webdriver import time import json # 構建spider自動生成的基本配置 class ZhihuSpider(scrapy.Spider): name = 'zhihu' allowed_domains = ['www.zhihu.com'] start_urls = ['http://www.zhihu.com/'] # 模擬請求的headers,非常重要,不設定也可能知乎不讓你訪問請求 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0", "HOST": "www.zhihu.com" } # 第一步:使用selenium登入知乎並獲取登入後的cookies,cookies沒失效時,只要初次請求執行一次 def loginZhihu(self): # 登入網址 loginurl='https://www.zhihu.com/signin' # 載入webdriver驅動,用於獲取登入頁面標籤屬性 driver=webdriver.Chrome() driver.get(loginurl) # 方式1 通過填充使用者名稱和密碼 # driver.find_element_by_name('username').clear() # 獲取使用者名稱框 # driver.find_element_by_name('username').send_keys(u'username') # 填充使用者名稱 # driver.find_element_by_name('password').clear() # 獲取密碼框 # driver.find_element_by_name('password').send_keys(u'password') # 填充密碼 # time.sleep(10) # 執行休眠10s等待瀏覽器的載入 # input("檢查網頁是否有驗證碼要輸入,有就在網頁輸入驗證碼,輸入完後在編輯器中回車;如果無驗證碼,則直接回車") # 非常關鍵,有時候知乎會在輸入密碼後彈出驗證碼,這一步可將程式碼執行暫時停滯 # driver.find_element_by_css_selector("button[class='Button SignFlow-submitButton Button--primary Button--blue']").click() # 點選登入按鈕 # 方式2 直接通過掃描二維碼,如果不是要求全自動化,建議用這個,非常直接 # 畢竟我們這一步只是想儲存登入後的cookies,至於用何種方式登入,可以不必過於計較 time.sleep(10) # 同樣休眠10s等待頁面 input("請頁面二維碼,並確認登入後,點選回車:") #點選二維碼手機掃描登入 # 通過上述的方式實現登入後,其實我們的cookies在瀏覽器中已經有了,我們要做的就是獲取 cookies = driver.get_cookies() # Selenium為我們提供了get_cookies來獲取登入cookies driver.close() # 獲取cookies便可以關閉瀏覽器 # 然後的關鍵就是儲存cookies,之後請求從檔案中讀取cookies就可以省去每次都要登入一次的 # 當然可以把cookies返回回去,但是之後的每次請求都要先執行一次login沒有發揮cookies的作用 jsonCookies=json.dumps(cookies) # 通過json將cookies寫入檔案 with open('zhihuCookies.json','w') as f: f.write(jsonCookies) print(cookies) # return cookies # Scrapy使用儲存ookies請求發現模組,看是否是登入之後的狀態 def question(self,response): with open('zhihu_find.html','w',encoding='utf-8') as f: f.write(response.text) #寫入檔案,儲存成.html檔案 pass def parse(self, response): pass # scrapy請求的開始時start_request def start_requests(self): zhihu_findUrl = 'https://www.zhihu.com/explore' self.loginZhihu() # 首次使用,先執行login,儲存cookies之後便可以註釋, # 畢竟每次執行都要登入還是挺麻煩的,我們要充分利用cookies的作用 # 從檔案中獲取儲存的cookies with open('zhihuCookies.json','r',encoding='utf-8') as f: listcookies=json.loads(f.read()) # 獲取cookies # 把獲取的cookies處理成dict型別 cookies_dict = dict() for cookie in listcookies: # 在儲存成dict時,我們其實只要cookies中的name和value,而domain等其他都可以不要 cookies_dict[cookie['name']] = cookie['value'] print(cookies_dict) # Scrapy發起其他頁面請求時,帶上cookies=cookies_dict即可,同時記得帶上header值, yield scrapy.Request(url=zhihu_findUrl,cookies=cookies_dict,callback=self.question,headers=self.headers)
通過上面的方法就可以實現,在請求其他頁面時也是登入之後的狀態,畢竟cookies作用之一就是記錄狀態的,當然儲存cookies之後你也可以試試將login_zhihu()的方法註釋,去請求其他頁面,只要我們的cookies不過期,效果都是一樣的。效果如下:
當然,除了通過儲存成dict型別,在請求時通過cookies=cookies_dict外,我們可以連串成字串,新增到headers頭部中,程式碼如下:
with open('zhihuCookies.json','r',encoding='utf-8') as f:
listcookies=json.loads(f.read())
cookie=[item["name"]+"="+item["value"] for item in listcookies]
cookiestr="; ".join(item for item in cookie)
print(cookiestr)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0",
"HOST": "www.zhihu.com",
"cookie": cookiestr #從檔案中獲取並拼接的cookies
}
# 放在header是發起請求
yield scrapy.Request(url=zhihu_findUrl,callback=self.question,headers=headers)
這種方法應該也是可行的,到時我到現在還沒有成功過,不知道是不是拼接cookies是不是哪裡寫錯了,大家成了幫我看看。
需要原始碼或者有其他指教,歡迎微信新增“第一行Python程式碼”,一起學習python程式碼。