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)
    
  • 相关阅读:
    POJ2778 DNA Sequence AC自动机上dp
    codeforces732F Tourist Reform 边双联通分量
    codeforces786B Legacy 线段树优化建图
    洛谷P3588 PUS 线段树优化建图
    codeforces1301D Time to Run 模拟
    codeforces1303B National Project 二分或直接计算
    codeforces1303C Perfect Keyboard 模拟或判断欧拉路
    codeforces1303D Fill The Bag 二进制应用+贪心
    python之路——使用python操作mysql数据库
    python之路——mysql索引原理
  • 原文地址:https://www.cnblogs.com/hanfe1/p/12661493.html
Copyright © 2011-2022 走看看