一、前言
现在知乎的登录请求越来越复杂了,通过f12调出浏览器网络请求情况分析request参数,似乎不再简单可知了,因为知乎很多请求参数都字符加密显示了,如下图,我们很难再知道发起请求时要传递什么参数给它。
那这样,我们要怎么才能登录知乎,于似乎Selenium这个神器就出现了,它可以很方便的实现登录,详细的使用方法请参见:菜鸟写Python-Selenium操作:Selenium登录豆瓣并获取cookies
二、思路
我们知道知乎一些内容是需要登录才能看到,因此在爬取时的时候要先实现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代码。