Python爬虫从入门到放弃(二十四)之 Scrapy登录知乎

简介: 因为现在很多网站为了限制爬虫,设置了为只有登录才能看更多的内容,不登录只能看到部分内容,这也是一种反爬虫的手段,所以这个文章通过模拟登录知乎来作为例子,演示如何通过scrapy登录知乎 在通过scrapy登录知乎之前,我们先通过requests模块登录知乎,来熟悉这个登录过程 不过在这之前需要了...

因为现在很多网站为了限制爬虫,设置了为只有登录才能看更多的内容,不登录只能看到部分内容,这也是一种反爬虫的手段,所以这个文章通过模拟登录知乎来作为例子,演示如何通过scrapy登录知乎

在通过scrapy登录知乎之前,我们先通过requests模块登录知乎,来熟悉这个登录过程

不过在这之前需要了解的知识有:

cookie和session
关于cookie和session我之前整理了一篇博客供参考:
http://www.cnblogs.com/zhaof/p/7211253.html
requests模块的会话维持功能:
这个我在 http://www.cnblogs.com/zhaof/p/6915127.html 关于requests模块中也已经做了整理
主要内容如下,详细内容可参考上面那篇关于requests模块使用的文章
会话维持
cookie的一个作用就是可以用于模拟登陆,做会话维持

import requests
s = requests.Session()
s.get("http://httpbin.org/cookies/set/number/123456")
response = s.get("http://httpbin.org/cookies")
print(response.text)

这是正确的写法,而下面的写法则是错误的

import requests
requests.get("http://httpbin.org/cookies/set/number/123456")
response = requests.get("http://httpbin.org/cookies")
print(response.text)

因为这种方式是两次requests请求之间是独立的,而第一次则是通过创建一个session对象,两次请求都通过这个对象访问
关于爬虫常见登录的方法
这里我之前的文章 http://www.cnblogs.com/zhaof/p/7284312.html 也整理的常用的爬虫登录方法
这点是非常重要的

只有上面这些基础的内容都已经掌握,才能完成下面内容

非框架登录知乎

这里我测试的结果是通过爬虫登录知乎的时候必须携带验证码,否则会提示验证码错误,下面是关于如果没有带验证码时候提示的错误,这个错误可能刚开始写登录知乎的时候都会碰到,所以这里我把这段代码贴出来:

import json
import requests
from bs4 import BeautifulSoup

headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
}

#这里是非常关键的
session = requests.session()

def get_index():
    '''
    用于获取知乎首页的html内容
    :return:
    '''
    response = session.get("http://www.zhihu.com",headers=headers)
    return response.text

def get_xsrf():
    '''
    用于获取xsrf值
    :return:
    '''
    html = get_index()
    soup = BeautifulSoup(html,'lxml')
    res = soup.find("input",attrs={"name":"_xsrf"}).get("value")
    return res


def zhihu_login(account,password):
    '''
    知乎登录
    :param account:
    :param password:
    :return:
    '''
    _xsrf = get_xsrf()
    post_url = "https://www.zhihu.com/login/phone_num"

    post_data = {
        "_xsrf":_xsrf,
        "phone_num":account,
        "password":password,
    }
    response = session.post(post_url,data=post_data,headers=headers)
    res = json.loads(response.text)
    print(res)


zhihu_login('13121210484','********')

上述代码当你的用户名和密码都正确的时候最后结果会打印如下内容:

我猜测是可能知乎识别了这是一个爬虫,所以让每次登陆都需要验证码,其实这个时候你正常通过浏览器登陆知乎并不会让你输入验证码,所以这里我们需要获去验证码并将验证码传递到请求参数中,我们分析登录页面就可当登录页需要输入验证码的时候,我们点击验证码会生成新的验证码,抓包分析如下:

这行我们就获得了生成验证码的地址:
https://www.zhihu.com/captcha.gif?r=1503303312357&type=login
这个时候我们登录的时候传递的参数中就会增加captcha参数

所以我们将上面的代码进行更改,添加验证码参数

import json
import requests
from bs4 import BeautifulSoup

headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
}

#这里是非常关键的
session = requests.session()


def get_index():
    '''
    用于获取知乎首页的html内容
    :return:
    '''
    response = session.get("http://www.zhihu.com",headers=headers)
    return response.text

def get_xsrf():
    '''
    用于获取xsrf值
    :return:
    '''
    html = get_index()
    soup = BeautifulSoup(html,'lxml')
    res = soup.find("input",attrs={"name":"_xsrf"}).get("value")
    return res


def get_captcha():
    '''
    获取验证码图片
    :return:
    '''
    import time
    t = str(int(time.time()*1000))
    captcha_url = "https://www.zhihu.com/captcha.gif?r={0}&type=login".format(t)
    t = session.get(captcha_url,headers=headers)
    with open("captcha.jpg","wb") as f:
        f.write(t.content)

    try:
        from PIL import Image
        im = Image.open("captcha.jpg")
        im.show()
        im.close()
    except:
        pass

    captcha = input("输入验证码>")
    return captcha


def zhihu_login(account,password):
    '''
    知乎登录
    :param account:
    :param password:
    :return:
    '''
    _xsrf = get_xsrf()
    post_url = "https://www.zhihu.com/login/phone_num"
    captcha = get_captcha()

    post_data = {
        "_xsrf":_xsrf,
        "phone_num":account,
        "password":password,
        'captcha':captcha,
    }
    response = session.post(post_url,data=post_data,headers=headers)
    res = json.loads(response.text)
    print(res)


zhihu_login('13121210484','******')

这样我们再次登录就会发现结果如下,表示登录成功:

这里要说明的一个问题是这里的验证码并没有接打码平台,所以是手工输入的。

scrapy登录知乎

我们上面已经通过非框架的模式即requests模块的方式成功登录了知乎,现在就是把上面的代码功能在scrapy中实现,这里有一个非常重要的地方,上面的代码中为了会话维持,我们通过:
session = requests.session()
那么我们如何在scrapy中实现呢?

这里就是通过yield,完整代码如下(这里的爬虫是在scrapy项目里直接生成的一个爬虫):

import json
import re

import scrapy
from urllib import parse

class ZhihuSpider(scrapy.Spider):
    name = "zhihu"
    allowed_domains = ["www.zhihu.com"]
    start_urls = ['https://www.zhihu.com/']
    headers = {
        'User-Agent':"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",

    }

    def start_requests(self):
        '''
        重写start_requests,请求登录页面
        :return:
        '''
        return [scrapy.Request('https://www.zhihu.com/#signin',headers=self.headers,callback=self.login)]


    def login(self,response):
        '''
        先通过正则获取xsrf值,然后通过scrapy.Request请求验证页面获取验证码
        :param response:
        :return:
        '''
        response_text = response.text
        match_obj = re.match('.*name="_xsrf" value="(.*?)"',response_text,re.DOTALL)
        print(match_obj.group(1))
        xsrf=''
        if match_obj:
            xsrf = match_obj.group(1)
        if xsrf:
            post_data = {
                "_xsrf":xsrf,
                "phone_num":"13121210484",
                "password":"********",
                'captcha':'',
            }
            import time
            t = str(int(time.time() * 1000))
            captcha_url = "https://www.zhihu.com/captcha.gif?r={0}&type=login".format(t)
            #这里利用meta讲post_data传递到后面的response中
            yield scrapy.Request(captcha_url,headers=self.headers,meta={"post_data":post_data} ,callback=self.login_after_captcha)

    def login_after_captcha(self,response):
        '''
        将验证码写入到文件中,然后登录
        :param response:
        :return:
        '''
        with open("captcha.jpg",'wb') as f:
            f.write(response.body)
        try:
            from PIL import Image
            im = Image.open("captcha.jpg")
            im.show()

        except:
            pass
        #提示用户输入验证码
        captcha = input("请输入验证码>:").strip()
        #从response中的meta中获取post_data并赋值验证码信息
        post_data = response.meta.get("post_data")
        post_data["captcha"] = captcha
        post_url = "https://www.zhihu.com/login/phone_num"
        # 这里是通过scrapy.FormRequest提交form表单
        return [scrapy.FormRequest(
            url=post_url,
            formdata=post_data,
            headers=self.headers,
            callback=self.check_login,
        )]

    def check_login(self,response):
        '''
        验证服务器的返回数据判断是否成功,我们使用scrapy会自动携带我们登录后的cookie
        :param response:
        :return:
        '''
        text_json = json.loads(response.text)
        print(text_json)
        for url in self.start_urls:
            yield self.make_requests_from_url(url,dont_filter=True,header=self.headers)

上述代码中:

yield scrapy.Request(captcha_url,headers=self.headers,meta={"post_data":post_data} ,callback=self.login_after_captcha)

原本scrapy中的scrapy.Request会保存访问过程中的cookie信息其实这里面也是用也是cookiejar,这里通过yield 的方式实现了与会话的维持
我们通过调试登录,如下,同样也登录成功:

 

所有的努力都值得期许,每一份梦想都应该灌溉!
目录
相关文章
|
4天前
|
数据采集 机器学习/深度学习 人工智能
Python编程入门:从零基础到实战应用
【9月更文挑战第15天】本文将引导读者从零开始学习Python编程,通过简单易懂的语言和实例,帮助初学者掌握Python的基本语法和常用库,最终实现一个简单的实战项目。文章结构清晰,分为基础知识、进阶技巧和实战应用三个部分,逐步深入,让读者在学习过程中不断积累经验,提高编程能力。
|
3天前
|
开发框架 缓存 数据库
探索Python中的装饰器:从入门到实践
【8月更文挑战第48天】本文将引导你进入Python装饰器的奇妙世界。不同于传统的“摘要”格式,我们将通过一段代码的演变,直观展示装饰器的魅力。文章不仅介绍基础概念,还将通过实例演示如何自定义装饰器,并探讨其在实际应用中的强大用途。让我们开始吧,一起深入理解这个改变函数行为的强大工具!
|
1天前
|
人工智能 数据挖掘 开发者
Python编程入门:从基础到实战
【9月更文挑战第18天】本文将带你走进Python的世界,从最基本的语法开始,逐步深入到实际的项目应用。无论你是编程新手,还是有一定基础的开发者,都能在这篇文章中找到你需要的内容。我们将通过详细的代码示例和清晰的解释,让你轻松掌握Python编程。
15 5
|
3天前
|
Python
全网最适合入门的面向对象编程教程:Python函数方法与接口-函数与方法的区别和lamda匿名函数
【9月更文挑战第15天】在 Python 中,函数与方法有所区别:函数是独立的代码块,可通过函数名直接调用,不依赖特定类或对象;方法则是与类或对象关联的函数,通常在类内部定义并通过对象调用。Lambda 函数是一种简洁的匿名函数定义方式,常用于简单的操作或作为其他函数的参数。根据需求,可选择使用函数、方法或 lambda 函数来实现代码逻辑。
|
3天前
|
存储 机器学习/深度学习 数据挖掘
深入浅出:Python编程入门与实践
【9月更文挑战第16天】本文以“深入浅出”的方式,引领读者步入Python编程的世界。从基础语法到实际应用,我们将一步步探索Python的魅力所在。无论你是编程新手,还是希望拓展技能的老手,这篇文章都将为你提供有价值的信息和指导。通过本文的学习,你将能够编写出简单而实用的Python程序,为进一步深入学习打下坚实的基础。让我们一起开始这段编程之旅吧!
|
9天前
|
存储 人工智能 数据挖掘
Python编程入门:从基础到实战
【9月更文挑战第10天】本文将引导你进入Python编程的世界,从基本语法到实际项目应用,逐步深入。我们将通过简单的例子和代码片段,帮助你理解并掌握Python编程的精髓。无论你是编程新手还是有一定经验的开发者,都能在这篇文章中找到有价值的信息。让我们一起开始Python编程之旅吧!
|
3天前
|
机器学习/深度学习 数据挖掘 程序员
Python编程基础:从入门到实践
【9月更文挑战第16天】本文是一篇Python编程的入门教程,旨在帮助初学者理解Python的基本概念和语法。文章首先介绍了Python的历史和特点,然后详细讲解了Python的基本语法,包括变量、数据类型、运算符、控制结构等。接着,文章通过一些实例代码,展示了如何使用Python进行基本的编程操作,如输入输出、条件判断、循环等。最后,文章还提供了一些学习资源和建议,帮助读者进一步学习和掌握Python编程。
|
2天前
|
数据采集 存储 JSON
从零到一构建网络爬虫帝国:HTTP协议+Python requests库深度解析
在网络数据的海洋中,网络爬虫遵循HTTP协议,穿梭于互联网各处,收集宝贵信息。本文将从零开始,使用Python的requests库,深入解析HTTP协议,助你构建自己的网络爬虫帝国。首先介绍HTTP协议基础,包括请求与响应结构;然后详细介绍requests库的安装与使用,演示如何发送GET和POST请求并处理响应;最后概述爬虫构建流程及挑战,帮助你逐步掌握核心技术,畅游数据海洋。
17 3
|
2天前
|
数据采集 API 开发者
🚀告别网络爬虫小白!urllib与requests联手,Python网络请求实战全攻略
在网络的广阔世界里,Python凭借其简洁的语法和强大的库支持,成为开发网络爬虫的首选语言。本文将通过实战案例,带你探索urllib和requests两大神器的魅力。urllib作为Python内置库,虽API稍显繁琐,但有助于理解HTTP请求本质;requests则简化了请求流程,使开发者更专注于业务逻辑。从基本的网页内容抓取到处理Cookies与Session,我们将逐一剖析,助你从爬虫新手成长为高手。
15 1
|
7天前
|
SQL 安全 数据库
从入门到精通:Python Web安全守护指南,SQL注入、XSS、CSRF全防御!
【9月更文挑战第13天】在开发Python Web应用时,安全性至关重要。本文通过问答形式,详细介绍如何防范SQL注入、XSS及CSRF等常见威胁。通过使用参数化查询、HTML转义和CSRF令牌等技术,确保应用安全。附带示例代码,帮助读者从入门到精通Python Web安全。
27 6