爬虫中的模拟登陆,IP代理,线程池

模拟登陆

  • 为什么要进行模拟登陆

    • 有些时候,我们需要爬取一些基于个人用户的用户信息(需要登录后才可以查看的)
  • 为什么需要识别验证码

    • 因为验证码往往是作为登录请求中的请求参数被使用
  • 验证码识别:借助于线上的一款打码平台(超级鹰,云打码,打码兔)

  • 超级鹰的使用流程:http://www.chaojiying.com/about.html

    • 注册:注册一个 <用户中心> 身份的账号
    • 登录:基于 <用户中心> 进行登录
    • 点击 软件ID -->生成一个软件id
    • 下载示例代码:点击开发文档->选择python语言->点击下载
  • cookie操作:

    • 手动处理(不建议):
      • 将cookie放置到headers中,灵活性差,cookie存储有时间上限
    • 自动处理(建议):使用requests模块中的Session对象:
      • Session对象:该对象可以想requests一样发送get和post请求,当该对象在进行请求发送的过程中,产生cookie,则该cookie会被自动存储到该对象中
        • session = requests.Session()
  • 模拟登陆案例

    #模拟登陆爬取古诗文网站登陆界面
    import requests
    from lxml import etree
    from chaojiying_Python.chaojiying import Chaojiying_Client
    
    #当你处理登陆爬虫时要将请求换成session
    session = requests.Session()
    #将超级鹰下载的包封装成一个函数进行引入调用
    def get_codeImg_text(imgPath, imgType):
        chaojiying = Chaojiying_Client('超级鹰账号', '超级鹰密码', '    899991')    #用户中心>>软件ID 生成一个替换 96001
        im = open(imgPath, 'rb').read()                                                   #本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
        # print(chaojiying.PostPic(im, 1902))
        return chaojiying.PostPic(im, imgType)['pic_str']
    
    headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
    }
    
    #模拟登录
    #获取验证码图片
    url = 'https://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx'
    #解析验证码图片
    page_text = requests.get(url=url,headers=headers).text
    tree = etree.HTML(page_text)
    code_img_src = 'https://so.gushiwen.org/'+tree.xpath('//*[@id="imgCode"]/@src')[0]
    code_img_data = session.get(url=code_img_src,headers=headers).content
    with open('./code.jpg','wb') as fp:
        fp.write(code_img_data)
    #解析动态参数
    __VIEWSTATE = tree.xpath('//input[@id="__VIEWSTATE"]/@value')[0]
    __VIEWSTATEGENERATOR = tree.xpath('//input[@id="__VIEWSTATEGENERATOR"]/@value')[0]
    print(__VIEWSTATE,__VIEWSTATEGENERATOR)
    #使用打码平台识别出来的验证码图片数据
    codeImg_text = get_codeImg_text('./code.jpg',1902)
    print(codeImg_text)
    login_url = 'https://so.gushiwen.org/user/login.aspx?from=http%3a%2f%2fso.gushiwen.org%2fuser%2fcollect.aspx'
    #动态参数:动态参数往往都会被隐藏在前台页面
    data = {
        #处理了动态参数
        "__VIEWSTATE": __VIEWSTATE,
        "__VIEWSTATEGENERATOR": __VIEWSTATEGENERATOR,
        "from": "http://so.gushiwen.org/user/collect.aspx",
        "email": "你的账号",
        "pwd": "你的密码",
        "code": codeImg_text,
        "denglu": "登录",
    }
    #登陆发送post请求,且传送data
    pages_text = session.post(url=login_url,headers=headers,data=data).text
    with open('./gushiwen.html','w',encoding='utf-8') as fp:
        fp.write(pages_text)

代理IP

  • 在爬取数据的时候可能会报出一个HttpConnectilonPool的错误

    • 原因
      • 请求池资源被耗尽,在headers中加入一个键值对:'Connection':'close'
      • 请求ip被服务器禁用
        • 可以使用代理IP解决
  • 代理:

    • 概念:代理服务器
    • 代理IP网站:快代理、西祠代理、goubanjia
  • 什么是高匿名、匿名和透明代理?他们有什么区别?

    • 使用透明代理,对方服务器可以知道你使用了代理,并且也知道你的真实IP
    • 使用匿名代理.对方服务器可以知道你使用了代理,但不知道你的真实IP
    • 使用高匿名代理:对方服务器不知道你使用了代理,更不知道你的真实IP
  • 类型:

    • http:只可以发起http请求
    • https:只可以发起https请求
  • 简单的ip代理演示

    url = 'https://www.baidu.com/s?wd=ip'
    page_text = requests.get(url=url,headers=headers,proxies={'http':'177.91.254.51:9999'})
    with open('./ip.html','w',encoding='utf-8') as fp
      fp.wirte(page_text)

线程池

  • 线程池:尽可能用在耗时较为严重的操作中

    • 视频的请求下载

    • 视频的持久化存储

    • 使用模块

      #模块引入
      from multiprocessing.dummy import Pool
      
      #创建线程数量
      pool = Pool(4)
      
      pool.map(func,iterable,chunksize=None)
      #map方法可以基于异步实现:让参数1对应的函数对参数2对应的容器元素一次进行操作,参数二必须是可迭代的,比如最典型的列表
      
  • 模拟请求阻塞操作

    • 普通的访问方式
    普通的访问方式
    import time
    def my_request(url):
        print('正在请求:',url)
        #设置了休眠等待
        time.sleep(10)
        print('请求完毕:', url)
    
    urls = [
        'www.1.com',
        'www.2.com',
        'www.3.com',
        'www.4.com',
    ]
    
    start = time.time()
    for url in urls:
        my_request(url)
    print(time.time()-start)
    • 使用线程池

      #使用线程池
      import time
      from multiprocessing.dummy import Pool
      pool = Pool(4)
      
      def my_request(url):
          print('正在请求:',url)
          time.sleep(10)
          print('请求完毕:', url)
      
      urls = [
          'www.1.com',
          'www.2.com',
          'www.3.com',
          'www.4.com',
      ]
      
      start = time.time()
      pool.map(my_request,urls)
      print(time.time()-start)
      pool.close()
      #join的意思是让主线程等待子线程全部结束后再结束
      pool.join()
  • 案例:对梨视频的视频爬取

    #对梨视频的视频爬取
    
    import re,random
    import requests
    from lxml import etree
    from multiprocessing.dummy import Pool
    pool = Pool(4)
    
    #定义一个函数,传送每一个url,下载视频
    def downloadDate(url):
        #content爬取二进制使用
        return requests.get(url=url,headers=headers).content
    #定义一个函数,存储每一个视频
    def saveDate(data):
        name = str(random.randint(0,10000))+'mp4'
        with open(name,'wb') as fp:
            fp.write(data)
        print(name,'下载成功')
    url = 'https://www.pearvideo.com/category_1'
    headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
    }
    
    page_text = requests.get(url=url,headers=headers).text
    tree = etree.HTML(page_text)
    li_list = tree.xpath('//ul[@id="listvideoListUl"]/li')
    #定义一个空列表存放所有的视频链接
    urls = []
    for li in li_list:
        detail_url = 'https://www.pearvideo.com/'+li.xpath('./div/a/@href')[0]
        pages_text = requests.get(url=detail_url,headers=headers).text
        ex = 'srcUrl="(.*?)",vdoUrl'
        video_url = re.findall(ex,pages_text,re.S)[0]
        urls.append(video_url)
    #在耗时较为严重的地方使用线程池,视频的请求下载及持久化存储
    #让函数对urls中的每一个元素进行异步网络请求下载
    #函数不能传参,不能加括号
    #datas是一个列表,存储的是所有的视频二进制的数据
    datas = pool.map(downloadDate,urls)
    
    pool.map(saveDate,datas)
    
    pool.close()
    #join的意思是让主线程等待子线程全部结束后再结束
    pool.join()
    
    
    
    #在获取视频链接的时候发现视频并不是存储在标签中,而是在js中的变量里,
    # 此时我们只能使用支持各种匹配的正则来获取链接
    """
    var contId="1565375",liveStatusUrl="liveStatus.jsp",
    liveSta="",playSta="1",autoPlay=!1,isLiving=!1,isVrVideo=!1,
    hdflvUrl="",sdflvUrl="",hdUrl="",sdUrl="",ldUrl="",
    srcUrl="https://video.pearvideo.com/mp4/short/20190612/cont-1565375-14010027-hd.mp4",
    vdoUrl=srcUrl,skinRes="//www.pearvideo.com/domain/skin",videoCDN="//video.pearvideo.com";
    """
  • 爬取喜马拉雅中的相声

    #爬取喜马拉雅中的相声
    import requests
    from multiprocessing.dummy import Pool
    pool = Pool(10)
    #定义一个函数,传送每一个url,下载视频
    def downloadDate(url):
        # content爬取二进制使用
        return requests.get(url=url,headers=headers).content
    
    #定义一个函数,存储每一个视频
    def saveDate(data):
        i = 0
        print(data)
        with open(name_list[i],'wb') as fp:
            fp.write(data)
        print(name_list[i], '下载成功')
        i += 1
    url = 'https://www.ximalaya.com/revision/play/album?albumId=9723091&pageNum=%d&sort=0&pageSize=30'
    
    for page in range(1,2):
        headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
        }
        params = {
            "albumId": "9723091",
            "pageNum": page,
            "sort": "0",
            "pageSize": "30"
        }
    
        new_url = format(url%page)
        #该数据为json数据,需要使用json进行解读,要带括号
        page_json = requests.get(url=new_url,headers=headers,params=params).json()
        pages_json = page_json['data']['tracksAudioPlay']
    
        src_list = []  #存放下音频连接
        name_list = []  #存放音频名字
        for pages in pages_json:
            src_list.append(pages['src'])
            name_list.append(pages['trackName'])
    
        # datas是一个列表,存储的是所有的音频二进制的数据
        datas = pool.map(downloadDate,src_list)
    
        print(datas)
    
        pool.map(saveDate,datas)
        pool.close()
        pool.join()

猜你喜欢

转载自www.cnblogs.com/Godisgirl/p/11020292.html