• Python爬虫 — requests模块(2)


    引入:

    ​ 有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个人主页数据)时,如果使用之前requests模块常规操作时,往往达不到我们想要的目的,例如:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import requests
    if __name__ == "__main__":
    
        #张三人人网个人信息页面的url
        url = 'http://www.renren.com/289676607/profile'
    
       #伪装UA
        headers={
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
        }
        #发送请求,获取响应对象
        response = requests.get(url=url,headers=headers)
        #将响应内容写入文件
        with open('./renren.html','w',encoding='utf-8') as fp:
            fp.write(response.text)
    

    ​ 结果发现,写入到文件中的数据,不是张三个人页面的数据,而是人人网登陆的首页面,why?首先我们来回顾下cookie的相关概念及作用。

    一、基于requests模块的cookie操作

    • cookie概念

      当用户通过浏览器首次访问一个域名时,访问的web服务器会给客户端发送数据,以保持web服务器与客户端之间的状态保持,这些数据就是cookie。

    • cookie作用

      我们在浏览器中,经常涉及到数据的交换,比如你登录邮箱,登录一个页面。我们经常会在此时设置30天内记住我,或者自动登录选项。那么它们是怎么记录信息的呢,答案就是今天的主角cookie了,Cookie是由HTTP服务器设置的,保存在浏览器中,但HTTP协议是一种无状态协议,在数据交换完毕后,服务器端和客户端的链接就会关闭,每次交换数据都需要建立新的链接。就像我们去超市买东西,没有积分卡的情况下,我们买完东西之后,超市没有我们的任何消费信息,但我们办了积分卡之后,超市就有了我们的消费信息。cookie就像是积分卡,可以保存积分,商品就是我们的信息,超市的系统就像服务器后台,http协议就是交易的过程。

    1、思路:

    1. 我们需要使用爬虫程序对人人网的登录时的请求进行一次抓取,获取请求中的cookie数据
    2. 在使用个人信息页的url进行请求时,该请求需要携带 1 中的cookie,只有携带了cookie后,服务器才可识别这次请求的用户信息,方可响应回指定的用户信息页数据
    # -*- coding:utf-8 -*-
    import requests
    if __name__ == "__main__":
    
        #登录请求的url(通过抓包工具获取)
        post_url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=201873958471'
        #创建一个session对象,该对象会自动将请求中的cookie进行存储和携带
        session = requests.session()
       #伪装UA
        headers={
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
        }
        formdata = {
            'email': '17701256561',
            'icode': '',
            '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',
        }
        #使用session发送请求,目的是为了将session保存该次请求中的cookie
        session.post(url=post_url,data=formdata,headers=headers)
    
        get_url = 'http://www.renren.com/960481378/profile'
        #再次使用session进行请求的发送,该次请求中已经携带了cookie
        response = session.get(url=get_url,headers=headers)
        #设置响应内容的编码格式
        response.encoding = 'utf-8'
        #将响应内容写入文件
        with open('./renren.html','w') as fp:
            fp.write(response.text)
    

    二、验证码处理

    云打码平台

    1. 注册
      • 普通用户和开发者用户
    2. 登录:
      • 登录普通用户(查看余额)
      • 登录开发者用户:
        1. 创建一个软件:我的软件->创建软件
        2. 下载示例代码:开发者中心->下载最新的DLL->pythonHttp示例代码下载
    # 函数封装
    def getCodeDate(userName,pwd,codePath,codeType):
        # 用户名(普通用户)
        username    = userName
    
        # 密码
        password    = pwd                            
    
        # 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
        appid       = 6003                                    
    
        # 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
        appkey      = '1f4b564483ae5c907a1d34f8e2f2776c'    
    
        # 图片文件
        filename    = codePath                       
    
        # 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。在此查询所有类型 http://www.yundama.com/price.html
        codetype    = codeType
    
        # 超时时间,秒
        timeout     = 2                                   
        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
    
    
    # 人人网的模拟登录(有验证码)
    # 调用上面的函数
    import requests
    import urllib
    from lxml import etree
    #获取session对象
    session = requests.Session()
    #将验证码图片进行下载
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
    }
    url = 'http://www.renren.com/'
    page_text = requests.get(url=url,headers=headers).text
    
    tree = etree.HTML(page_text)
    code_img_url = tree.xpath('//*[@id="verifyPic_login"]/@src')[0]
    urllib.request.urlretrieve(url=code_img_url,filename='code.jpg')
    
    #识别验证码图片中的数据值
    code_data = getCodeDate('bobo328410948','bobo328410948','./code.jpg',2004)
    
    #模拟登录
    login_url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=201914927558'
    data = {
        "email":"www.zhangbowudi@qq.com",
        "icode":code_data,
        "origURL":"http://www.renren.com/home",
        "domain":"renren.com",
        "key_id":"1",
        "captcha_type":"web_login",
        "password":"4f0350f09aeffeef86307747218b214b0960bdf35e30811c0d611fe39db96ec1",
        "rkey":"9e75e8dc3457b14c55a74627fa64fb43",
        "f":"http%3A%2F%2Fwww.renren.com%2F289676607",
    }
    #该次请求产生的cookie会被自动存储到session对象中
    session.post(url=login_url,data=data,headers=headers)
    
    url = 'http://www.renren.com/289676607/profile'
    page_text = session.get(url=url,headers=headers).text
    
    with open('renren.html','w',encoding='utf-8') as fp:
        fp.write(page_text)
    

    三、基于requests模块的代理操作

    • 什么是代理

      代理就是第三方代替本体处理相关事务。例如:生活中的代理:代购,中介,微商......

    • 爬虫中为什么需要使用代理

      一些网站会有相应的反爬虫措施,例如很多网站会检测某一段时间某个IP的访问次数,如果访问频率太快以至于看起来不像正常访客,它可能就会会禁止这个IP的访问。所以我们需要设置一些代理IP,每隔一段时间换一个代理IP,就算IP被禁止,依然可以换个IP继续爬取。

    • 代理的分类:

      1. 正向代理:代理客户端获取数据。正向代理是为了保护客户端防止被追究责任。
      2. 反向代理:代理服务器提供数据。反向代理是为了保护服务器或负责负载均衡。
    • 免费代理ip提供网站

    • 代码

      # -*- coding:utf-8 -*-
      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)
          #切换成原来的IP
          requests.get(url, proxies={"http": ""})
      

    四、基于multiprocessing.dummy线程池的数据爬取

    需求:爬取梨视频的视频信息,并计算其爬取数据的耗时

    • 普通爬取

      import time
      import requests
      import random
      from lxml import etree
      import re
      from fake_useragent import UserAgent
      #安装fake-useragent库:pip install fake-useragent
      url = 'http://www.pearvideo.com/category_1'
      #随机产生UA,如果报错则可以添加如下参数:
      #ua = UserAgent(verify_ssl=False,use_cache_server=False).random
      #禁用服务器缓存:
      #ua = UserAgent(use_cache_server=False)
      #不缓存数据:
      #ua = UserAgent(cache=False)
      #忽略ssl验证:
      #ua = UserAgent(verify_ssl=False)
      
      ua = UserAgent().random
      headers = {
          'User-Agent':ua
      }
      #获取首页页面数据
      page_text = requests.get(url=url,headers=headers).text
      #对获取的首页页面数据中的相关视频详情链接进行解析
      tree = etree.HTML(page_text)
      li_list = tree.xpath('//div[@id="listvideoList"]/ul/li')
      detail_urls = []
      for li in li_list:
          detail_url = 'http://www.pearvideo.com/'+li.xpath('./div/a/@href')[0]
          title = li.xpath('.//div[@class="vervideo-title"]/text()')[0]
          detail_urls.append(detail_url)
      for url in detail_urls:
          page_text = requests.get(url=url,headers=headers).text
          vedio_url = re.findall('srcUrl="(.*?)"',page_text,re.S)[0]
          
          data = requests.get(url=vedio_url,headers=headers).content
          fileName = str(random.randint(1,10000))+'.mp4' #随机生成视频文件名称
          with open(fileName,'wb') as fp:
              fp.write(data)
              print(fileName+' is over')
      
    • 基于线程池的爬取

      import time
      import requests
      import random
      from lxml import etree
      import re
      from fake_useragent import UserAgent
      #安装fake-useragent库:pip install fake-useragent
      #导入线程池模块
      from multiprocessing.dummy import Pool
      #实例化线程池对象
      pool = Pool()
      url = 'http://www.pearvideo.com/category_1'
      #随机产生UA
      ua = UserAgent().random
      headers = {
          'User-Agent':ua
      }
      #获取首页页面数据
      page_text = requests.get(url=url,headers=headers).text
      #对获取的首页页面数据中的相关视频详情链接进行解析
      tree = etree.HTML(page_text)
      li_list = tree.xpath('//div[@id="listvideoList"]/ul/li')
      
      detail_urls = []#存储二级页面的url
      for li in li_list:
          detail_url = 'http://www.pearvideo.com/'+li.xpath('./div/a/@href')[0]
          title = li.xpath('.//div[@class="vervideo-title"]/text()')[0]
          detail_urls.append(detail_url)
          
      vedio_urls = []#存储视频的url
      for url in detail_urls:
          page_text = requests.get(url=url,headers=headers).text
          vedio_url = re.findall('srcUrl="(.*?)"',page_text,re.S)[0]
          vedio_urls.append(vedio_url) 
      #使用线程池进行视频数据下载    
      func_request = lambda link:requests.get(url=link,headers=headers).content
      video_data_list = pool.map(func_request,vedio_urls)
      #使用线程池进行视频数据保存
      func_saveData = lambda data:save(data)
      pool.map(func_saveData,video_data_list)
      def save(data):
          fileName = str(random.randint(1,10000))+'.mp4'
          with open(fileName,'wb') as fp:
              fp.write(data)
              print(fileName+'已存储')
              
      pool.close()
      pool.join()
      
  • 相关阅读:
    Python-内置函数
    Python-匿名函数
    Python-函数递归-二分法
    Python-函数递归
    Day4-函数
    CSS-定位
    CSS-文本属性,文字属性
    CSS-浮动
    CSS-盒模型
    CSS-继承和层叠
  • 原文地址:https://www.cnblogs.com/jiumo/p/10458756.html
Copyright © 2020-2023  润新知