zoukankan      html  css  js  c++  java
  • Python

    单线程多任务的异步爬虫

    • 协程基础

      • 特殊函数:
        • 就是async关键字修饰的一个函数的定义
        • 特殊之处
          • 特殊函数被调用后会返回一个协程对象
          • 特殊函数调用后内部的程序语句没有被立即执行
    • 协程

      • 对象 协程==特殊的函数 ,协程表示的就是一组特定的操作
    • 任务对象

      • 高级的协程(对协程的进一步封装)
        • 任务对象 =协程==特殊的函数
          • 任务对象==特殊的函数
      • 绑定回调:
        • task.add_done_callback(task)
          • 参数task:当前回调函数对应的任务对象
          • task.result():返回的就是任务对象对应的特殊函数的返回值
    • 事件循环对象

      • 创建事件循环对象
      • 将任务对象注册到改对象中并且开启该对象
      • 作用:
        • loop可以将其内部注册的所有的任务对象进行异步执行
    • 挂起:交出cpu的使用权,

    • 重点:在特殊函数的内部的实现中,不可以出现不支持异步的模块代码,如果出现了则会中断整个的异步效果!!!

    • requests 一定是不支持异步

    • aiohttp是一个支持异步的网络请求模块

      • 环境安装

      • 编码流程

        • 大致的架构

          •   with aiohttp.ClientSession() as s:
                 #s.get(url,headers,params,proxy="http://ip:port")
                 with s.get(url) as response:
                     #response.read()二进制(.content)
                     page_text = response.text()
                     return page_text
            
        • 补充细节

          • 在每一个with前加上async关键字

          • 需要在每一个阻塞操作前加上await关键字

            •   async with aiohttp.ClientSession() as s:
                    #s.get(url,headers,params,proxy="http://ip:port")
                    async with await s.get(url) as response:
                        #response.read()二进制(.content)
                        page_text = await response.text()
                        return page_text
              

    特殊函数

    import asyncio
    from time import sleep
    #特殊函数
    
    async def get_request(url):
        print('正在下载:',url)
        sleep(2)
        print('下载完成',url)
    
        return 'page_text'
    
    #回调函数的定义(一定是一个普通的函数)
    def parse(task):
        #参数表示的就是任务对象
        print('i am callback!!!',task.result())
    
    
    #特殊函数的调用
    c = get_request('wwww.1.com')
    
    #创建一个任务对象
    task = asyncio.ensure_future(c)
    #给任务对象绑定一个回调函数
    task.add_done_callback(parse)
    
    #创建一个事件循环对象
    loop = asyncio.get_event_loop()
    
    # 将任务对象注册到改对象中并且开启该对象
    loop.run_until_complete(task) #让loop执行了一个任务
    

    多任务异步

    import asyncio
    from  time import sleep
    import time
    #特殊的函数
    async def get_request(url):
        print('正在下载',url)
        await  asyncio.sleep(2)
        print('下载完成',url)
        return 'i am page_text!!!'
    def parse(task):
        page_text = task.result()
        print(page_text)
    
    
    # 多任务的异步协程
    start = time.time()
    urls = ['www.1.com','www.2.com','www.3.com']
    tasks = []#存储的是所有的任务对象,多任务!
    for url in urls:
        c= get_request(url)
        task = asyncio.ensure_future(c)
        task.add_done_callback(parse)
        tasks.append(task)
    
    
    loop = asyncio.get_event_loop()
    #asyncio.wait(tasks):给每一个任务对象赋予一个可被挂起的权限
    loop.run_until_complete(asyncio.wait(tasks))
    print('总耗时:',time.time()-start)
    

    基于aiohttp的多任务异步爬虫

    import asyncio
    import aiohttp
    import time
    from bs4 import BeautifulSoup
    #将被请求的url全部整合到一个列表中
    urls = ['http://127.0.0.1:5000/bobo','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom']
    start = time.time()
    
    async def get_request(url):
        async with aiohttp.ClientSession() as s:
            #s.get(url,headers,params,proxy="http://ip:port")
            async with await s.get(url) as response:
                #response.read()二进制(.content)
                page_text = await response.text()
                return page_text
    
    def parse(task):
        page_text = task.result()
        soup = BeautifulSoup(page_text,'lxml')
        data = soup.find('div',class_="tang").text
        print(data)
    tasks = []
    for url in urls:
        c = get_request(url)
        task = asyncio.ensure_future(c)
        task.add_done_callback(parse)
        tasks.append(task)
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))
    
    print('总耗时:',time.time()-start)
    

    selenium 的基本使用

    • 概念:基于浏览器自动化的一个模块.

    • 环境的安装

      • pip install selenium
    • selenium和爬虫之间的关联:

      • 模拟登录
      • 便捷的捕获到动态加载的数据(重点)
        • 特点:可见及可得
        • 缺点:效率低
    • selenium的集体使用

    • 动作链:ActionChains,一系列的行为动作

      • 使用流程:
        • 实例化一个动作连对象,需要将指定的浏览器和动作连对象进行绑定
        • 执行相关的连续的动作
        • perform()立即执行动作连制定好的动作
    • 12306模拟登录分析:

      • 验证码的的处理:
    • selenium规避风险

      • 正经打开一个网站进行window.navigator.webdriver的js注入,返回值为undefined
      • 使用selenium打开的页面,进行上述js注入返回的是true
    • 无头浏览器

      • phantomJs
      • 谷歌无头
    selenium 的基本使用代码
    from selenium import webdriver
    from time import sleep
    #结合着浏览去的驱动实例化一个浏览器对象
    bro = webdriver.Chrome(executable_path='./chromedriver.exe')
    
    #请求的发送
    url = 'https://www.jd.com/'
    bro.get(url)
    sleep(1)
    #标签定位
    # bro.find_element_by_xpath('//input[@id="key"]')
    search = bro.find_element_by_id('key')
    search.send_keys('mac pro')#向指定标签中录入文本数据
    sleep(2)
    btn = bro.find_element_by_xpath('//*[@id="search"]/div/div[2]/button')
    btn.click()
    sleep(2)
    #JS注入
    bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    
    #捕获到当前页面的数据
    page_text = bro.page_source
    print(page_text)
    sleep(3)
    
    bro.quit()
    

    selenium 动态加载数据的捕获代码

    #http://125.35.6.84:81/xk/,将药监总局前3页的企业名称进行爬取
    from selenium import webdriver
    from lxml import etree
    from time import sleep
    bro = webdriver.Chrome(executable_path='./chromedriver.exe')
    url = 'http://125.35.6.84:81/xk/'
    bro.get(url)
    page_text = bro.page_source
    
    all_page_text = [page_text]
    #点击下一页
    for i in range(2):
        nextPage = bro.find_element_by_xpath('//*[@id="pageIto_next"]')
        nextPage.click()
        sleep(1)
        all_page_text.append(bro.page_source)
    
    for page_text in all_page_text:
        tree = etree.HTML(page_text)
        li_list = tree.xpath('//*[@id="gzlist"]/li')
        for li in li_list:
            name = li.xpath('./dl/@title')[0]
            print(name)
    
    
    sleep(2)
    bro.quit()
    

    selenium动作链

    from selenium import webdriver
    from selenium.webdriver import ActionChains#动作连
    from time import sleep
    bro = webdriver.Chrome(executable_path='./chromedriver.exe')
    
    url = 'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
    
    bro.get(url)
    #NoSuchElementException:定位的标签是存在与iframe之中,则就会抛出这个错误
    #解决方法:switch_to.frame进行指定子页面的切换
    bro.switch_to.frame('iframeResult')
    div_tag = bro.find_element_by_xpath('//*[@id="draggable"]')
    
    #实例化一个动作连对象
    action = ActionChains(bro)
    action.click_and_hold(div_tag)#点击且长按
    
    #perform()让动作连立即执行
    for i in range(5):
        action.move_by_offset(xoffset=15,yoffset=15).perform()
        sleep(2)
    action.release()
    sleep(5)
    bro.quit()
    

    12306模拟登陆代码

    from selenium import webdriver
    from selenium.webdriver import ActionChains
    from time import sleep
    from PIL import Image #安装PIL或者是Pillow
    from CJY import Chaojiying_Client #超级鹰
    
    #封装一个识别验证码的函数
    def transformCode(imgPath,imgType):
        chaojiying = Chaojiying_Client('bobo328410948', 'bobo328410948', '899370')
        im = open(imgPath, 'rb').read()
        return chaojiying.PostPic(im, imgType)['pic_str']
    
    
    bro = webdriver.Chrome(executable_path='./chromedriver.exe')
    
    bro.get('https://kyfw.12306.cn/otn/login/init')
    sleep(2)
    #将当前浏览器页面进行图片保存
    bro.save_screenshot('./main.png')
    #将验证码的局部区域进行裁剪
    #捕获标签在页面中的位置信息
    img_tag = bro.find_element_by_xpath('//*[@id="loginForm"]/div/ul[2]/li[4]/div/div/div[3]/img')
    location = img_tag.location#标签的起始位置坐标(左下角坐标)
    size = img_tag.size#标签的尺寸
    #裁剪范围对应的矩形区域
    rangle = (int(location['x']),int(location['y']),int(location['x']+size['width']),int(location['y']+size['height']))
    #使用Image工具进行指定区域的裁剪
    i = Image.open('./main.png')
    frame = i.crop(rangle)#crop就是根据指定的裁剪范围进行图片的截取
    frame.save('code.png')
    
    #调用打码平台进行验证码的识别
    result = transformCode('./code.png',9004)
    print(result) #x1,y1|x2,y2|x3,y3
    
    #x1,y1|x2,y2|x3,y3 ==>[[x1,y1],[x2,y2],[x3,y3]]
    all_list = []#[[x1,y1],[x2,y2],[x3,y3]]
    if '|' in result:
        list_1 = result.split('|')
        count_1 = len(list_1)
        for i in range(count_1):
            xy_list = []
            x = int(list_1[i].split(',')[0])
            y = int(list_1[i].split(',')[1])
            xy_list.append(x)
            xy_list.append(y)
            all_list.append(xy_list)
    else:
        x = int(result.split(',')[0])
        y = int(result.split(',')[1])
        xy_list = []
        xy_list.append(x)
        xy_list.append(y)
        all_list.append(xy_list)
    
    
    for point in all_list:
        x = point[0]
        y = point[1]
        ActionChains(bro).move_to_element_with_offset(img_tag,x,y).click().perform()
        sleep(1)
    
    
    bro.find_element_by_id('username').send_keys('xxxxxx')
    sleep(1)
    bro.find_element_by_id('password').send_keys('xxxx')
    sleep(1)
    
    bro.find_element_by_id('loginSub').click()
    
    sleep(10)
    print(bro.page_source)
    bro.quit()
    
    

    违规检测 + 无头浏览器代码

    #规避检测
    # from selenium import webdriver
    # from selenium.webdriver import ChromeOptions
    # option = ChromeOptions()
    # option.add_experimental_option('excludeSwitches', ['enable-automation'])
    #
    # bro = webdriver.Chrome(executable_path='./chromedriver.exe',options=option)
    #
    # url = 'https://www.taobao.com/'
    #
    # bro.get(url)
    
    #无头浏览器
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from time import sleep
    chrome_options = Options()
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--disable-gpu')
    
    bro = webdriver.Chrome(executable_path='./chromedriver.exe',chrome_options=chrome_options)
    url = 'https://www.taobao.com/'
    bro.get(url)
    sleep(2)
    bro.save_screenshot('123.png')
    
    print(bro.page_source)
    
    
    • 单线程+多任务的异步协程
      • 特殊函数
        • 调用,函数内部程序语句不会被立即执行
        • 调用之后会返回一个协程对象
      • 协程
        • 对象表示一组操作
      • 任务对象
        • 高级的协程。任务对象就表示一组指定的操作
        • 绑定回调:
          • add_done_callback(task):task.result()
      • 事件循环
        • eventLoop.
        • 需要将所有的任务对象注册到该对象中
        • 开启事件循环
      • await:
        • 被用作在特殊函数内部(被阻塞)。
      • wait(tasks):
        • 给每一个任务对象赋予一个可被挂起的权限。
      • 注意:特殊函数内部不可以出现不支持异步模块的代码。
      • aiohttp:支持异步的网络请求模块。
        async with aiohttp.ClintSession() as s:
        async with await s.get(url) as response:
        page_text = await response.text()
        return page_text
    • selenium
      • selenium和爬虫之间的关联
        • 模拟登录
        • 便捷获取动态加载的数据
      • 相关的方法和属性:
        • get(url)
        • find_xxx:标签定位
        • switch_to.frame(id)
        • send_keys(xxx)
        • click()
        • page_source
        • js注入:execute_script(jsCode)
        • 动作连
        • 无头浏览器
        • 规避检测
  • 相关阅读:
    Ubuntu 14.04 卸载通过源码安装的库
    Ubuntu 14.04 indigo 相关依赖
    Ubuntu 14.04 indigo 安装 cartographer 1.0.0
    Ubuntu 14.04 改变文件或者文件夹的拥有者
    安装cartographer遇到Unrecognized syntax identifier "proto3". This parser only recognizes "proto2"问题
    Unrecognized syntax identifier "proto3". This parser only recognizes "proto2". ”问题解决方法
    查看所有用户组,用户名
    1卸载ROS
    Ubuntu14.04 软件安装卸载
    Ubuntu14.04系统显示器不自动休眠修改
  • 原文地址:https://www.cnblogs.com/zgboy/p/13172668.html
Copyright © 2011-2022 走看看