• Day 40 爬虫_requests模块高级操作


    模拟登陆

    引入

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

    分析

    模拟浏览器请求行为

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





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

    参数分析:

    email:用户名

    password:密码

    icode:验证码(通过云打码识别)

    剩下的参数不需要分析

    案例:模拟登陆人人网

    import requests
    from lxml import etree
    from YDM import YDMHttp
    result = None
    def codeText(pic, codetype):
        # 用户名
        username = 'ysging'
    
        # 密码
        password = 'abcd_1234'
    
        # 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
        appid = 10502
    
        # 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
        appkey = 'bee94fd2f6ac7b0d7fbb56169b137566'
    
        # 图片文件
        filename = pic
    
        # 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。在此查询所有类型 http://www.yundama.com/price.html
        codetype = codetype
    
        # 超时时间,秒
        timeout = 20
        result = None
        # 检查
        if (username == 'username'):
            print('请设置好相关参数再测试')
        else:
            # 初始化
            yundama = YDMHttp(username, password, appid, appkey)
    
            # 登陆云打码
            uid = yundama.login()
            print('uid: %s' % uid)
    
            # 查询余额
            balance = yundama.balance()
            print('balance: %s' % balance)
    
            # 开始识别,图片路径,验证码类型ID,超时时间(秒),识别结果
            cid, result = yundama.decode(filename, codetype, timeout)
            print('cid: %s, result: %s' % (cid, result))
        return result
    
    
    url = 'http://www.renren.com'
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36 OPR/67.0.3575.115 (Edition B2)'
    }
    
    req_txt = requests.get(url=url, headers=header).text
    tree = etree.HTML(req_txt)
    code_url = tree.xpath('//*[@id="verifyPic_login"]/@src')[0]
    code_con = requests.get(url=code_url, headers=header).content
    with open('./pic/code.jpg', 'wb') as f:
        f.write(code_con)
    codeText('./pic/code.jpg', 1004)
    print('result: ',result)
    
    index_url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2020301043668'
    data = {
        'email': '17326040421',
        'icode': result,
        'origURL': 'http://www.renren.com/home',
        'domain': 'renren.com',
        'key_id': '1',
        'captcha_type': 'web_login',
        'password': '9b9cae65878ef80dd7e5ccd794a505e3ce14be5adaad624da5b6632f316db743',
        'rkey': 'd2c22670c2504ecf4dcff869d4dfe18d',
        'f': ''
    }
    start = requests.post(url=index_url,data=data,headers=header).status_code
    print(start)

    会话和Cookies

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

    1、手动处理:通过抓包工具获取cookie值,将该值封装到headers中。(不建议)

    2、自动处理:

      cookie值的来源:模拟登陆post请求后,由服务器端创建,

      session会话对象

        1、可以进行请求的发送

        2、如果请求过程中产生了cookie,则该cookie会被自动存储,携带在改session对象中

      自动处理流程:

        1、创建一个session对象:session = requests.Session()

        2、使用session对象进行模拟登陆post请求的发送(Cookie就会被存储在session中)

        3、session对象对个人主页对应的get请求进行发送(携带了Cookie)

    无状态HTTP

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

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

    1、会话:会话(对象)是用来存储特定用户进行会话所需的属性及配置信息的。

    2、cookie:指的是某些网站为了辨别用户身份、进行会话跟踪而存储在用户本地终端上的数据。

    3、会话维持:当客户端第一次请求服务器时,服务器会返回一个响应对象,响应头中带有Set-Cookie字段,cookie会被客户端进行存储,该字段表明服务器已经为该客户端用户创建了一个会话对象,用来存储该用户的相关属性机器配置信息。当浏览器下一次再请求该网站时,浏览器会把cookie放到请求头中一起提交给服务器,cookie中携带了对应会话的ID信息,服务器会检查该cookie即可找到对应的会话是什么,然后再判断会话来以此辨别用户状态。

    4、形象案例:当iphone用户第一次向iphone的售后客服打电话咨询相关问题时,售后客服会针对当前用户创建一个唯一的“问题描述”,用来记录当前用户的iphone产品出现的相关问题,然后当用户阐述清楚问题后,售后客服就会将问题记录在所谓的“问题描述”中,并将“问题描述”的唯一编号通过短信告诉该用户。这样的好处就是,下次该用户的产品再次出现问题向售后电话咨询时,提供了“问题描述”的唯一编码后,就不需要在将该产品之前的问题再次进行描述了。此案例中,“问题描述”就相当于是会话,“问题描述”的唯一编码就是会话ID,短信就是cookie。

    案例:爬取人人网内自己的个人信息

    import requests
    from lxml import etree
    from YDM import YDMHttp
    result = None
    def codeText(pic, codetype):
        # 用户名
        username = 'ysging'
    
        # 密码
        password = 'abcd_1234'
    
        # 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
        appid = 10502
    
        # 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
        appkey = 'bee94fd2f6ac7b0d7fbb56169b137566'
    
        # 图片文件
        filename = pic
    
        # 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。在此查询所有类型 http://www.yundama.com/price.html
        codetype = codetype
    
        # 超时时间,秒
        timeout = 20
        result = None
        # 检查
        if (username == 'username'):
            print('请设置好相关参数再测试')
        else:
            # 初始化
            yundama = YDMHttp(username, password, appid, appkey)
    
            # 登陆云打码
            uid = yundama.login()
            print('uid: %s' % uid)
    
            # 查询余额
            balance = yundama.balance()
            print('balance: %s' % balance)
    
            # 开始识别,图片路径,验证码类型ID,超时时间(秒),识别结果
            cid, result = yundama.decode(filename, codetype, timeout)
            print('cid: %s, result: %s' % (cid, result))
        return result
    
    
    url = 'http://www.renren.com'
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36 OPR/67.0.3575.115 (Edition B2)'
    }
    
    req_txt = requests.get(url=url, headers=header).text
    tree = etree.HTML(req_txt)
    code_url = tree.xpath('//*[@id="verifyPic_login"]/@src')[0]
    code_con = requests.get(url=code_url, headers=header).content
    with open('./pic/code.jpg', 'wb') as f:
        f.write(code_con)
    codeText('./pic/code.jpg', 1004)
    print('result: ',result)
    
    session = requests.Session()
    index_url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2020301043668'
    data = {
        'email': '17326040421',
        'icode': result,
        'origURL': 'http://www.renren.com/home',
        'domain': 'renren.com',
        'key_id': '1',
        'captcha_type': 'web_login',
        'password': '9b9cae65878ef80dd7e5ccd794a505e3ce14be5adaad624da5b6632f316db743',
        'rkey': 'd2c22670c2504ecf4dcff869d4dfe18d',
        'f': ''
    }
    start = session.post(url=index_url,data=data,headers=header).status_code
    print(start)
    user_url = 'http://www.renren.com/974212085/profile'
    user_txt = session.get(url=user_url,headers=header).text
    with open('user.html','w',encoding='utf-8') as f:
        f.write(user_txt)
    print('over!!!')

    requests模块的代理IP操作

    引入

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

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

    什么是代理

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

    代理的作用

    1、突破自身IP访问的限制,访问一些平时不能访问的站点。

    2、隐藏真实IP,免受攻击,防止自身IP被封锁

    相关代理网站

    1、快代理

    2、西祠代理

    3、www.goubanjia.com

    代理ip的类型

    http:应用到http协议对应的url中

    https:应用到https协议对应的url中

    代理ip的匿名度

    透明:服务器知道该次请求使用了代理ip,也知道请求对应的真实ip

    匿名:服务器知道该次请求使用了代理ip,不知道请求对应的真实ip

    高匿:服务器不知道该次请求使用了代理ip,也不知道请求对应的真实ip

    案例展示

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

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

    import requests
    url = 'https://www.baidu.com/baidu?wd=ip'
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36 OPR/67.0.3575.115 (Edition B2)'
    }
    req_txt = requests.get(url=url,headers=header,proxies={"https":"117.88.4.2:3000"}).text
    with open(r'C:UsersAdministratorDesktopip.html','w',encoding='utf-8') as f:
        f.write(req_txt)
    print('over!!!')
  • 相关阅读:
    MySQL讲义
    python使用matplotlib在一个图形中绘制多个子图以及一个子图中绘制多条动态折线问题
    python爬虫登陆网页版腾讯课堂
    父子组件之间相互传值
    echarts图中使用到的属性及对应的作用,饼图实例、折线图实例
    vue get类型接口调用方式
    javaScript前进后退点击事件
    vue页面跳转
    如何修改vant组件中原有样式?
    Module not found: Error: Can't resolve 'less-loader' in '文件位置'报错解决
  • 原文地址:https://www.cnblogs.com/ysging/p/12684294.html
Copyright © 2020-2023  润新知