python爬虫-知乎登录,python爬虫

python爬虫-知乎登录,python爬虫

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
Required
- requests (必须)
- pillow (可选)
'''

import requests
try:
    import cookielib
except:
    import http.cookiejar as cookielib
import re
import time
import os.path
try:
    from PIL import Image
except:
    pass
#使用验证码识别库
#import pytesseract


# 构造 Request headers
agent = 'Mozilla/5.0 (Windows NT 5.1; rv:33.0) Gecko/20100101 Firefox/33.0'
headers = {
    'User-Agent': agent
}

# 使用登录cookie信息
session = requests.session()
session.cookies = cookielib.LWPCookieJar(filename='cookies')
try:
    session.cookies.load(ignore_discard=True)
except:
    print("Cookie 未能加载")


def get_xsrf():
    '''_xsrf 是一个动态变化的参数'''
    index_url = 'https://www.zhihu.com'
    # 获取登录时需要用到的_xsrf
    index_page = session.get(index_url, headers=headers)
    html = index_page.text
    pattern = r'name="_xsrf" value="(.*?)"'
    # 这里的_xsrf 返回的是一个list
    _xsrf = re.findall(pattern, html)
    return _xsrf[0]


# 获取验证码
def get_captcha():
    t = str(int(time.time()*1000))
    captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + "&type=login"
    r = session.get(captcha_url, headers=headers)
    with open('captcha.jpg', 'wb') as f:
        f.write(r.content)
        f.close()
    # 用pillow 的 Image 显示验证码
    # 如果没有安装 pillow 到源代码所在的目录去找到验证码然后手动输入
    try:
        im = Image.open('captcha.jpg')
        #使用验证码识别,系统需要安装tesseract-ocr软件
        #下载地址:https://jaist.dl.sourceforge.net/project/tesseract-ocr-alt/tesseract-ocr-setup-3.02.02.exe
        #由于验证码识别,测试识别率不高,因此暂时不使用,寻找更好的识别方法再加
        #code = pytesseract.image_to_string(im)
        #print(code)
        im.show()
        im.close()
        #if len(code)!=4:
        #    print('自动识别不出验证码,请手动输入验证码!')
        #else:
        #    captcha = code
        #    return captchac
    except:
        print(u'请到 %s 目录找到captcha.jpg 手动输入' % os.path.abspath('captcha.jpg'))
    captcha = input("please input the captcha\n>")
    return captcha


def isLogin():
    # 通过查看用户个人信息来判断是否已经登录
    url = "https://www.zhihu.com/settings/profile"
    login_code = session.get(url,allow_redirects=False).status_code
    if int(x=login_code) == 200:
        return True
    else:
        return False



def login(secret, account):
    # 通过输入的用户名判断是否是手机号
    if re.match(r"^1\d{10}$", account):
        print("手机号登录 \n")
        post_url = 'https://www.zhihu.com/login/phone_num'
        postdata = {
            '_xsrf': get_xsrf(),
            'password': secret,
            'remember_me': 'true',
            'phone_num': account,
        }
    #可加上邮箱的判断,这里不加了
    else:
        print("邮箱登录 \n")
        post_url = 'https://www.zhihu.com/login/email'
        postdata = {
            '_xsrf': get_xsrf(),
            'password': secret,
            'remember_me': 'true',
            'email': account,
        }
    try:
        # 不需要验证码直接登录成功
        login_page = session.post(post_url, data=postdata, headers=headers)
        login_code = login_page.text
        print(login_page.status)
        print(login_code)
    except:
        # 需要输入验证码后才能登录成功
        postdata["captcha"] = get_captcha()
        login_page = session.post(post_url, data=postdata, headers=headers)
        login_code = eval(login_page.text)
        print(login_code['msg'])
        return login_code['r']
    session.cookies.save()

try:
    input = raw_input
except:
    pass


if __name__ == '__main__':
    while True:
        if isLogin():
            print('您已经登录')
        else:
            account = input('请输入你的用户名\n>  ')
            secret = input("请输入你的密码\n>  ")
            result = login(secret, account)
            if result == 0:
                #爬取登录成功后的网站内容
                conf_url = "https://www.zhihu.com/settings/profile"
                text = session.get(conf_url,headers=headers).text
                print(text)
                break

以上代码在python 2.*中运行时,只需修改代码的print处即可

代码部分参考网友,代码持续更新优化中,如有错误或更优的方法欢迎大家的留言!

# !/usr/bin/env
python3 # -*- coding: utf-8 -*- ”’ Required- requests (必须)- pillow
(可选) ”’ import requests try : import cookielib…

下面我们看看用scrapy模拟登录的基本写法:

Python爬虫之模拟知乎登录的方法教程,python爬虫

前言

对于经常写爬虫的大家都知道,有些页面在登录之前是被禁止抓取的,比如知乎的话题页面就要求用户登录才能访问,而
“登录” 离不开 HTTP 中的 Cookie 技术。

登录原理

Cookie 的原理非常简单,因为 HTTP 是一种无状态的协议,因此为了在无状态的
HTTP
协议之上维护会话(session)状态,让服务器知道当前是和哪个客户在打交道,Cookie
技术出现了 ,Cookie 相当于是服务端分配给客户端的一个标识。

图片 1

  • 浏览器第一次发起 HTTP 请求时,没有携带任何 Cookie 信息
  • 服务器把 HTTP 响应,同时还有一个 Cookie 信息,一起返回给浏览器
  • 浏览器第二次请求就把服务器返回的 Cookie 信息一起发送给服务器
  • 服务器收到HTTP请求,发现请求头中有Cookie字段,
    便知道之前就和这个用户打过交道了。

实战应用

用过知乎的都知道,只要提供用户名和密码以及验证码之后即可登录。当然,这只是我们眼中看到的现象。而背后隐藏的技术细节就需要借助浏览器来挖掘了。现在我们就用
Chrome 来查看当我们填完表单后,究竟发生了什么?

图片 2

(如果已经登录的,先退出)首先进入知乎的登录页面
,打开 Chrome 的开发者工具条(按
F12)先尝试输入一个错误的验证码观察浏览器是如何发送请求的。

图片 3

从浏览器的请求可以发现几个关键的信息

  • 登录的 URL 地址是
  • 登录需要提供的表单数据有4个:用户名(email)、密码(password)、验证码(captcha)、_xsrf。
  • 获取验证码的URL地址是

_xsrf
是什么?如果你对CSRF(跨站请求伪造)攻击非常熟悉的话,那么你一定知道它的作用,xsrf是一串伪随机数,它是用于防止跨站请求伪造的。它一般存在网页的
form 表单标签中,为了证实这一点,可以在页面上搜索
“xsrf”,果然,_xsrf在一个隐藏的 input 标签中

图片 4

摸清了浏览器登录时所需要的数据是如何获取之后,那么现在就可以开始写代码用
Python 模拟浏览器来登录了。登录时所依赖的两个第三方库是 requests 和
BeautifulSoup,先安装

pip install beautifulsoup4==4.5.3
pip install requests==2.13.0

http.cookiejar 模块可用于自动处理HTTP Cookie,LWPCookieJar 对象就是对
cookies 的封装,它支持把 cookies 保存到文件以及从文件中加载。

而 session 对象 提供了 Cookie 的持久化,连接池功能,可以通过 session
对象发送请求

首先从cookies.txt 文件中加载
cookie信息,因为首次运行还没有cookie,所有会出现 LoadError 异常。

from http import cookiejar
session = requests.session()
session.cookies = cookiejar.LWPCookieJar(filename='cookies.txt')
try:
 session.cookies.load(ignore_discard=True)
except LoadError:
 print("load cookies failed")

获取 xsrf

前面已经找到了 xsrf 所在的标签,,利用 BeatifulSoup 的 find
方法可以非常便捷的获取该值

def get_xsrf():
 response = session.get("https://www.zhihu.com", headers=headers)
 soup = BeautifulSoup(response.content, "html.parser")
 xsrf = soup.find('input', attrs={"name": "_xsrf"}).get("value")
 return xsrf

获取验证码

验证码是通过 /captcha.gif
接口返回的,这里我们把验证码图片下载保存到当前目录,由人工识别,当然你可以用第三方支持库来自动识别,比如
pytesser。

def get_captcha():
 """
 把验证码图片保存到当前目录,手动识别验证码
 :return:
 """
 t = str(int(time.time() * 1000))
 captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + "&type=login"
 r = session.get(captcha_url, headers=headers)
 with open('captcha.jpg', 'wb') as f:
  f.write(r.content)
 captcha = input("验证码:")
 return captcha

登录

一切参数准备就绪之后,就可以请求登录接口了。

def login(email, password):
 login_url = 'https://www.zhihu.com/login/email'
 data = {
  'email': email,
  'password': password,
  '_xsrf': get_xsrf(),
  "captcha": get_captcha(),
  'remember_me': 'true'}
 response = session.post(login_url, data=data, headers=headers)
 login_code = response.json()
 print(login_code['msg'])
 for i in session.cookies:
  print(i)
 session.cookies.save()

请求成功后,session 会自动把 服务端的返回的cookie 信息填充到
session.cookies
对象中,下次请求时,客户端就可以自动携带这些cookie去访问那些需要登录的页面了。

auto_login.py 示例代码

# encoding: utf-8
# !/usr/bin/env python
"""
作者:liuzhijun
"""
import time
from http import cookiejar

import requests
from bs4 import BeautifulSoup

headers = {
  "Host": "www.zhihu.com",
  "Referer": "https://www.zhihu.com/",
  'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87'
}

# 使用登录cookie信息
session = requests.session()
session.cookies = cookiejar.LWPCookieJar(filename='cookies.txt')
try:
  print(session.cookies)
  session.cookies.load(ignore_discard=True)

except:
  print("还没有cookie信息")


def get_xsrf():
  response = session.get("https://www.zhihu.com", headers=headers)
  soup = BeautifulSoup(response.content, "html.parser")
  xsrf = soup.find('input', attrs={"name": "_xsrf"}).get("value")
  return xsrf


def get_captcha():
  """
  把验证码图片保存到当前目录,手动识别验证码
  :return:
  """
  t = str(int(time.time() * 1000))
  captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + "&type=login"
  r = session.get(captcha_url, headers=headers)
  with open('captcha.jpg', 'wb') as f:
    f.write(r.content)
  captcha = input("验证码:")
  return captcha


def login(email, password):
  login_url = 'https://www.zhihu.com/login/email'
  data = {
    'email': email,
    'password': password,
    '_xsrf': get_xsrf(),
    "captcha": get_captcha(),
    'remember_me': 'true'}
  response = session.post(login_url, data=data, headers=headers)
  login_code = response.json()
  print(login_code['msg'])
  for i in session.cookies:
    print(i)
  session.cookies.save()


if __name__ == '__main__':
  email = "xxxx"
  password = "xxxxx"
  login(email, password)

github源码地址:

总结

以上就是关于Python爬虫之模拟知乎登录的全部内容,希望本文的内容对大家学习或者使用python能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对帮客之家的支持。

前言
对于经常写爬虫的大家都知道,有些页面在登录之前是被禁止抓取的,比如知乎的话…

依然是使用requests
主要的问题是模拟登陆:

前言:

什么是cookie?

Cookie,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。

比如说有些网站需要登录后才能访问某个页面,在登录之前,你想抓取某个页面内容是不允许的。那么我们可以利用Urllib库保存我们登录的Cookie,然后再抓取其他页面,这样就达到了我们的目的。


  注意:我们经常调试代码的时候基本都用chrome浏览器,但是我就因为用了谷歌浏览器(它总是登录的时候不提示我用验证码,误导我以为登录时不需要验证码,其实登录时候必须要验证码的),这里你可以多试试几个浏览器,一定要找个提示你输入验证码的浏览器调试。

a.png

一、Urllib库简介

Urllib是python内置的HTTP请求库,官方地址:

包括以下模块:

>>>urllib.request 请求模块

>>>urllib.error 异常处理模块

>>>urllib.parse url解析模块

>>>urllib.robotparser robots.txt解析模块

 


  1、我们登录的时候,提示我们输入验证码,当验证码弹出之前会有个请求,我们打开这个请求,很明显,type是login,验证码无疑了,就算是看请求的因为名,你也应该知道这个就是验证码的请求,或者打开这个验证码的请求url,这。

通过chrome开发者工具可以了解到,登陆的数据有这么一些,
但是根据我的观察,有时候需要用到验证码,所以,我的爬虫一律包含验证码,想要尝试验证码自动识别的同学,可以移步我另一篇文章简单验证码识别,虽然那篇文章只讲数字验证码的识别,但是基本思想是一样的。
言归正传,__xsrf这个数据在登陆网页上可以找到,所以可以通过正则找出来。

二、urllib.request.urlopen介绍

uurlopen一般常用的有三个参数,它的参数如下:

urllib.requeset.urlopen(url,data,timeout)

简单的例子:

1、url参数的使用(请求的URL)

response = urllib.request.urlopen('http://www.baidu.com')

2、data参数的使用(以post请求方式请求)

data= bytes(urllib.parse.urlencode({'word':'hello'}), encoding='utf8')

response= urllib.request.urlopen('http://www.baidu.com/post', data=data)

3、timeout参数的使用(请求设置一个超时时间,而不是让程序一直在等待结果)

response= urllib.request.urlopen('http://www.baidu.com/get', timeout=4)

 


  图片 5

登陆函数大概是这样的:

三、构造Requset

1、数据传送POST和GET(举例说明:此处列举登录的请求,定义一个字典为values,参数为:email和password,然后利用urllib.parse.urlencode方法将字典编码,命名为data,构建request时传入两个参数:url、data。运行程序,即可实现登陆。)

GET方式:直接以链接形式访问,链接中包含了所有的参数。

LOGIN_URL= "http://fr*****.aflt.kiwisns.com/postLogin/"

values={'email':'*******@user.com','password':'123456'}

data=urllib.parse.urlencode(values).encode()

geturl = LOGIN_URL+ "?"+data

request = urllib.request.Request(geturl)

 

POST方式:上面说的data参数就是用在这里的,我们传送的数据就是这个参数data。

LOGIN_URL='http://fr*****.aflt.kiwisns.com/postLogin/'

values={'email':'*******@user.com','password':'123456'}

data=urllib.parse.urlencode(values).encode()

request=urllib.request.Request(URL,data)

 

2、设置Headers(有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers
的属性)

图片 6

fiddler抓包请求-headers

上图可以看到该请求的headers,这个头中包含了许多信息:Cache、Client、Transport等等。其中,agent就是请求的身份,如果没有写入请求身份,那么服务器不一定会响应,所以可以在headers中设置agent。

举例:(这个例子只是说明了怎样设置headers)

user_agent = r'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0'

headers={'User-Agent':user_agent,'Connection':'keep-alive'}

request=urllib.request.Request(URL,data,headers)

 


  图片 7

Paste_Image.png

四、使用cookie登录

1、获取登录网址

浏览器输入需要登录的网址:’

此处确定需要登录的网址为:”

图片 8

查看登录的request网址

2、查看要传送的post数据

找到登录后的request中有webforms的信息,会列出登录要用的post数据,包括Email,password,auth。

图片 9

webforms信息

3、查看headers信息

找到登录后看到的request的headers信息,找出User-Agent设置、connection设置等

图片 10

User-Agent设置、connection设置

4、开始编码,使用cookie登录该网站

图片 11

5、反复使用cookie登录

(上面代码中我们保存cookie到本地了,以下代码我们能够直接从文件导入cookie进行登录,不用再构建request了)

图片 12

 


 

以上

  验证码的图片,悲惨了,这怎么整。别着急。。

函数初次登陆,需要账号和密码,之后,程序会自动记录一个cookie文件,在当前文件夹下,下次运行程序就不需要再输入密码和账号了,读写cookie文件的程序大概是这样:

  图片 13

Paste_Image.png

  2、验证码提示我们要点击倒着写的字体,这。。。,爬虫和反爬虫就是无休止的互相折磨。这明显就是上面那个图片的信息。

下载源码后,基本操作是:
先需要实例化:
from python_zhihu import ZhiHu
zh=ZhiHu()
下载某个问题下的高赞答案:
zh.get_text(‘填入网址’)
下载某个问题下所有的图片:
zh,get_img(‘url’)

  图片 14

源码:https://github.com/ladingwu/python\_zhihu

  3、机智的我,发现验证码的请求参数里面有三个参数,r是一个13位的数字,type是登录用的,lang很可疑,改改它,把cn给他改成en。mygod这不也是验证码么,就试试它了。

  图片 15

  图片 16

  4、页面基本登录原理分析完了,我们接下来看看代码怎么写,首先我们重构scrapy的start_requests方法(有scrapy基础的同学都知道,这个名字可不是瞎写的)。

  5、分析这个验证码的请求连接,

   最后,我们要请求这个url,这里必须要加上请求头信息,callback就是下面你要执行的方法。

    def start_requests(self):
        '''
        1、首先构造并抓取登录需要提交的验证码
        :return:
        '''
        t = str(int(time.time() * 1000))
        captcha_url = 'https://www.zhihu.com/captcha.gif?r={0}&type=login&lang=en'.format(t)
        return [scrapy.Request(url=captcha_url, headers=self.header, callback=self.parser_captcha)]

  6、上面请求完成后,就会将请求结果直接返回个下面的这个方法,所以它必须有个形式参数,来接收请求的结果,首先我们将请求的的结果,其实就是刚才我们看到的那个图片,图片的信息就在body里面,直接将整个body存成一个文件,然后我这里用的是Image打开我们存入的文件,文件都给你打开了,你还不得看看输入一下(如果你有云大码平台的服务,就直接让云大码平台搞定就行),这里我们只能自己看自己输入了。搞完了验证码,我们现在准备开始登陆,这里可不是直接用登陆的url登陆就行,你仔细的话还有个xrsf参数需要我们获取,那就请求的url直接就是登陆页面,注意你的头部信息,不伪装一下,立马给你请求出错。callback就不说了吧。这需要注意的就是,这直接把验证码存入了scrapy的meta里面了。

    def parser_captcha(self, response):
        '''
        1、根据start_requests方法返回的验证码,将它存入本地
        2、打开下载下来的验证码
        3、这里是需要手动输入的,这里可以接入打码平台
        :param response:
        :return:
        '''
        with open('captcha.jpg', 'wb') as f:
            f.write(response.body)
            f.close()
        try:
            im = Image.open('captcha.jpg')
            im.show()
            im.close()
        except:
            pass
        captcha = input("请输入你的验证>")
        return scrapy.FormRequest(url='https://www.zhihu.com/#signin', headers=self.header, callback=self.login, meta={
            'captcha': captcha
        })

  7、下面我们来搞定xsrf参数,这里我用xpath,一句话搞定,下面就是post_url就是上面phone_num请求里面的url,也是真正意义上的post提交登录信息的url。因为我们已经把验证码放进了meta里面了,所以这里直接获取就行。基本登录信息伪装完成以后,开始提交登录信息,登录完成以后,我们设置一个callback回调方法,检查一下登录信息。

    def login(self, response):
        xsrf = response.xpath("//input[@name='_xsrf']/@value").extract_first()
        if xsrf is None:
            return ''
        post_url = 'https://www.zhihu.com/login/phone_num'
        post_data = {
            "_xsrf": xsrf,
            "phone_num": '你的账户名称',
            "password": '你的账户密码',
            "captcha": response.meta['captcha']
        }
        return [scrapy.FormRequest(url=post_url, formdata=post_data, headers=self.header, callback=self.check_login)]

  8、上面请求完成以后,会返回我们一个字典,这里我们判断一下是否登录成功,如果登录成功以后,就执行我们start_urls里面的url地址,因为已经登录成功了,所以这里我们的start_urls就是

    def check_login(self, response):
        js = json.loads(response.text)
        print(js)
        if 'msg' in js and js['msg'] == '登录成功':
            for url in self.start_urls:
                print(url)
                yield scrapy.Request(url=url, headers=self.header, dont_filter=True)
        else:
            print("登录失败,请检查!!!")

  

  

 

 

代码如下:

import json
import scrapy
import time
from PIL import Image


class ZhihuloginSpider(scrapy.Spider):
    name = 'zhihu_login'
    allowed_domains = ['zhihu.com']
    start_urls = ['https://www.zhihu.com/']
    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',
    }

    def parse(self, response):
        #主页爬取的具体内容
        print(response.text)

    def start_requests(self):
        '''
        1、首先构造并抓取登录需要提交的验证码
        :return:
        '''
        t = str(int(time.time() * 1000))
        captcha_url = 'https://www.zhihu.com/captcha.gif?r={0}&type=login&lang=en'.format(t)
        return [scrapy.Request(url=captcha_url, headers=self.header, callback=self.parser_captcha)]

    def parser_captcha(self, response):
        '''
        1、根据start_requests方法返回的验证码,将它存入本地
        2、打开下载下来的验证码
        3、这里是需要手动输入的,这里可以接入打码平台
        :param response:
        :return:
        '''
        with open('captcha.jpg', 'wb') as f:
            f.write(response.body)
            f.close()
        try:
            im = Image.open('captcha.jpg')
            im.show()
            im.close()
        except:
            pass
        captcha = input("请输入你的验证>")
        return scrapy.FormRequest(url='https://www.zhihu.com/#signin', headers=self.header, callback=self.login, meta={
            'captcha': captcha
        })

    def login(self, response):
        xsrf = response.xpath("//input[@name='_xsrf']/@value").extract_first()
        if xsrf is None:
            return ''
        post_url = 'https://www.zhihu.com/login/phone_num'
        post_data = {
            "_xsrf": xsrf,
            "phone_num": '你的账户名称',
            "password": '你的账户密码',
            "captcha": response.meta['captcha']
        }
        return [scrapy.FormRequest(url=post_url, formdata=post_data, headers=self.header, callback=self.check_login)]

    # 验证返回是否成功
    def check_login(self, response):
        js = json.loads(response.text)
        print(js)
        if 'msg' in js and js['msg'] == '登录成功':
            for url in self.start_urls:
                print(url)
                yield scrapy.Request(url=url, headers=self.header, dont_filter=True)
        else:
            print("登录失败,请检查!!!")

  

相关文章