zoukankan      html  css  js  c++  java
  • 05 request高级操作

    05 request高级操作

    模拟登陆

    引入

    sometimes,相关的需求会让我们去爬取基于某些用户的相关用户信息,例如爬取张三人人网账户中的个人身份信息、好友账号信息等。那么这个时候,我们就需要对当前用户进行登录操作,登录成功后爬取其用户的相关用户信息。在浏览器中我们可以很便捷的进行用户登录操作,但是使用requests模块如何进行模拟浏览器行为的登录操作呢?

    img

    分析

    • 模拟浏览器请求行为
      • 在浏览器中进行登录时,录入完用户名、密码和验证码后,需要点击登录按钮。只有在点击登录按钮后,当前页面才会发起一次网络请求。该次网络请求可以通过抓包工具捕获。

    img

    • 经过抓包分析后,我们就可以模拟浏览器点击登陆按钮后发起的请求操作了。该请求为post请求,对应的url在上图中可以看到,切请求携带的参数也可以在抓到的数据包中获取。

      • 参数分析:
        • email:用户名
        • password:密码
        • icode:验证码(通过云打码识别)
        • 剩下的参数不需要分析
    • 模拟登录代码:

    import requests
    from lxml import etree
    from YunCode import YDMHttp,get_code_image
    
    
    if __name__ == '__main__':
        url = 'http://www.renren.com/'
        headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
        }
        page_text = requests.get(url=url, headers=headers).text
        print(page_text)
        print(page_text)
        # 解析验证码图片地址
        tree = etree.HTML(page_text)
        code_img_src = tree.xpath('//*[@id="verifyPic_login"]/@src')[0]
    
        # 请求验证码图片,且保存至本地
        img_data = requests.get(url=code_img_src, headers=headers).content
        with open('./code.jpg', 'wb') as fp:
            fp.write(img_data)
        #验证码图片显示的内容数据
        code_text=get_code_image('./code.jpg', 1004)
        #参数处理
        formdata = {
            'email': 'xxx',
            'icode': code_text,
            'origURL': 'http://www.renren.com/home',
            'domain': 'renren.com',
            'key_id': '1',
            'captcha_type': 'web_login',
            'password': '7b456e6c3eb6615b2e122a2942ef3845da1f91e3de075179079a3b84952508e4',
            'rkey': '44fd96c219c593f3c9612360c80310a3',
            'f': 'https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3Dm7m_NSUp5Ri_ZrK5eNIpn_dMs48UAcvT-N_kmysWgYW%26wd%3D%26eqid%3Dba95daf5000065ce000000035b120219',
        }
        #发送post请求模拟游览器登陆
        post_url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2020201440719'
        response = requests.post(url=post_url, data=formdata, headers=headers).text
        # 将响应内容写入文件
        with open('./renren.html','w') as fp:
            fp.write(response)
    
    

    requests模块的cookie处理

    会话和Cookies

    在浏览网站的过程中,我们经常会遇到需要登录的情况,有些页面只有登录之后才可以访问,而且登录之后可以连续访问很多次网站,但是有时候过一段时间就需要重新登录。还有一些网站,在打开浏览器时就自动登录了,而且很长时间都不会失效,这种情况又是为什么?其实这里面就涉及到了会话和cookie的相关知识,本节就来揭开他们的神秘面纱。

    无状态HTTP

    HTTP的无状态指的是http协议对事物处理是没有记忆能力的,也就是说服务器不知道客户端是什么状态。当我们向服务器发送请求后,服务器解析此请求,然后返回对应的响应,服务器负责完成这个过程,而且这个过程是完全独立的,服务器不会记录前后状态的变化,也就是缺少状态记录。这就意味着如果后续需要处理前面的信息,则必须重传,这导致需要额外传递一些前面的重复请求,才能获取后续响应,然而这种效果显然不是我们想要的。为了保持前后状态,我们肯定不能将前面的请求全部重传一次,这太浪费资源了,对于这种需要用户登录页面来说,更是棘手。

    这时两个保持http连接状态的技术出现了,分别是会话和cookie。会话在服务端,用来保存用户的会话信息。cookie在客户端,有了cookie,浏览器在下次访问网页时会自动附带上cookie发送给服务器,服务器识别cookie并鉴定出是哪个用户,然后在判断出用户的相关状态,然后返回对应的响应。

    • 会话:会话(对象)是用来存储特定用户进行会话所需的属性及配置信息的。
    • cookie:指的是某些网站为了辨别用户身份、进行会话跟踪而存储在用户本地终端上的数据。
    • 会话维持:当客户端第一次请求服务器时,服务器会返回一个响应对象,响应头中带有Set-Cookie字段,cookie会被客户端进行存储,该字段表明服务器已经为该客户端用户创建了一个会话对象,用来存储该用户的相关属性机器配置信息。当浏览器下一次再请求该网站时,浏览器会把cookie放到请求头中一起提交给服务器,cookie中携带了对应会话的ID信息,服务器会检查该cookie即可找到对应的会话是什么,然后再判断会话来以此辨别用户状态。
    • 形象案例:当iphone用户第一次向iphone的售后客服打电话咨询相关问题时,售后客服会针对当前用户创建一个唯一的“问题描述”,用来记录当前用户的iphone产品出现的相关问题,然后当用户阐述清楚问题后,售后客服就会将问题记录在所谓的“问题描述”中,并将“问题描述”的唯一编号通过短信告诉该用户。这样的好处就是,下次该用户的产品再次出现问题向售后电话咨询时,提供了“问题描述”的唯一编码后,就不需要在将该产品之前的问题再次进行描述了。此案例中,“问题描述”就相当于是会话,“问题描述”的唯一编码就是会话ID,短信就是cookie。

    案例分析

    需求:使用requests模块实现github的模拟登录

    • 浏览器登录流程:

      • 录入用户名和密码,点击登录
      • img
      • 页面跳转,显示登录成功后的主页面:
      • img
    • requests模拟登陆流程:

      • 通过抓包工具捕获点击登陆按钮后对应的post请求数据包

      • imgimg

      • 获取该数据包的url和请求参数

      • 发起请求,进行持久化存储

      • import requests
        from lxml import etree
        
        headers = {
            ‘User-Agent’: ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36’
        }
        url = ‘https://github.com/session‘
        data = {
            ‘commit’: ‘Sign in’,
            ‘utf8’: ‘✓’,
            ‘authenticity_token’:’lGnVdPaEf/jfBd6dzkQFpd4idQZxO96HSvRzWIPo5099dvmZTqEx+Q13zLjQzYpE08YmZdJStHd+Vk6Yhz7t/Q==’ ,
            ‘login’: ‘bobo328410948@sina.com’,
            ‘password’: ‘bobo@15027900535’,
            ‘webauthn-support’: ‘supported’,
        }
        page_text = requests.post(url=url,headers=headers,data=data).text
        
        with open(‘./git.html’,’w’,encoding=’utf-8’) as fp:
            fp.write(page_text)
        

        查看爬取下来的页面是否为登陆成功后的页面:img结果发现该页面不是登陆成功后的页面,则表示模拟登陆失败!

    模拟登陆失败原因分析:

    1.检查分析抓取的登陆时发起的post请求对应的数据包:

    img该数据包是携带了cookie进行的请求发送,那么该cookie是什么时候存储到客户端的呢?一定是该请求的前次请求时产生的cookie。

    在浏览器进行登陆请求发送之前,我们已经是第二次访问的github服务器端了,因为第一次是在浏览器中访问登陆页面时。

    img

    抓取该次请求的数据包,查看响应头信息中是否存在set-cookie,如果有,则证实该次请求时,服务器端给客户端创建了会话对象,且创建了cookie返回给了客户端进行存储。

    img果然存在set-cookie,因此,我们在使用requests模块进行模拟登陆时,发起的请求也是需要携带cookie的。那么cookie如何被携带到requests的请求中呢?

    - requests模块处理cookie的两种方式:

    1.将cookie手动从抓包工具中获取,然后封装到requests请求的headers中,将headers作用到请求方法中。(不建议)

    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36',
        'Cookie':'xxxxxxxxx'
    }
    

    2.创建会话对象,使用会话对象进行请求发送。因为会话中会自动携带且处理cookie。(推荐)

    - 代码展示:

    在使用会话对象发起登陆请求时,需要额外注意该请求参数:

    ’authenticity_token':'lGnVdPaEf/jfBd6dzkQFpd4idQZxO96HSvRzWIPo5099dvmZTqEx+Q13zLjQzYpE08YmZdJStHd+Vk6Yhz7t/Q==' ,
    

    该参数的value值看起来像是一组密文数据,则该数据很有可能是动态变化的,因此需要动态捕获,动态赋值。如果该参数不处理的话,也是会登陆失败的。那么该值应该从那哪里动态捕获呢?这种值我们可以统一称为动态taken参数,该值一般都会动态存在与该请求对应的前台页面中,因此我们在登陆页面的源码中进行搜索:

    img

    因此我们可以通过数据解析,动态解析捕获到该请求参数的值。详细代码如下:

    import requests
    from lxml import etree
    headers = {
     'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
    }
    #创建会话对象,该会话对象可以调用get和post发起请求
    session = requests.Session()
    #使用会话对面对登录页面发起请求
    page_text = session.get(url='https://github.com/login',headers=headers).text
    #解析出动态的taken值
    tree = etree.HTML(page_text)
    t = tree.xpath('//*[@id="login"]/form/input[2]/@value')[0]
    #指定模拟登录请求的url
    url = 'https://github.com/session'
    #参数封装(处理动态taken值)
    data = {
     'commit': 'Sign in',
     'utf8': '✓',
     'authenticity_token': t,
     'login': 'bobo328410948@sina.com',
     'password': 'bobo@15027900535',
     'webauthn-support': 'supported',
    }
    #使用会话对象进行模拟登录请求发送(携带cookie)
    page_text = session.post(url=url,headers=headers,data=data).text
    #持久化存储
    with open('./git.html','w',encoding='utf-8') as fp:
     fp.write(page_text)
    

    查看git.html:登录成功

    img

    requests模块的代理IP

    引入

    我们在做爬虫的过程中经常会遇到这样的情况,最初爬虫正常运行,正常抓取数据,一切看起来都是那么美好,然而一杯茶的功夫可能就会出现错误,比如403,这时打开网页一看,可能会看到“您的IP访问频率太高”这样的提示。出现这种现象的原因是网站采取了一些反爬措施。比如,服务器会检测某个IP在单位时间内请求的次数,如果超过了某个阈值,就会直接拒绝服务,返回一些错误信息,这种情况可以称为封IP。

    既然服务器检测的是某个IP单位时间的请求次数,那么借助某种方式来伪装我们的IP,让服务器识别不出是由我们本机发起的请求,不就可以成功防止封IP了吗?一种有效的方式就是使用代理。

    什么是代理

    代理实际上指的就是代理服务器,它的功能就是代理网络用户去取得网络信息。形象的说,它是网络信息的中转站。在我们正常请求一个网站时,是发送了请求给Web服务器,Web服务器把响应传回我们。如果设置了代理服务器,实际上就是在本机和服务器之间搭建了一个桥梁,此时本机不是直接向Web服务器发起请求,而是向代理服务器发出请求,请求会发送给代理服务器,然后代理服务器再发送给Web服务器,接着由代理服务器再把Web服务器返回的响应转发给本机。这样我们同样可以正常访问网页,但这个过程中Web服务器识别出的真实IP就不再是我们本机的IP了,就成功实现了IP伪装,这就是代理的基本原理。

    代理的作用

    • 突破自身IP访问的限制,访问一些平时不能访问的站点。
    • 隐藏真实IP,免受攻击,防止自身IP被封锁

    相关代理网站

    • 快代理
    • 西祠代理
    • www.goubanjia.com

    案例展示

    当我们在百度中搜索“ip”关键词后,对应搜索结果的页面显示中会有本次浏览器发起请求对应的IP信息:

    img

    如果我们使用requests模块相关操作应用了代理,则请求到该页面中显示的ip信息就是代理IP相关信息了。我们可以使用requests模块请求方法的proxies参数处理代理IP:

    import requests
    import random
    if __name__ == "__main__":
        #不同浏览器的UA
        header_list = [
            # 遨游
            {"user-agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon 2.0)"},
            # 火狐
            {"user-agent": "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"},
            # 谷歌
            {
                "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11"}
        ]
        #不同的代理IP
        proxy_list = [
            {"http": "112.115.57.20:3128"},
            {'http': '121.41.171.223:3128'}
        ]
        #随机获取UA和代理IP
        header = random.choice(header_list)
        proxy = random.choice(proxy_list)
        url = 'http://www.baidu.com/s?ie=UTF-8&wd=ip'
        #参数3:设置代理
        response = requests.get(url=url,headers=header,proxies=proxy)
        response.encoding = 'utf-8'
        with open('daili.html', 'wb') as fp:
            fp.write(response.content)
    
  • 相关阅读:
    The "tsconfig.json" file must have compilerOptions.sourceMap set to true
    *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<WKWebViewConfiguration 0x1701bcd20> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the k
    Android Service
    关于phonegap-plugin-contentsync插件
    Ionic APP 热更新 之 产品发布状态下的热更新搭建,去local-dev-addon插件
    Ionic APP 热更新
    在懒加载的Ionic工程中使用 ionic2-auto-complete 组件:Can't bind to 'dataProvider' since it isn't a known property of 'ion-auto-complete'
    Template parse errors: The pipe 'translate' could not be found
    How to update Ionic cli and libraries
    第七章 Hyper-V 2012 R2 授权管理
  • 原文地址:https://www.cnblogs.com/hanfe1/p/12661493.html
Copyright © 2011-2022 走看看