閑來無事,寫一個模擬登錄知乎的小demo。
分析網頁發現:登錄需要的手機號,密碼,_xsrf參數,驗證碼
實現思路:
1、獲取驗證碼
2、獲取_xsrf 參數
3、攜帶參數,請求登錄
驗證碼url : "https://www.zhihu.com/captcha.gif?r={t}&type=login&lang=en".format(t=t) # t 為時間戳
登錄界面url : "https://www.zhihu.com/#signin"
手機登錄申請url : 'https://www.zhihu.com/login/phone_num'
實現代碼:
首先配置文件 settings 中 ROBOTSTXT_OBEY = False
1、開頭及驗證碼處理部分,先重寫scrapy的start_requests方法。其次利用Pillow 來處理驗證碼,將驗證碼顯示出來,手動填寫(畢竟打碼是需要費用的),知乎默認的驗證碼為中文,經分析發現驗證碼url 后面的 lang 參數決定語言,所以試着將語言改為英文(en)
# -*- coding: utf-8 -*- import scrapy import time import json from PIL import Image class ZhihuSpider(scrapy.Spider): name = 'zhihu' allowed_domains = ['www.zhihu.com'] # 重寫start_requests方法,處理驗證碼問題 def start_requests(self): t = str(time.time()).replace('','.') # 驗證碼url start_urls = "https://www.zhihu.com/captcha.gif?r={t}&type=login&lang=en".format(t=t) self.header ={ "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", 'Referer':' https: // www.zhihu.com /' } # 請求驗證碼的url return [scrapy.Request(url=start_urls,headers=self.header,callback=self.capcha,dont_filter=True)] # 獲取驗證碼 def capcha(self,response): # 獲取驗證碼,將驗證馬寫入本地 with open('capcha.jpg','wb') as f: f.write(response.body) try: # 利用pillow打開驗證碼 im = Image.open('capcha.jpg') im.show() except: print('請打開文件%s自行輸入'%("capcha.jpg")) cap = input("請輸入驗證碼>>") data = { "cap":cap } log_url = "https://www.zhihu.com/#signin" return scrapy.Request(url=log_url,callback=self.parse_login,headers=self.header,meta=data,dont_filter=True)
2、得到驗證碼后,開始搞_xsrf參數,從登錄源碼中分析得到_xsrf 在屬性為name="_xsrf" 的input 節點中的value值
# 解析申請登陸的頁面,獲取參數xsrf def parse_login(self,response): xsrf = response.xpath('//input[@name="_xsrf"]/@value').extract_first() if not xsrf: print("請求錯誤") return '' phone_num = input("請輸入手機號碼") password = input("請輸入密碼") data = { 'captcha':response.meta['cap'], '_xsrf':xsrf, 'password':password, 'captcha_type':' en', 'phone_num':phone_num } # 用手機號-密碼 登錄的url url = 'https://www.zhihu.com/login/phone_num' return scrapy.FormRequest(url=url,callback=self.login_zh,headers=self.header,formdata=data,dont_filter=True,meta={'direct_list': [301, 302], 'direct_ignore': True})
3、參數都獲取到后就可以模擬登錄了
# 驗證是否登錄成功 def login_zh(self,response): print(json.loads(response.text)['msg']) url = "https://www.zhihu.com/#signin" # 請求登錄知乎 yield scrapy.Request(url=url,callback=self.zh,headers=self.header,dont_filter=True,meta={'direct_list':[301,302],'direct_ignore':True}) # 后續解析知乎登錄后的頁面 def zh(self,response): print(response.text)
本次登錄后,並未對頁面進行解析,只是打印一下頁面,作為驗證。