内容字号:默认大号超大号

段落设置:段首缩进取消段首缩进

字体设置:切换到微软雅黑切换到宋体

Python爬虫实战之(四):模拟登录京东商城

2018-04-16 17:11 出处:清屏网 人气: 评论(0

前两篇和大家分享了爬虫中http的一些概念和使用方法,基础篇我们主要介绍了 http的请求头 ,高级篇我们主要介绍了 cookiesession (具体可以点击上面链接进行回顾)。但其实在爬虫中还有很多关于http的内容需要了解,例如 tokenoauth 等。对于这些概念博主将在后续文章中逐一的详细介绍,本篇主要针对前两篇内容与大家分享一个 模拟登录 的实战例子。

开始想以知乎为例,但是看到网上关于知乎模拟登录的教程太多了,所以就以 “京东” 为例。

大家都知道,京东是不需要登录就可以访问主页内容的,因此模拟登录的意义在于查看个人信息,比如可以获取个人的交易信息(购物车商品,购物历史记录,待收货商品信息等),或者卖家的商品销售信息和评论等等。

好了,了解背景过后,让我们开始模拟登录吧。

准备工作

大家都知道,模拟登录其实就是通过http的 post请求 方式来提交用户信息的( 用户名和密码 )。对于浏览器而言,只输入用户名和密码就可以登陆了(偶尔有验证码),那是因为浏览器在背后都帮你处理好了。而爬虫的模拟登录过程需要我们自己解决,因此我们需要弄清楚浏览器的那些背后操作是如何进行的才能对症下药。

难点分析:

  • 寻找提交表单所需字段信息
  • cookie信息的获取和使用
  • 验证码的处理

我们打开浏览器,博主用的 Chrome 浏览器。首先使用 Ctrl+Shift+N 进入干净的无痕模式,防止之前的cookie数据造成干扰。

输入了京东的登陆网址 passport.jd.com/new/login.a… ,进入如下登录界面。

表单字段信息

现在我们通过开发者工具来看看浏览器背后都干了什么吧。有的朋友提问到,输入用户名和密码后页面直接跳转到主页面了,看不到我们要的数据了。 其实这里只需要故意将你的密码输错不进入跳转就可以解决了。

点击登录,然后我们看到有个 FormData ,这就是浏览器每次向服务器提交的表单信息。

第一眼看过去感觉快要无望了。但是别着急,这些字段信息其实都是有处可寻的。我们 Ctrl+U 打开京东登录页面的源码里,然后 Ctrl+F 试着搜一搜这些字段信息。

先搜第一个 uuid 字段,发现它就在源码中,紧着后面是一些其它的字段信息,那就齐活了。我们看到除了 loginname,nloginpwd,authcode, 其他的字段全都是 hidden 的类型,也就是被 隐藏 了的字段。

好了,那下一步就自然知道干什么了。我们可以直接请求登录页面源码提取字段信息了。

Cookie的处理

Cookie可以通过使用http的 Cookiejar 定制 opener 进行获取,也可以直接使用 requests 模块来实现。

requests模块实现起来比较方便,因为内部已经封装好了自动处理Cookie的功能。第一次发送请求可以通过服务器获取Cookie,后续的请求则会自动带着已获取的Cookie信息进行发送。当然,也可以手动添加Cookie,手动添加的Cookie优先级高,将会覆盖默认的信息。

为了说明模拟登录的用法,本篇博主将使用简便的requests模块来完成对Cookie的处理。

验证码的处理

验证码的处理方法也有多种,可以分为 自动识别 的和 手动识别

  • 手动处理验证码就是通过验证码链接将验证码图片下载到本地,然后手动敲入完成信息录入。
  • 自动识别是使用一些高级的算法技术来完成的,可以使用 OCR 智能图文识别, 机器学习 进行识别训练等。

本篇将选择手动录入验证码,旨在理解模拟登录的过程。

代码实现

初始信息配置

class JD_crawl:
    def __init__(self, username, password):
        self.headers = {
                        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36'
                                      ' (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
                        'Referer': 'https://www.jd.com/',
                        }
        self.login_url = "https://passport.jd.com/new/login.aspx"
        self.post_url = "https://passport.jd.com/uc/loginService"
        self.auth_url = "https://passport.jd.com/uc/showAuthCode"
        self.session = requests.session()
        self.username = username
        self.password = password
  • 创建了一个 JD_crawl 的类,设置了实例的 headerssession 会话对象,以及三个后面请求需要用到的url。
  • 因为整个登录是一个完整的过程,所以后续若干请求需要共同使用同一个 session会话对象

提取表单登录信息

def get_login_info(self):
        html = self.session.get(self.login_url, headers=self.headers).content
        soup = BeautifulSoup(html, 'lxml')

        uuid = soup.select('#uuid')[0].get('value')
        eid = soup.select('#eid')[0].get('value')
        fp = soup.select('input[name="fp"]')[0].get('value')  # session id
        _t = soup.select('input[name="_t"]')[0].get('value')  # token
        login_type = soup.select('input[name="loginType"]')[0].get('value')
        pub_key = soup.select('input[name="pubKey"]')[0].get('value')
        sa_token = soup.select('input[name="sa_token"]')[0].get('value')

        auth_page = self.session.post(self.auth_url,
                                      data={'loginName': self.username, 'nloginpwd': self.password}).text
        print(auth_page)
        if 'true' in auth_page:
            auth_code_url = soup.select('#JD_Verification1')[0].get('src2')
            auth_code = str(self.get_auth_img(auth_code_url))
        else:
            auth_code = ''

        data = {
            'uuid': uuid,
            'eid': eid,
            'fp': fp,
            '_t': _t,
            'loginType': login_type,
            'loginname': self.username,
            'nloginpwd': self.password,
            'chkRememberMe': True,
            'pubKey': pub_key,
            'sa_token': sa_token,
            'authcode': auth_code
            }
        return data
  • 首先对登录的 login_url 发起请求,获取登陆页面源码后通过 BeautifulSoup 解析工具 ccs选择器 来提取隐藏字段信息。
  • loginname,nloginpwd,authcode 三个非隐藏字段需要用户手动录入。
  • 对于是否需要录入验证码的问题,可以通过请求 https://passport.jd.com/uc/showAuthCode (代码中的auth_url)来判断。

请求结果是一个如下格式的字符串。

请求结果: ({"verifycode":xxx})
xxx:true 或者 false

因此可以简单的查看结果中是否有 true 来判断是否需要验证码。

  • 如果为 true 就需要调用验证码函数方法,将验证码图片下载,输入图片上的验证码,并赋给 authcode 字段进行表单提交完成登录。
  • 如果为false则不需要验证码, authcode 字段为空字符串。

一般当我们多次输入了错误的账号或密码时,构成安全危险,就会提示输入验证码。

获取验证码

def get_auth_img(self, url):
        auth_code_url = 'http:{}&yys={}'.format(url, str(int(time.time()*1000)))
        auth_img = self.session.get(auth_code_url, headers=self.headers)
        with open('authcode.jpg', 'wb') as f:
            f.write(auth_img.content)
        code_typein = input('请根据下载图片输入验证码:')
        return code_typein
  • 从源码获取的验证码链接是一个相对链接 src2
src2="//authcode.jd.com/verify/image?a=1&acid=dcb4370b-2763-44e6-83ff-4b89bc01193d&uid=dcb4370b-2763-44e6-83ff-4b89bc01193d"

因此,我们需要将它补全,在 src2 前面拼接字符串 http: 。但是当我们尝试这个url的时候会发现图片并没有下载成功,为什么呢?

因为还需要在结尾加上时间戳,接着看后边的 onclic k,它的字符串中有和 src2 完全一样的链接,但在结尾处多了 &yys= '' 。通过观察内容发现有 datetime 字样,于是可以判断这可能是一个 时间戳字符串

onclick="this.src= document.location.protocol +'//authcode.jd.com/verify/image?a=1&acid=dcb4370b-2763-44e6-83ff-4b89bc01193d&uid=dcb4370b-2763-44e6-83ff-4b89bc01193d&yys='+new Date().getTime();$('#authcode').val('');"

小提示:

时间戳(引自百度百科):

时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。

时间戳在Python中可以用 time模块 来完成:

time.time()*1000
  • 将验证码图片存为 jpg 格式,储存在项目文件目录下。

可以看到图片就在目录下,我们双击打开然后按照图片输入验证码。

模拟登录

def login(self):
        data = self.get_login_info()
        headers = {
                    'Referer': self.post_url,
                    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36'
                                  ' (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
                    'X-Requested-With': 'XMLHttpRequest'
                  }
        try:
            login_page = self.session.post(self.post_url, data=data, headers=headers)
            print(login_page.text)
        except Exception as e:
            print(e)
  • 根据获取的表单登录信息进行提交登录。
  • 请求的url是 https://passport.jd.com/uc/loginService
  • 注意这里的 Service 中的 "S" 是大写。

如果登录成功,则会显示以下字符串。

({"success":"http://www.jd.com"})

登录验证及结果

为了验证登录真的成功了,现将博主的购物车拿出来做实验,如果在获取源码中找到了指定商品名称,那么就说明成功了。

好吧,都是之前随便放的,就以 牙线 为测试目标吧。

def shopping(self):
        carshop = self.session.post('https://cart.jd.com/cart.action', headers=self.headers)
        print(carshop.text)

简单的请求了一下 购物车url 。在下载的源码中搜索 “牙” ,然后找了目标。

代码链接: github.com/xiaoyusmd/j…

总结

本篇主要介绍了京东商城的模拟登录方法,当然还有一些网站的登录机制比较复杂,比如 weibo 登录需要调用 api ,需要我们详细阅读api说明。

后续将会分享更多模拟登录的内容,欢迎大家指正。

参考链接: https://github.com/xchaoinfo/fuck-login http://blog.csdn.net/weixin_38206454/article/details/78655209?locationNum=2&fps=1

如果想学习Python爬虫和数据分析,可以关注微信公众号 Python数据科学 ,博主会一直更新精彩内容,并分享更多的实战讲解,带你走进爬虫世界。


分享给小伙伴们:
本文标签: Python爬虫京东商城

相关文章

发表评论愿您的每句评论,都能给大家的生活添色彩,带来共鸣,带来思索,带来快乐。

CopyRight © 2015-2016 QingPingShan.com , All Rights Reserved.

清屏网 版权所有 豫ICP备15026204号