精华内容
下载资源
问答
  • 这本书全面介绍了C语言的一些核心技术,并被国外多所名牌大学采用为教材,希望对各位有所帮助!
  • [转]OpenGL核心技术之帧缓冲

    万次阅读 2017-02-12 15:03:48
    已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。 CSDN视频网址:http://edu.csdn.net/lecturer/144 本篇博文主要是给读者解密关于游戏后处理渲染效果的...

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

    CSDN视频网址:http://edu.csdn.net/lecturer/144

    本篇博文主要是给读者解密关于游戏后处理渲染效果的原理,后处理渲染效果在Unity,UE4虚幻引擎等商业引擎 使用的非常多,

    比如Bloom,Blur,SSAO,PSSM,HDR等等都属于后处理渲染效果,它们的实现其实就是应用帧缓冲技术实现的,本篇博文主要是

    围绕帧缓冲给读者介绍其实现原理以及应用案例。

    在前面给读者介绍了几种不同的屏幕缓冲:用于写入颜色值的颜色缓冲,用于写入深度信息的深度缓冲,以及允许我们基于一些条件丢弃指定片段的模板缓冲。本篇博客主要是给读者介绍帧缓冲,什么是帧缓冲?其实就是把前面介绍的这几种缓冲结合起来叫做帧缓冲(Framebuffer),它被储存于内存中。OpenGL给了我们自己定义帧缓冲的自由,我们可以选择性的定义自己的颜色缓冲、深度和模板缓冲。本篇博客主要是给读者介绍帧缓冲,我们前面介绍的渲染操作都是在默认的帧缓冲之上进行的,当你创建了你的窗口的时候默认帧缓冲就被创建和配置好了,通过创建我们自己的帧缓冲我们能够获得一种额外的渲染方式。通过帧缓冲可以将你的场景渲染到一个不同的帧缓冲中,可以使我们能够在场景中创建镜子这样的效果,或者做出一些炫酷的特效。首先我们会讨论它们是如何工作的,然后我们将利用帧缓冲来实现一些炫酷的效果。

    我们在引擎渲染中经常会使用一些后处理效果,这些后处理效果就是在帧缓冲中进行的。下面我们就告诉读者帧缓冲是如何工作的?

    我们可以使用一个叫做glGenFramebuffers的函数来创建一个帧缓冲对象(简称FBO):

     

    GLuint fbo;
    glGenFramebuffers(1, &fbo);

     

    首先我们要创建一个帧缓冲对象,把它绑定到当前帧缓冲,做一些操作,然后解绑帧缓冲。我们使用glBindFramebuffer来绑定帧缓冲:

    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

     

    绑定到GL_FRAMEBUFFER目标后,接下来所有的读、写帧缓冲的操作都会影响到当前绑定的帧缓冲。也可以把帧缓冲分开绑定到读或写目标上,分别使用GL_READ_FRAMEBUFFER或GL_DRAW_FRAMEBUFFER来做这件事。如果绑定到了GL_READ_FRAMEBUFFER,就能执行所有读取操作,

    像glReadPixels这样的函数使用了,绑定到GL_DRAW_FRAMEBUFFER上,就允许进行渲染、清空和其他的写入操作。在此给读者总结一下构建一个完整的帧

    缓冲满足的条件:

    建构一个完整的帧缓冲必须满足以下条件:

    • 我们必须往里面加入至少一个附件(颜色、深度、模板缓冲)。
    • 其中至少有一个是颜色附件。
    • 所有的附件都应该是已经完全做好的(已经存储在内存之中)。
    • 每个缓冲都应该有同样数目的样本。

    上面的条件提到了样本,如果你不知道什么是样本也不用担心,我们会在后面的博文中讲到。

    我们需要为帧缓冲创建一些附件(Attachment),还需要把这些附件附加到帧缓冲上。当我们做完所有上面提到的条件的时候我们就可以用 glCheckFramebufferStatus 带上 GL_FRAMEBUFFER 这个参数来检查是否真的成功做到了。然后检查当前绑定的帧缓冲,返回了这些规范中的哪个值。如果返回的是 GL_FRAMEBUFFER_COMPLETE就对了:

     

    if(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
      // Execute victory dance

    后续所有渲染操作将渲染到当前绑定的帧缓冲的附加缓冲中,由于我们的帧缓冲不是默认的帧缓冲,渲染命令对窗口的视频输出不会产生任何影响。出于这个原因,它被称为离屏渲染(off-screen rendering),就是渲染到一个另外的缓冲中。为了让所有的渲染操作对主窗口产生影响我们必须通过绑定为0来使默认帧缓冲被激活:

     

     

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    当我们做完所有帧缓冲操作,不要忘记删除帧缓冲对象:

     

     

     

     

    glDeleteFramebuffers(1, &fbo);


    现在在执行完成检测前,我们需要把一个或更多的附件附加到帧缓冲上。一个附件就是一个内存地址,这个内存地址里面包含一个为帧缓冲准备的缓冲,它可以是个图像。当创建一个附件的时候我们有两种方式可以采用:纹理或渲染缓冲(renderbuffer)对象。

     

    接下来介绍纹理当把一个纹理附加到帧缓冲上的时候,所有渲染命令会写入到纹理上,就像它是一个普通的颜色/深度或者模板缓冲一样。使用纹理的好处是,所有渲染操作的结果都会被储存为一个纹理图像,这样我们就可以简单的在着色器中使用了。

    创建一个帧缓冲的纹理和创建普通纹理差不多:

    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    这里主要的区别是我们把纹理的维度设置为屏幕大小(尽管不是必须的),我们还传递NULL作为纹理的data参数。对于这个纹理,

     

    我们只分配内存,而不去填充它。纹理填充会在渲染到帧缓冲的时候去做。

     

    如果你打算把整个屏幕渲染到一个或大或小的纹理上,你需要用新的纹理的尺寸作为参数再次调用glViewport(要在渲染到你的帧缓冲之前

    做好),否则只有一小部分纹理或屏幕能够绘制到纹理上。现在我们已经创建了一个纹理,最后一件要做的事情是把它附加到帧缓冲上:

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D, texture, 0);

    glFramebufferTexture2D函数需要传入下列参数:

    • target:我们所创建的帧缓冲类型的目标(绘制、读取或两者都有)。
    • attachment:我们所附加的附件的类型。现在我们附加的是一个颜色附件。需要注意,最后的那个0是暗示我们可以附加1个以上颜色的附件。我们会在后面的教程中谈到。
    • textarget:你希望附加的纹理类型。
    • texture:附加的实际纹理。
    • level:Mipmap level。我们设置为0。

    除颜色附件以外,我们还可以附加一个深度和一个模板纹理到帧缓冲对象上。为了附加一个深度缓冲,我们可以知道那个GL_DEPTH_ATTACHMENT作为附件类型。记住,这时纹理格式和内部格式类型(internalformat)就成了 GL_DEPTH_COMPONENT去反应深度缓冲的存储格式。附加一个模板缓冲,你要使用 GL_STENCIL_ATTACHMENT作为第二个参数,把纹理格式指定为GL_STENCIL_INDEX

    也可以同时附加一个深度缓冲和一个模板缓冲为一个单独的纹理,这样纹理的每32位数值就包含了24位的深度信息和8位的模板信息。为了把一个深度和模板缓冲附加到一个单独纹理上,我们使用GL_DEPTH_STENCIL_ATTACHMENT类型配置纹理格式以包含深度值和模板值的结合物。下面是一个附加了深度和模板缓冲为单一纹理的例子:

    glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 800, 600, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL );
    
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texture, 0);

    再介绍渲染缓冲对象OpenGL引进了渲染缓冲对象(Renderbuffer objects),所以在过去那些美好时光里纹理是附件的唯一可用的类型。和纹理图像一样,渲染缓冲对象也是一个缓冲,它可以是一堆字节、整数、像素或者其他东西。渲染缓冲对象的一大优点是,它以OpenGL原生渲染格式储存它的数据,因此在离屏渲染到帧缓冲的时候,这些数据就相当于被优化过的了。

    渲染缓冲对象将所有渲染数据直接储存到它们的缓冲里,而不会进行针对特定纹理格式的任何转换,这样它们就成了一种快速可写的存储介质了。然而,渲染缓冲对象通常是只写的,不能修改它们(就像获取纹理,不能写入纹理一样)。可以用glReadPixels函数去读取,函数返回一个当前绑定的帧缓冲的特定像素区域,而不是直接返回附件本身。

    因为它们的数据已经是原生格式了,在写入或把它们的数据简单地到其他缓冲的时候非常快。当使用渲染缓冲对象时,像切换缓冲这种操作变得异常高速。我们在每个渲染迭代末尾使用的那个glfwSwapBuffers函数,同样以渲染缓冲对象实现:我们简单地写入到一个渲染缓冲图像,最后交换到另一个里。渲染缓冲对象对于这种操作来说很完美。

    创建一个渲染缓冲对象和创建帧缓冲代码差不多:

    GLuint rbo;
    glGenRenderbuffers(1, &rbo);


    相似地,我们打算把渲染缓冲对象绑定,这样所有后续渲染缓冲操作都会影响到当前的渲染缓冲对象:

     

    glBindRenderbuffer(GL_RENDERBUFFER, rbo);

     

    由于渲染缓冲对象通常是只写的,它们经常作为深度和模板附件来使用,由于大多数时候,我们不需要从深度和模板缓冲中读取数据,但仍关心深度和模板测试。我们就需要有深度和模板值提供给测试,但不需要对这些值进行采样(sample),所以深度缓冲对象是完全符合的。当我们不去从这些缓冲中采样的时候,渲染缓冲对象通常很合适,因为它们等于是被优化过的。

     

    调用glRenderbufferStorage函数可以创建一个深度和模板渲染缓冲对象:

    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600);

     

    创建一个渲染缓冲对象与创建纹理对象相似,不同之处在于这个对象是专门被设计用于图像的,而不是通用目的的数据缓冲,比如纹理。这里我们选择GL_DEPTH24_STENCIL8作为内部格式,它同时代表24位的深度和8位的模板缓冲。

     

    最后一件还要做的事情是把帧缓冲对象附加上:

    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);


    在帧缓冲项目中,渲染缓冲对象可以提供一些优化,但更重要的是知道何时使用渲染缓冲对象,何时使用纹理。通常的规则是,如果你永远都不需要从特定的缓冲中进行采样,渲染缓冲对象对特定缓冲是更明智的选择。如果哪天需要从比如颜色或深度值这样的特定缓冲采样数据的话,你最好还是使用纹理附件。从执行效率角度考虑,它不会对效率有太大影响。

     

     

    下面通过案例的方式介绍如何使用帧缓存,我们会把场景渲染到一个颜色纹理上,这个纹理附加到一个我们创建的帧缓冲上,然后把纹

     

     

    理绘制到一个简单的四边形上,这个四边形铺满整个屏幕。输出的图像看似和没用帧缓冲一样,但是这次,它其实是直接打印到了一个单独的

    四边形上面。为什么这很有用呢?下一部分我们会看到原因。

    第一件要做的事情是创建一个帧缓冲对象,并绑定它,这比较明了:

     

    GLuint framebuffer;
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);

    第二件要做的事情是我们创建一个纹理图像,这是我们将要附加到帧缓冲的颜色附件。我们把纹理的尺寸设置为窗口的宽度和高度,并保持数据未初始化:

     

     

     

     

    // Generate texture
    GLuint texColorBuffer;
    glGenTextures(1, &texColorBuffer);
    glBindTexture(GL_TEXTURE_2D, texColorBuffer);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);
    
    // Attach it to currently bound framebuffer object
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0);

    我们同样打算要让OpenGL确定可以进行深度测试(模板测试,如果你用的话)所以我们必须还要确保向帧缓冲中添加一个深度(和模板)

     

    附件。由于我们只采样颜色缓冲,并不采样其他缓冲,我们可以创建一个渲染缓冲对象来达到这个目的。

    创建一个渲染缓冲对象不太难。唯一一件要记住的事情是,我们正在创建的是一个渲染缓冲对象的深度和模板附件。我们把它的内部给事设置

    GL_DEPTH24_STENCIL8,对于我们的目的来说这个精确度已经足够了。

    GLuint rbo;
    glGenRenderbuffers(1, &rbo);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600);  
    glBindRenderbuffer(GL_RENDERBUFFER, 0);

     

    我们为渲染缓冲对象分配了足够的内存空间以后,我们可以解绑渲染缓冲。

    接着,在做好帧缓冲之前,还有最后一步,我们把渲染缓冲对象附加到帧缓冲的深度和模板附件上:

     

    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);

     

    然后我们要检查帧缓冲是否真的做好了,如果没有,我们就打印一个错误消息。

     

     

    if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
     cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

     

    还要保证解绑帧缓冲,这样我们才不会意外渲染到错误的帧缓冲上。

    现在帧缓冲做好了,我们要做的全部就是渲染到帧缓冲上,而不是绑定到帧缓冲对象的默认缓冲。余下所有命令会影响到当前绑定的帧缓冲上。所有深度和模板操作同样会从当前绑定的帧缓冲的深度和模板附件中读取,当然,得是在它们可用的情况下。如果你遗漏了比如深度缓冲,所有深度测试就不会工作,因为当前绑定的帧缓冲里没有深度缓冲。

    所以,为把场景绘制到一个单独的纹理,我们必须以下面步骤来做:

    1. 使用新的绑定为激活帧缓冲的帧缓冲,像往常那样渲染场景。
    2. 绑定到默认帧缓冲。
    3. 绘制一个四边形,让它平铺到整个屏幕上,用新的帧缓冲的颜色缓冲作为他的纹理。

    为了绘制四边形我们将会创建新的着色器。我们不打算引入任何花哨的变换矩阵,因为我们只提供已经是标准化设备坐标的顶点坐标,所以我们可以直接把它们作为顶点着色器的输出。顶点着色器看起来像这样:

     

    #version 330 core
    layout (location = 0) in vec2 position;
    layout (location = 1) in vec2 texCoords;
    
    out vec2 TexCoords;
    
    void main()
    {
        gl_Position = vec4(position.x, position.y, 0.0f, 1.0f);
        TexCoords = texCoords;
    }


    片段着色器更简洁,因为我们做的唯一一件事是从纹理采样:

     

     

     

    #version 330 core
    in vec2 TexCoords;
    out vec4 color;
    
    uniform sampler2D screenTexture;
    
    void main()
    {
        color = texture(screenTexture, TexCoords);
    }

     

    接着需要你为屏幕上的四边形创建和配置一个VAO。渲染迭代中帧缓冲处理会有下面的结构:

    // First pass
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // We're not using stencil buffer now
    glEnable(GL_DEPTH_TEST);
    DrawScene();
    
    // Second pass
    glBindFramebuffer(GL_FRAMEBUFFER, 0); // back to default
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    
    screenShader.Use();  
    glBindVertexArray(quadVAO);
    glDisable(GL_DEPTH_TEST);
    glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);

     

    第一,由于我们用的每个帧缓冲都有自己的一系列缓冲,我们打算使用glClear设置的合适的位(bits)来清空这些缓冲。

     

    第二,当渲染四边形的时候,我们关闭深度测试,因为我们不关系深度测试,我们绘制的是一个简单的四边形;当我们绘制普通场景时我们必须再次开启深度测试。实现效果如下所示:

     

    上述案例实现得出的结果是可以自由的获取渲染场景中的任何像素,其实就是把它作为一个纹理图像。接下来利用帧缓冲实现我们游戏中经常使用的后处理效果,比如游戏中颜色的反相处理,就是把颜色值取反。这个在片段着色器中处理即可,在片段着色器里返回这些颜色的反色(Inversion)并不难。我们得到屏幕纹理的颜色,然后用1.0减去它:

     

    void main()
    {
        color = vec4(vec3(1.0 - texture(screenTexture, TexCoords)), 1.0);
    }

    反相是一种相对简单的后处理特效,实现的效果如下所示:

     


     

    这样把整个场景都处理了,这也是后处理渲染实现的效果,这样只需要在上述片段着色器中修改一行代码即可实现。

    下面再继续深入探讨,在单独纹理图像上进行后处理的另一个好处是我们可以从纹理的其他部分进行采样。比如我们可以从当前纹理值的周围采样多个纹理值。创造性地把它们结合起来就能创造出有趣的效果了。

    kernel是一个长得有点像一个小矩阵的数值数组,它中间的值中心可以映射到一个像素上,这个像素和这个像素周围的值再乘以kernel,最后再把结果相加就能得到一个值。所以,我们基本上就是给当前纹理坐标加上一个它四周的偏移量,然后基于kernel把它们结合起来。下面是一个kernel的例子:

    这个kernel表示一个像素周围八个像素乘以2,它自己乘以-15。这个例子基本上就是把周围像素乘上2,中间像素去乘以一个比较大的负数来进行平衡。kernel对于后处理来说非常管用,因为用起来简单。网上能找到有很多实例,为了能用上kernel我们还得改改片段着色器。这里假设每个kernel都是3×3(实际上大多数都是3×3):

     

    const float offset = 1.0 / 300;  
    
    void main()
    {
        vec2 offsets[9] = vec2[](
            vec2(-offset, offset),  // top-left
            vec2(0.0f,    offset),  // top-center
            vec2(offset,  offset),  // top-right
            vec2(-offset, 0.0f),    // center-left
            vec2(0.0f,    0.0f),    // center-center
            vec2(offset,  0.0f),    // center-right
            vec2(-offset, -offset), // bottom-left
            vec2(0.0f,    -offset), // bottom-center
            vec2(offset,  -offset)  // bottom-right
        );
    
        float kernel[9] = float[](
            -1, -1, -1,
            -1,  9, -1,
            -1, -1, -1
        );
    
        vec3 sampleTex[9];
        for(int i = 0; i < 9; i++)
        {
            sampleTex[i] = vec3(texture(screenTexture, TexCoords.st + offsets[i]));
        }
        vec3 col;
        for(int i = 0; i < 9; i++)
            col += sampleTex[i] * kernel[i];
    
        color = vec4(col, 1.0);
    }

     

     

    在片段着色器中我们先为每个四周的纹理坐标创建一个9个vec2偏移量的数组。偏移量是一个简单的常数,你可以设置为自己喜欢的。接着我们定义kernel,这里应该是一个锐化kernel,它通过一种有趣的方式从所有周边的像素采样,对每个颜色值进行锐化。最后,在采样的时候我们把每个偏移量加到当前纹理坐标上,然后用加在一起的kernel的值乘以这些纹理值。

    这个锐化的kernel看起来像这样:

    再举个例子关于模糊(Blur)效果的Kernel定义如下:

    由于所有数值加起来的总和为16,简单返回结合起来的采样颜色是非常亮的,所以我们必须将kernel的每个值除以16.最终的kernel数组会是这样的:

     

    float kernel[9] = float[](
        1.0 / 16, 2.0 / 16, 1.0 / 16,
        2.0 / 16, 4.0 / 16, 2.0 / 16,
        1.0 / 16, 2.0 / 16, 1.0 / 16  
    );

    通过在像素着色器中改变kernel的float数组,我们就完全改变了之后的后处理效果.现在看起来会像是这样:

     


     

    这样的模糊效果具有创建许多有趣效果的潜力,模糊效果在后处理中使用的非常多,它会结合着Bloom后处理渲染使用。模糊也能为我们在后面的教程中提供都颜色值进行平滑处理的能力。

    最后把关于帧缓冲的顶点着色器和片段着色器代码分别给读者展示如下:

    顶点着色器代码:

     

    #version 330 core
    layout (location = 0) in vec2 position;
    layout (location = 1) in vec2 texCoords;
    
    out vec2 TexCoords;
    
    void main()
    {
        gl_Position = vec4(position.x, position.y, 0.0f, 1.0f); 
        TexCoords = texCoords;
    } 


    片段着色器代码如下所示:

     

     

    #version 330 core
    in vec2 TexCoords;
    
    out vec4 color;
    
    uniform sampler2D screenTexture;
    
    const float offset = 1.0 / 300;  
    
    void main()
    {
        vec2 offsets[9] = vec2[](
            vec2(-offset, offset),  // top-left
            vec2(0.0f,    offset),  // top-center
            vec2(offset,  offset),  // top-right
            vec2(-offset, 0.0f),    // center-left
            vec2(0.0f,    0.0f),    // center-center
            vec2(offset,  0.0f),    // center-right
            vec2(-offset, -offset), // bottom-left
            vec2(0.0f,    -offset), // bottom-center
            vec2(offset,  -offset)  // bottom-right    
        );
    
        float kernel[9] = float[](
            -1, -1, -1,
            -1,  9, -1,
            -1, -1, -1
        );
        
        vec3 sampleTex[9];
        for(int i = 0; i < 9; i++)
        {
            sampleTex[i] = vec3(texture(screenTexture, TexCoords.st + offsets[i]));
        }
        vec3 col;
        for(int i = 0; i < 9; i++)
            col += sampleTex[i] * kernel[i];
        
        color = vec4(col, 1.0);
    } 

    另外把在C++中关于处理帧缓存的核心代码给读者展示如下:

     

     

    // Setup cube VAO
        GLuint cubeVAO, cubeVBO;
        glGenVertexArrays(1, &cubeVAO);
        glGenBuffers(1, &cubeVBO);
        glBindVertexArray(cubeVAO);
        glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
        glBindVertexArray(0);
        // Setup plane VAO
        GLuint floorVAO, floorVBO;
        glGenVertexArrays(1, &floorVAO);
        glGenBuffers(1, &floorVBO);
        glBindVertexArray(floorVAO);
        glBindBuffer(GL_ARRAY_BUFFER, floorVBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(floorVertices), &floorVertices, GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
        glBindVertexArray(0);
        // Setup screen VAO
        GLuint quadVAO, quadVBO;
        glGenVertexArrays(1, &quadVAO);
        glGenBuffers(1, &quadVBO);
        glBindVertexArray(quadVAO);
        glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat)));
        glBindVertexArray(0);
    
        // Load textures
        GLuint cubeTexture = loadTexture(FileSystem::getPath("resources/textures/container.jpg").c_str());
        GLuint floorTexture = loadTexture(FileSystem::getPath("resources/textures/metal.png").c_str());
        #pragma endregion
    
        // Framebuffers
        GLuint framebuffer;
        glGenFramebuffers(1, &framebuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);  
        // Create a color attachment texture
        GLuint textureColorbuffer = generateAttachmentTexture(false, false);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);
        // Create a renderbuffer object for depth and stencil attachment (we won't be sampling these)
        GLuint rbo;
        glGenRenderbuffers(1, &rbo);
        glBindRenderbuffer(GL_RENDERBUFFER, rbo); 
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, screenWidth, screenHeight); // Use a single renderbuffer object for both a depth AND stencil buffer.
        glBindRenderbuffer(GL_RENDERBUFFER, 0);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // Now actually attach it
        // Now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now
        if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
        glBindFramebuffer(GL_FRAMEBUFFER, 0);


    每一帧处理的代码如下所示:

     

     

            /
            // Bind to framebuffer and draw to color texture 
            // as we normally would.
            // //
            glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
            // Clear all attached buffers        
            glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // We're not using stencil buffer so why bother with clearing?
    
            glEnable(GL_DEPTH_TEST);
            // Set uniforms
            shader.Use();
            glm::mat4 model;
            glm::mat4 view = camera.GetViewMatrix();
            glm::mat4 projection = glm::perspective(camera.Zoom, (float)screenWidth/(float)screenHeight, 0.1f, 100.0f);
            glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
            glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
    
            // Floor
            glBindVertexArray(floorVAO);
            glBindTexture(GL_TEXTURE_2D, floorTexture);
            model = glm::mat4();
            glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
            glDrawArrays(GL_TRIANGLES, 0, 6);		
            glBindVertexArray(0);	
            // Cubes
            glBindVertexArray(cubeVAO);
            glBindTexture(GL_TEXTURE_2D, cubeTexture);  
            model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
            glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
            glDrawArrays(GL_TRIANGLES, 0, 36);
            model = glm::mat4();
            model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
            glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
            glDrawArrays(GL_TRIANGLES, 0, 36);
            glBindVertexArray(0);			
    
            /
            // Bind to default framebuffer again and draw the 
            // quad plane with attched screen texture.
            // //
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
            // Clear all relevant buffers
            glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways)
            glClear(GL_COLOR_BUFFER_BIT);
            glDisable(GL_DEPTH_TEST); // We don't care about depth information when rendering a single quad
    
            // Draw Screen
            screenShader.Use();
            glBindVertexArray(quadVAO);
            glBindTexture(GL_TEXTURE_2D, textureColorbuffer);	// Use the color attachment texture as the texture of the quad plane
            glDrawArrays(GL_TRIANGLES, 0, 6);
            glBindVertexArray(0);
    
    
            // Swap the buffers
            glfwSwapBuffers(window);

     

     

    总结:
    以上就是关于帧缓冲的介绍,它主要的作用是可以获取到场景像素,后处理就是对场景像素作渲染处理的,所以该技术广泛的被应用在后处理开发中,这也是为读者揭示后处理渲染的本质,希望对大家有所帮助。。。。。

     

     

     

     

     

    展开全文
  • 技术维度:详细讲解了 Python 网络爬虫实现的核心技术,包括网络爬虫的工作原理、如何用 urllib 库编写网络爬虫、爬虫的异常处理、正则表达式、爬虫中 Cookie 的使用、爬虫的浏览器伪装技术、定向爬取技术、反爬虫...

    内容简介

    本书从技术、工具与实战3个维度讲解了 Python 网络爬虫:

    • 技术维度:详细讲解了 Python 网络爬虫实现的核心技术,包括网络爬虫的工作原理、如何用 urllib 库编写网络爬虫、爬虫的异常处理、正则表达式、爬虫中 Cookie 的使用、爬虫的浏览器伪装技术、定向爬取技术、反爬虫技术,以及如何自己动手编写网络爬虫;

    • 工具维度:以流行的 Python 网络爬虫框架 Scrapy 为对象,详细讲解了 Scrapy 的功能使用、高级技巧、架构设计、实现原理,以及如何通过 Scrapy 来更便捷、高效地编写网络爬虫;

    • 实战维度:以实战为导向,是本书的主旨,除了完全通过手动编程实现网络爬虫和通过 Scrapy 框架实现网络爬虫的实战案例以外,本书还有博客爬取、图片爬取、模拟登录等多个综合性的网络爬虫实践案例。

    作者简介

    韦玮,资深网络爬虫技术专家、大数据专家和软件开发工程师,从事大型软件开发与技术服务多年,现任重庆韬翔网络科技有限公司创始人兼 CEO,国家专利发明人。

    精通 Python 技术,在 Python 网络爬虫、Python 机器学习、Python 数据分析与挖掘、Python Web 开发等多个领域都有丰富的实战经验。

    CSDN、51CTO、天善智能等科技类社区和媒体的特邀专家和讲师,输出了大量的高质量课程和文章,深受用户喜爱。

    微博:http://weibo.com/qiansyy

    本书内容

    前言

    为什么写这本书

    网络爬虫其实很早就出现了,最开始网络爬虫主要应用在各种搜索引擎中。在搜索引擎中,主要使用通用网络爬虫对网页进行爬取及存储。

    随着大数据时代的到来,我们经常需要在海量数据的互联网环境中搜集一些特定的数据并对其进行分析,我们可以使用网络爬虫对这些特定的数据进行爬取,并对一些无关的数据进行过滤,将目标数据筛选出来。对特定的数据进行爬取的爬虫,我们将其称为聚焦网络爬虫。在大数据时代,聚焦网络爬虫的应用需求越来越大。

    目前在国内 Python 网络爬虫的书籍基本上都是从国外引进翻译的,国内的本版书籍屈指可数,故而我跟华章的副总编杨福川策划了这本书。本书的撰写过程中各方面的参考资料非常少,因此完成本书所花费的精力相对来说是非常大的。

    本书从系统化的视角,为那些想学习 Python 网络爬虫或者正在研究 Python 网络爬虫的朋友们提供了一个全面的参考,让读者可以系统地学习 Python 网络爬虫的方方面面,在理解并掌握了本书的实例之后,能够独立编写出自己的 Python 网络爬虫项目,并且能够胜任 Python 网络爬虫工程师相关岗位的工作。

    同时,本书的另一个目的是,希望可以给大数据或者数据挖掘方向的从业者一定的参考,以帮助这些读者从海量的互联网信息中爬取需要的数据。所谓巧妇难为无米之炊,有了这些数据之后,从事大数据或者数据挖掘方向工作的读者就可以进行后续的分析处理了。

    本书的主要内容和特色

    本书是一本系统介绍 Python 网络爬虫的书籍,全书注重实战,涵盖网络爬虫原理、如何手写 Python 网络爬虫、如何使用 Scrapy 框架编写网络爬虫项目等关于 Python 网络爬虫的方方面面。

    本书的主要特色如下:

    • 系统讲解 Python 网络爬虫的编写方法,体系清晰。

    • 结合实战,让读者能够从零开始掌握网络爬虫的基本原理,学会编写 Python 网络爬虫以及 Scrapy 爬虫项目,从而编写出通用爬虫及聚焦爬虫,并掌握常见网站的爬虫反屏蔽手段。

    • 有配套免费视频,对于书中的难点,读者可以直接观看作者录制的对应视频,加深理解。

    • 拥有多个爬虫项目编写案例,比如博客类爬虫项目案例、图片类爬虫项目案例、模拟登录爬虫项目等。除此之外,还有很多不同种类的爬虫案例,可以让大家在理解这些案例之后学会各种类型爬虫的编写方法。

    总之,在理解本书内容并掌握书中实例之后,读者将能胜任 Python 网络爬虫工程师方向的工作并学会各种类型网络爬虫项目的编写。此外,本书对于大数据或数据挖掘方向的从业者也非常有帮助,比如可以利用 Python 网络爬虫轻松获取所需的数据信息等。

    本书面向的读者

    • Python 网络爬虫初学者

    • 网络爬虫工程师

    • 大数据及数据挖掘工程师

    • 高校计算机专业的学生

    • 其他对 Python 或网络爬虫感兴趣的人员

    如何阅读本书

    本书分为四篇,共计20章。

    第一篇为理论基础篇(第1~2章),主要介绍了网络爬虫的基础知识,让大家从零开始对网络爬虫有一个比较清晰的认识。

    第二篇为核心技术篇(第3~9章),详细介绍了网络爬虫实现的核心技术,包括网络爬虫的工作原理、如何用 Urllib 库编写网络爬虫、爬虫的异常处理、正则表达式、爬虫中 Cookie 的使用、手写糗事百科爬虫、手写链接爬虫、手写微信爬虫、手写多线程爬虫、浏览器伪装技术、Python 网络爬虫的定向爬取技术及实例等。学完这一部分内容,读者就可以写出自己的爬虫了。这部分的爬虫编写采用的是一步步纯手写的方式进行的,没有采用框架。

    第三篇为框架实现篇(第10~17章),主要详细介绍了如何用框架实现 Python 网络爬虫项目。使用框架实现 Python 网络爬虫项目相较于手写方式更加便捷,主要包括 Python 爬虫框架分类、Scrapy 框架在各系统中的安装以及如何避免各种“坑”、如何用 Scrapy 框架编写爬虫项目、Scrapy 框架架构详解、Scrapy 的中文输出与存储、在 Scrapy 中如何使用 for 循环实现自动网页爬虫、如何通过 CrawlSpider 实现自动网页爬虫、如何将爬取的内容写进数据库等。其中第12章为基础部分,读者需要着重掌握。

    第四篇为项目实战篇(第18~20章),分别讲述了博客类爬虫项目、图片类爬虫项目、模拟登录爬虫项目的编程及实现。其中,也会涉及验证码处理等方面的难点知识,帮助读者通过实际的项目掌握网络爬虫项目的编写。

    勘误和支持

    由于作者的水平有限,书中难免有一些错误或不准确的地方,恳请各位读者不吝指正。

    相关建议各位可以通过微博@韦玮pig 或通过 QQ 公众号 a67899 或微信公众平台 weijc7789(可以直接扫描下方二维码添加)进行反馈,也可以直接向邮箱 ceo@iqianyue.com 发送邮件,期待能够收到各位读者的意见和建议,欢迎来信。

    扫描关注 QQ 公众号

    扫描关注微信公众号

    致谢

    感谢机械工业出版社华章公司的副总编杨福川老师与编辑李艺老师,在近一年的时间里,是你们一次次在我遇到困难的时候,给予我鼓励,让我可以坚持写下去。创作一本图书是非常艰苦的,除了技术知识等因素之外,还需要非常大的毅力。特别感谢杨福川在写作过程中对我各方面的支持,尤其是对我毅力的培养。

    感谢 CSDN、51CTO 与极客学院,因为你们,让我在这个领域获得了更多的学员与支持。

    感谢恩师何云景教授对我创业方面的帮助,因为有您,我才拥有了一个更好的创业开端及工作环境。

    特别致谢

    最后,需要特别感谢的是我的女友,因为编写这本书,少了很多陪你的时间,感谢你的不离不弃与理解包容。希望未来可以加倍弥补你那些错过吃的美食和那些错过逛的街道。

    同时,也要感谢你帮我完成书稿的校对工作,谢谢你的付出与支持。因为有了你默默的付出,我才能坚定地走下去;因为有了你不断的支持,我才可以安心地往前冲。

    感谢爷爷从小对我人生观、价值观的培养,您是一个非常有思想的人。

    感谢远方的父母、叔叔、姐姐,那些亲情的陪伴是我最珍贵的财富。

    谨以此书献给热爱 Python 的朋友们!

    第一篇 理论基础篇
    • 第1章 什么是网络爬虫

    • 第2章 网络爬虫技能总览

    网络爬虫也叫做网络机器人,可以代替人们自动地在互联网中进行数据信息的采集与整理。在大数据时代,信息的采集是一项重要的工作,如果单纯靠人力进行信息采集,不仅低效繁琐,搜集的成本也会提高。此时,我们可以使用网络爬虫对数据信息进行自动采集,比如应用于搜索引擎中对站点进行爬取收录,应用于数据分析与挖掘中对数据进行采集,应用于金融分析中对金融数据进行采集,除此之外,还可以将网络爬虫应用于舆情监测与分析、目标客户数据的收集等各个领域。当然,要学习网络爬虫开发,首先需要认识网络爬虫,在本篇中,我们将带领大家一起认识几种典型的网络爬虫,并了解网络爬虫的各项常见功能。

    第1章 什么是网络爬虫

    随着大数据时代的来临,网络爬虫在互联网中的地位将越来越重要。互联网中的数据是海量的,如何自动高效地获取互联网中我们感兴趣的信息并为我们所用是一个重要的问题,而爬虫技术就是为了解决这些问题而生的。我们感兴趣的信息分为不同的类型:如果只是做搜索引擎,那么感兴趣的信息就是互联网中尽可能多的高质量网页;如果要获取某一垂直领域的数据或者有明确的检索需求,那么感兴趣的信息就是根据我们的检索和需求所定位的这些信息,此时,需要过滤掉一些无用信息。前者我们称为通用网络爬虫,后者我们称为聚焦网络爬虫。

    1.1 初识网络爬虫

    网络爬虫又称网络蜘蛛、网络蚂蚁、网络机器人等,可以自动化浏览网络中的信息,当然浏览信息的时候需要按照我们制定的规则进行,这些规则我们称之为网络爬虫算法。使用 Python 可以很方便地编写出爬虫程序,进行互联网信息的自动化检索。

    搜索引擎离不开爬虫,比如百度搜索引擎的爬虫叫作百度蜘蛛(Baiduspider)。百度蜘蛛每天会在海量的互联网信息中进行爬取,爬取优质信息并收录,当用户在百度搜索引擎上检索对应关键词时,百度将对关键词进行分析处理,从收录的网页中找出相关网页,按照一定的排名规则进行排序并将结果展现给用户。在这个过程中,百度蜘蛛起到了至关重要的作用。那么,如何覆盖互联网中更多的优质网页?又如何筛选这些重复的页面?这些都是由百度蜘蛛爬虫的算法决定的。采用不同的算法,爬虫的运行效率会不同,爬取结果也会有所差异。所以,我们在研究爬虫的时候,不仅要了解爬虫如何实现,还需要知道一些常见爬虫的算法,如果有必要,我们还需要自己去制定相应的算法,这些在后面都会为大家详细地讲解,在此,我们仅需要对爬虫的概念有一个基本的了解。

    除了百度搜索引擎离不开爬虫以外,其他搜索引擎也离不开爬虫,它们也拥有自己的爬虫。比如360的爬虫叫 360Spider,搜狗的爬虫叫 Sogouspider,必应的爬虫叫 Bingbot。

    如果想自己实现一款小型的搜索引擎,我们也可以编写出自己的爬虫去实现,当然,虽然可能在性能或者算法上比不上主流的搜索引擎,但是个性化的程度会非常高,并且也有利于我们更深层次地理解搜索引擎内部的工作原理。

    大数据时代也离不开爬虫,比如在进行大数据分析或数据挖掘时,我们可以去一些比较大型的官方站点下载数据源。但这些数据源比较有限,那么如何才能获取更多更高质量的数据源呢?此时,我们可以编写自己的爬虫程序,从互联网中进行数据信息的获取。所以在未来,爬虫的地位会越来越重要。

    1.2 为什么要学网络爬虫

    在上一节中,我们初步认识了网络爬虫,但是为什么要学习网络爬虫呢?要知道,只有清晰地知道我们的学习目的,才能够更好地学习这一项知识,所以在这一节中,我们将会为大家分析一下学习网络爬虫的原因。

    当然,不同的人学习爬虫,可能目的有所不同,在此,我们总结了4种常见的学习爬虫的原因。

    1)学习爬虫,可以私人订制一个搜索引擎,并且可以对搜索引擎的数据采集工作原理进行更深层次地理解。

    有的朋友希望能够深层次地了解搜索引擎的爬虫工作原理,或者希望自己能够开发出一款私人搜索引擎,那么此时,学习爬虫是非常有必要的。简单来说,我们学会了爬虫编写之后,就可以利用爬虫自动地采集互联网中的信息,采集回来后进行相应的存储或处理,在需要检索某些信息的时候,只需在采集回来的信息中进行检索,即实现了私人的搜索引擎。当然,信息怎么爬取、怎么存储、怎么进行分词、怎么进行相关性计算等,都是需要我们进行设计的,爬虫技术主要解决信息爬取的问题。

    2)大数据时代,要进行数据分析,首先要有数据源,而学习爬虫,可以让我们获取更多的数据源,并且这些数据源可以按我们的目的进行采集,去掉很多无关数据。

    在进行大数据分析或者进行数据挖掘的时候,数据源可以从某些提供数据统计的网站获得,也可以从某些文献或内部资料中获得,但是这些获得数据的方式,有时很难满足我们对数据的需求,而手动从互联网中去寻找这些数据,则耗费的精力过大。此时就可以利用爬虫技术,自动地从互联网中获取我们感兴趣的数据内容,并将这些数据内容爬取回来,作为我们的数据源,从而进行更深层次的数据分析,并获得更多有价值的信息。

    3)对于很多 SEO 从业者来说,学习爬虫,可以更深层次地理解搜索引擎爬虫的工作原理,从而可以更好地进行搜索引擎优化。

    既然是搜索引擎优化,那么就必须要对搜索引擎的工作原理非常清楚,同时也需要掌握搜索引擎爬虫的工作原理,这样在进行搜索引擎优化时,才能知己知彼,百战不殆。

    4)从就业的角度来说,爬虫工程师目前来说属于紧缺人才,并且薪资待遇普遍较高,所以,深层次地掌握这门技术,对于就业来说,是非常有利的。

    有些朋友学习爬虫可能为了就业或者跳槽。从这个角度来说,爬虫工程师方向是不错的选择之一,因为目前爬虫工程师的需求越来越大,而能够胜任这方面岗位的人员较少,所以属于一个比较紧缺的职业方向,并且随着大数据时代的来临,爬虫技术的应用将越来越广泛,在未来会拥有很好的发展空间。

    除了以上为大家总结的4种常见的学习爬虫的原因外,可能你还有一些其他学习爬虫的原因,总之,不管是什么原因,理清自己学习的目的,就可以更好地去研究一门知识技术,并坚持下来。

    1.3 网络爬虫的组成

    接下来,我们将介绍网络爬虫的组成。网络爬虫由控制节点、爬虫节点、资源库构成。

    图1-1所示是网络爬虫的控制节点和爬虫节点的结构关系。

    图1-1 网络爬虫的控制节点和爬虫节点的结构关系

    可以看到,网络爬虫中可以有多个控制节点,每个控制节点下可以有多个爬虫节点,控制节点之间可以互相通信,同时,控制节点和其下的各爬虫节点之间也可以进行互相通信,属于同一个控制节点下的各爬虫节点间,亦可以互相通信。

    控制节点,也叫作爬虫的中央控制器,主要负责根据 URL 地址分配线程,并调用爬虫节点进行具体的爬行。

    爬虫节点会按照相关的算法,对网页进行具体的爬行,主要包括下载网页以及对网页的文本进行处理,爬行后,会将对应的爬行结果存储到对应的资源库中。

    1.4 网络爬虫的类型

    现在我们已经基本了解了网络爬虫的组成,那么网络爬虫具体有哪些类型呢?

    网络爬虫按照实现的技术和结构可以分为通用网络爬虫、聚焦网络爬虫、增量式网络爬虫、深层网络爬虫等类型。在实际的网络爬虫中,通常是这几类爬虫的组合体。

    首先我们为大家介绍通用网络爬虫(General Purpose Web Crawler)。通用网络爬虫又叫作全网爬虫,顾名思义,通用网络爬虫爬取的目标资源在全互联网中。通用网络爬虫所爬取的目标数据是巨大的,并且爬行的范围也是非常大的,正是由于其爬取的数据是海量数据,故而对于这类爬虫来说,其爬取的性能要求是非常高的。这种网络爬虫主要应用于大型搜索引擎中,有非常高的应用价值。

    通用网络爬虫主要由初始 URL 集合、URL 队列、页面爬行模块、页面分析模块、页面数据库、链接过滤模块等构成。通用网络爬虫在爬行的时候会采取一定的爬行策略,主要有深度优先爬行策略和广度优先爬行策略。具体的爬行策略,我们将在第3章讲解,在此,我们只需要知道通用网络爬虫的基本构成和主要的爬行策略。

    聚焦网络爬虫(Focused Crawler)也叫主题网络爬虫,顾名思义,聚焦网络爬虫是按照预先定义好的主题有选择地进行网页爬取的一种爬虫,聚焦网络爬虫不像通用网络爬虫一样将目标资源定位在全互联网中,而是将爬取的目标网页定位在与主题相关的页面中,此时,可以大大节省爬虫爬取时所需的带宽资源和服务器资源。聚焦网络爬虫主要应用在对特定信息的爬取中,主要为某一类特定的人群提供服务。

    聚焦网络爬虫主要由初始 URL 集合、URL 队列、页面爬行模块、页面分析模块、页面数据库、链接过滤模块、内容评价模块、链接评价模块等构成。内容评价模块可以评价内容的重要性,同理,链接评价模块也可以评价出链接的重要性,然后根据链接和内容的重要性,可以确定哪些页面优先访问。聚焦网络爬虫的爬行策略主要有4种,即基于内容评价的爬行策略、基于链接评价的爬行策略、基于增强学习的爬行策略和基于语境图的爬行策略。关于聚焦网络爬虫具体的爬行策略,我们将在1.5节进行详细分析。

    增量式网络爬虫(Incremental Web Crawler),所谓增量式,对应着增量式更新。增量式更新指的是在更新的时候只更新改变的地方,而未改变的地方则不更新,所以增量式网络爬虫,在爬取网页的时候,只爬取内容发生变化的网页或者新产生的网页,对于未发生内容变化的网页,则不会爬取。增量式网络爬虫在一定程度上能够保证所爬取的页面,尽可能是新页面。

    深层网络爬虫(Deep Web Crawler),可以爬取互联网中的深层页面,在此我们首先需要了解深层页面的概念。

    在互联网中,网页按存在方式分类,可以分为表层页面和深层页面。所谓的表层页面,指的是不需要提交表单,使用静态的链接就能够到达的静态页面;而深层页面则隐藏在表单后面,不能通过静态链接直接获取,是需要提交一定的关键词之后才能够获取得到的页面。在互联网中,深层页面的数量往往比表层页面的数量要多很多,故而,我们需要想办法爬取深层页面。

    爬取深层页面,需要想办法自动填写好对应表单,所以,深层网络爬虫最重要的部分即为表单填写部分。

    深层网络爬虫主要由 URL 列表、LVS 列表(LVS 指的是标签/数值集合,即填充表单的数据源)、爬行控制器、解析器、LVS 控制器、表单分析器、表单处理器、响应分析器等部分构成。

    深层网络爬虫表单的填写有两种类型:第一种是基于领域知识的表单填写,简单来说就是建立一个填写表单的关键词库,在需要填写的时候,根据语义分析选择对应的关键词进行填写;第二种是基于网页结构分析的表单填写,简单来说,这种填写方式一般是领域知识有限的情况下使用,这种方式会根据网页结构进行分析,并自动地进行表单填写。

    以上,为大家介绍了网络爬虫中常见的几种类型,希望读者能够对网络爬虫的分类有一个基本的了解。

    1.5 爬虫扩展——聚焦爬虫

    由于聚焦爬虫可以按对应的主题有目的地进行爬取,并且可以节省大量的服务器资源和带宽资源,具有很强的实用性,所以在此,我们将对聚焦爬虫进行详细讲解。图1-2所示为聚焦爬虫运行的流程,熟悉该流程后,我们可以更清晰地知道聚焦爬虫的工作原理和过程。

    首先,聚焦爬虫拥有一个控制中心,该控制中心负责对整个爬虫系统进行管理和监控,主要包括控制用户交互、初始化爬行器、确定主题、协调各模块之间的工作、控制爬行过程等方面。

    然后,将初始的 URL 集合传递给 URL 队列,页面爬行模块会从 URL 队列中读取第一批 URL 列表,然后根据这些 URL 地址从互联网中进行相应的页面爬取。爬取后,将爬取到的内容传到页面数据库中存储,同时,在爬行过程中,会爬取到一些新的 URL,此时,需要根据我们所定的主题使用链接过滤模块过滤掉无关链接,再将剩下来的 URL 链接根据主题使用链接评价模块或内容评价模块进行优先级的排序。完成后,将新的 URL 地址传递到 URL 队列中,供页面爬行模块使用。另一方面,将页面爬取并存放到页面数据库后,需要根据主题使用页面分析模块对爬取到的页面进行页面分析处理,并根据处理结果建立索引数据库,用户检索对应信息时,可以从索引数据库中进行相应的检索,并得到对应的结果。

    图1-2 聚焦爬虫运行的流程

    这就是聚焦爬虫的主要工作流程,了解聚焦爬虫的主要工作流程有助于我们编写聚焦爬虫,使编写的思路更加清晰。

    1.6 小结

    1)网络爬虫也叫作网络蜘蛛、网络蚂蚁、网络机器人等,可以自动地浏览网络中的信息,当然浏览信息的时候需要按照我们制定的规则去浏览,这些规则我们将其称为网络爬虫算法。使用 Python 可以很方便地编写出爬虫程序,进行互联网信息的自动化检索。

    2)学习爬虫,可以:①私人订制一个搜索引擎,并且可以对搜索引擎的数据采集工作原理,进行更深层次地理解;②为大数据分析提供更多高质量的数据源;③更好地研究搜索引擎优化;④解决就业或跳槽的问题。

    3)网络爬虫由控制节点、爬虫节点、资源库构成。

    4)网络爬虫按照实现的技术和结构可以分为通用网络爬虫、聚焦网络爬虫、增量式网络爬虫、深层网络爬虫等类型。在实际的网络爬虫中,通常是这几类爬虫的组合体。

    5)聚焦网络爬虫主要由初始 URL 集合、URL 队列、页面爬行模块、页面分析模块、页面数据库、链接过滤模块、内容评价模块、链接评价模块等构成。

    第2章 网络爬虫技能总览
    第二篇 核心技术篇
    第3章 网络爬虫实现原理与实现技术(上)
    第3章 网络爬虫实现原理与实现技术(下)
    第4章 Urllib 库与 URLError 异常处理(上)
    第4章 Urllib 库与 URLError 异常处理(下)
    第5章 正则表达式与 Cookie 的使用(上)
    第5章 正则表达式与 Cookie 的使用(下)
    第6章 手写 Python 爬虫(上)
    第6章 手写 Python 爬虫(下)
    第7章 学会使用 Fiddler (上)
    第7章 学会使用 Fiddler (下)
    第8章 爬虫的浏览器伪装技术
    第9章 爬虫的定向爬取技术
    第三篇 框架实现篇
    第10章 了解 Python 爬虫框架
    第11章 爬虫利器——Scrapy 安装与配置
    第12章 开启 Scrapy 爬虫项目之旅(上)
    第12章 开启 Scrapy 爬虫项目之旅(中)
    第12章 开启 Scrapy 爬虫项目之旅(下)
    第13章 Scrapy 核心架构
    第14章 Scrapy 中文输出与存储
    第15章 编写自动爬取网页的爬虫
    第16章 CrawlSpider
    第17章 Scrapy 高级应用
    第四篇 项目实战篇
    第18章 博客类爬虫项目
    第19章 图片类爬虫项目
    第20章 模拟登录爬虫项目

    阅读全文: http://gitbook.cn/gitchat/geekbook/5b7103e3dcc9492d208237a8

    展开全文
  • 这是一款以生产质量为核心的XX建筑材料有限公司引进美国聚氨酯生产技术,安全生产、质量生产成为了XX建筑...该文档为XX建筑材料有限公司引进美国聚氨酯生产技术,是一份很不错的参考资料,具有较高参考价值,感兴趣...
  • 当你是从百度或google搜索 关键词"ASP.NET核心技术",".NET核心技术"过来的话,我很想鄙视你一下,真的,因为我遇到太多的这样的人了,"ASP.NET核心技术",".NET核心技术"这样的问题真的没必要问,有意思吗,基础弄懂了吗...

       当你是从百度或google搜索 关键词"ASP.NET核心技术",".NET核心技术"过来的话,我很想鄙视你一下,真的,因为我遇到太多的这样的人了,"ASP.NET核心技术",".NET核心技术"这样的问题真的没必要问,有意思吗,基础弄懂了吗,精通了asp.net吗,还不如问问"ASP.NET基础是什么",基础都没有弄懂,就一天到晚在那追求核心是什么,这些在我看来不是问出来的,当你用ASP.NET开发有几年经验,然后有自己的建树后,你就会知道,这些当年问得问题是多么的傻,原来当初是一个不想去弄清事情,却想别人一口給个权威答案的懒惰者,居然你进来了,我也不想让你空手而归,于是給篇文章,学习下,希望能从基础学起,打牢基础了,你会看到核心是什么的,以上仅仅是个人看法.下面文章,我们一起看看.net技术吧!

    文章:

          不可否认,应用软件的开发正在经历一次巨变——将最终增强开发人员的生产力并开启一道通向全新概念的应用程序的大门。

      新型的开发模式正逐渐被推广,将分发软件演变成一种服务还有待于所有开发人员的共同努力,而互联网却将彻底改变应用程序的开发模式和配置方式。

      传统上,软件开发人员通过集成本地系统服务的方式开发应用程序。这种模型使开发人员有权使用一整套丰富的开发资源,精确控制应用程序的性能。

      如今,开发人员在很大程度上已挣脱了这种模式的束缚,致力于构建具有复杂结构的n层系统,这种系统能将网络中各处的众多的应用程序进行集成,并大大提升应用程序的价值。这样,开发人员便可集中精力挖掘软件独特的商业价值,而不必日夜为如何构建基本结构伤脑筋了。令人欣喜的局面将应运而生:软件投放市场的时间大大缩短、开发人员的编程效率明显提高,最为根本的是开发出质量上乘的软件。

      我们正在进入计算机发展的下一个阶段——基于Internet的阶段,特别是基于Internet核心技术——XML扩充标记语言。尽管多层应用程序开发将焦点集中在建造大型企业级应用程序上,但现在XML使得能够创建可用于任何人、任何场所的大型应用程序。它扩大了应用程序的使用范围。这样,软件就不是只能从CD上安装的某种东西,而是一种服务——就像呼叫服务或者计费电视一样,可以通过通信媒体来预订。

      这一切,是通过将紧密联接的、高效的n层计算技术与面向消息的、松散联接的Web概念相结合来实现的。我们将这种计算风格称为Web Service(Web服务),它的出现标志着人类已经迈入应用程序开发技术的新纪元。Web服务是一种应用程序,它可以使用标准的互联网协议,像超文本传输协议(HTTP)和XML,将功能纲领性地体现在互联网和企业内部网上。

      我们也可将Web服务视作Web上的组件编程。

      从理论上讲,开发人员通过调用Web应用编程接口(API),将Web服务集成进他们的应用程序,就像调用本地服务一样。两者区别在于前者能够通过Internet发送到某个远程系统的服务上。例如,像微软护照(Microsoft Passport)这样的服务,可以给开发人员提供应用程序身份确认的功能。通过对护照服务编程,开发人员就可以利用护照服务的基础体系,实现维护用户数据库,确信服务开启和运行以及正确地备份等等功能。

      ■松散联接

      跨越网络的分布应用程序逻辑的概念并不是一个新名词,但跨越Web的分布和集成应用程序逻辑的概念却是。

      此前,像微软的DCOM (Distributed Component Object Model )、Object Management Group公司的CORBA (Common Object Request Broker Architecture )以及Sun公司的RMI(Remote Method Invocation )这些分布式对象模型被称为分布应用程序逻辑。运用这些系统结构,虽然服务放在远程系统上,开发人员仍然可以像原来本机编程那样维护和丰富应用程序的功能。

      但这种系统的问题是不能扩展到Internet。因为该体系的基础是服务器上的客户端和服务器的紧密联结。这意味着两者必须是同质的基础体系,但也就常常意味着这种系统是非常脆弱的,如果有任何一端接口发生变化,另一端程序必然就会被中断。举个例子,如果服务器应用程序的接口改变了,那么客户端也将会失效。

      开发中要求有一个紧密联接的系统这本身没有错,而且许多应用程序也一直就是建立在这些系统上的。但最终,随着时间的流逝,这种模型是不会扩展的。因为众多公司企业要求相互沟通,这很难保证会有一个统一的系统,同样也很难保证,你的客户的服务器会有你所需要的完全一致的系统,你甚至都不可能猜想到它所用的是什么操作系统、什么对象模型和什么编程语言。

      相反,Web服务的联接非常松散。这就意味者你可以在联接的任何一端任意改变接口,而应用程序可以不受影响地照常工作。从技术上说,这主要是由于使用了拥有稳固性能的基于消息的异步技术,如像HTTP、SMTP等Web标准协议。而且最重要的是,XML可以帮助实现其通用性。

      作为一个宏伟的计划,.NET的路还很长。今后的发展无论是崎岖坎坷还是一片光明,在对新技术和IT产业的推动上,微软都是功不可没的。

      消息系统将通信的基本单元打包进自描述的、运用于网络通信层的包(被称做消息)。消息系统和分布式对象系统的关键区别在于,发送者需要对接收者的系统了解多少。使用分布式的对象系统,发送者需要帮助接收者考虑许多问题,比如应用程序将如何激活和卸载、调用的是什么接口等等。

      另一方面,消息系统在通讯层上达成协议。发送者只需考虑的是接收者能够知道信息正被发送。发送方不需要了解一旦消息被收到后将会如何处理,也不需要对发送方和接收方之间作任何考虑。

      在通讯层上达成协议的优势是显而易见的。例如,协议能够使接收方随时作修改而无须中断发送方,只要该协议始终明白是同一条消息。接收方不用中断任何当前应用程序,可以自由升级和改进。更进一步说,就是发送方不用要求任何特殊的软件就可以和接收方交谈,只要他发送的是符合格式的信息,接收方就可以作出应答。

       ■XML的通讯基础:SOAP

      建造跨越Web的 Web服务的工作和异步系统的关键是使用统一的数据说明格式,这就是XML。特别说明的是,Web服务器在三方面需要XML来实现:基础语言、服务说明以及服务发现。

      ● SOAP:系统在底层需要有统一语言,特别地,应用程序相互通讯需要建立一套规则来说明如何表示不同数据类型(如整数和数组),如何表示命令(如进行数据处理)。同时,应用程序在需要时还可以扩充这种语言。简单对象存取协议SOAP(Simple Object Access Protocol),这是XML的一种实现,代表了一组如何表示和扩充数据和命令的规则集。

      ● WDSL(Web Services描述语言) :一旦应用程序有了如何表述数据和命令的基本规则,他们就需要如何描述可以接收的特定数据和命令。应用程序只是声明如何接收整数是不够的,他们必须用明确的方法声明。如给你两个整数,把它们相乘。WDSL是一种XML语法,开发人员和开发工具可以用它来表示Web服务的功能。

      ● SOAP Discovery:最后需要一组规则来定位服务的描述——对于开发者和开发工具在什么地方可以发现一个Web服务。SOAP Discovery规范提供了一组规则让开发者和开发工具可以自动发现Web服务的描述。

      一旦这些准备好了,开发者可以方便地发现Web 服务,把它作为一个对象集成进他们的应用程序,并使应用程序和Web服务相互通讯。

       ■.NET框架:Web服务引擎

      很显然,许多基本结构都需实现上述进程对开发人员和用户的透明化。.NET框架(.NET Framework)提供此基本结构。从.NET框架角度看,所有组件都可以是Web服务,而Web服务也仅是一种组件。实际上,.NET框架提取出微软组件对象模型(COM)的精华,将它们与松散联接计算的精华有机地结合在一起,生成了强大、高效的Web组件系统:简化程序员的“管道”操作,深入地集成了安全性,引进了基于互联网的操作系统,极大地改善应用程序的可靠性和可扩展性。

      .NET框架由三个主要部分组成:通用语言运行库、一套层次结构的统一类库和一个被称为ASP+的高级ASP版本。

      有关.NET的许多东西让人印象深刻,尤其是微软充分传达出的对互联网作为未来主要技术平台的首肯,和在某些方面对公开的标准的欢迎。

      .NET的确牵动着每个人的猜测……

      1.通用语言运行库

      除了通用语言运行库的字面含义外,在开发阶段和运行过程中它还扮演着另一个角色。在组件运行时,运行库负责管理内存分配、启动和中止线程和进程、强化安全系数,同时还调整任何该组件涉及到的其他组件的附件配置。在开发阶段,运行库的角色稍微有点变化:因为很多方面可以自动实现(例如内存管理等)。运行库可以使开发过程变得非常简单,特别是同今天的COM编程相比更是如此。特别典型的是,像Reflection这样的特性可以极大地缩小开发人员将商业逻辑转化成一个可重复使用的组件而不得不编写的代码数量。

      运行库对于编程语言来说并不是新鲜的东西。实际上每一种编程语言都已包含一个运行库。Visual Basic开发系统有最明显的运行库(正规名字为VBRUN),Visual C++也有一个MSVCRT,此外,像Visual FoxPro、Jscript、SmallTalk、Perl、Python和Java等等都如此。.NET框架的关键角色就是它提供了一个跨所有编程语言的统一环境。

      2.统一编程类

      .NET框架类为开发人员提供了一套可以使用的统一的面向对象、异步、层次结构的可扩展类库。现在,C++的使用者使用Microsoft Foundation Classes,Java程序员使用Windows Foundation Classes,Visual Basic的用户使用Visual Basic APIs。微软用.NET框架统一了这些不同的框架。结果是,开发人员不用非去学多个框架来完成自己的工作。而且,通过创建一套跨编程语言的通用API,.NET框架可以实现跨语言继承、纠错处理以及程序调试。实际上,从JScript 到C++的所有编程语言,对于.Net框架都是相互等同的,开发人员可以自由地选择他们想使用的任何语言。

      .NET是一种全新的平台,它将对现有的所有代码产生影响。盖茨说:“微软所有的产品都会被涉及。我们的整个战略是围绕这个平台展开的。”

      3.ASP+

      ASP+是使用 .NET框架提供的类库构建而成的,它提供了一个Web应用程序模型,该模型由一组控件和一个基本结构组成。有了它,Web应用程序的构建变得非常容易。开发人员可以直接使用ASP+控件集,该控件集封装了公共的、用于超文本标识语言(HTML)用户界面的各种小组件(诸如文本框、下拉选单等等)。实际上,这些控件运行在Web服务器上,它们将用户界面转换成HTML格式后再发送给浏览器。在服务器上,控件负责将面向对象的编程模型呈现给Web开发人员,这种编程模型能提供面向对象的编程技术拥有的丰富功能。ASP+还提供一些基本结构服务(诸如会话状态管理和进程循环),这些服务进一步减少了开发人员要编写的代码量,并使应用程序的可靠性得到了大幅度提高。ASP+还允许开发人员将软件作为一项服务进行传送。通过使用ASP+ Web服务功能,ASP+开发人员只需进行简单的业务逻辑编程,而由ASP+基本结构负责通过SOAP传送服务。

      尽管ASP+还未正式发行,但它已在改进应用程序功能方面创造出了令人难以置信的奇迹:在现有基于ASP的应用程序性能基础上,性能优化了三倍之多,更为激动人心的是生产效率再度攀升。

       ■.NET框架的核心部分

      .NET框架有几个要素值得一提。首先是它的安全系统和配置系统。这两个系统协同工作,有力地遏止了运行不安全代码的可能性,并大幅度减少了号称“DLL Hell”的对应用程序进行配置时所面临的挑战。

      安全系统是一个高度细化、基于事实的系统,它赋予开发人员和管理员多种代码处理权限(而不仅仅是“on”或“off”)。将来,还会根据代码本身的核心要素来决定如何实施上述权限。

      例如,当.NET框架应用程序被下载到某一系统中时,它会申请一组权限(诸如对临时目录的写入权限)。运行时将收集有关应用程序的事实信息(诸如:它是从何处下载的、是否用了有效签名、甚至它访问系统的准确程度),并按管理策略决定是否允许应用程序运行。运行时甚至还可告之应用程序它无法授权申请的所有权限,并允许应用程序自行决定是否继续运行。

      有这种安全系统作保障,许多应用程序配置问题便会迎刃而解。开发人员和管理员(最终是用户)所面临的最大挑战之一是版本的管理问题。如果在您新装了某个应用程序之后,一切都陷于瘫痪状态,而在这之前系统一直运行得非常良好,那么最大的可能是新安装的应用程序重写了一些共享库,并极有可能修正了现有应用程序正使用的程序错误。这种情况出现的频率很高,以致人们将它称为:“DLL Hell”。

      .NET框架拥有的几项高级功能可以彻底消除“DLL Hell”现象。首先,它有一个非常强大的内部命名系统,能够有效地防止两个库因互相重名而被错当为对方的情况发生。除此之外,它还提供一项被称作“side by side”配置的新功能。如果前例中新安装的应用程序确实重写了共享库,现有应用程序可对该库进行修复。等现有应用程序再次启动时,它会检查所有的共享文件。如果发现文件被更改,同时这些更改又是不兼容的,则它可以请求运行时提取一个它可以使用的版本。得益于强大的安全系统,运行时可以安全地执行该操作,这样应用程序就完成了本身的修复工作。

       ■编者语

      人们总是喜欢不厌其烦地发表诸如“互联网改变了一切”的陈词。同样地,在谈论互联网给人类带来的影响时,总是情不自禁地使用广告式的夸张语,以表达对互联网的推崇。不过,互联网的确彻底改变了应用程序的开发模式和配置方式。将分发软件演变成一种服务还有待人们的共同努力,XML是实现这个梦想的重要手段。.NET框架是微软开发人员战略的核心内容,它旨在帮助开发人员轻松地构建、配置和运行Web服务。

      总之,.NET的最先受益者,将是我们的开发人员。.NET的路还很长,今后的发展无论是崎岖坎坷还是一片光明,在对新技术和IT产业的推动上,微软都是功不可没的。

    展开全文
  • 引进BigTable GFS(2003年发表)使用商用硬件集群存储海量数据。文件系统将数据在节点之间冗余复制。MapReduce(2004)是GFS架构的一个补充,因为它能够充分利用GFS集群中所有低价服务器提供的大量CPU 但是两个系统...
  • 此时,国内银行建设核心业务系统面临两种选择:一是自主开发,二是整体引进。承载着打造“后发优势”及快速与国际接轨的梦想与希望,国内一些银行纷纷走上整体引进之路。 然而,在具体实施过程中,“引进一套国外...
             我国银行信息化经过前些年“数据大集中”的初步准备,目前,正在进入一个全新的“应用系统整合”阶段。在整合过程中,建设核心业务系统成为一个新热点。此时,国内银行建设核心业务系统面临两种选择:一是自主开发,二是整体引进。承载着打造“后发优势”及快速与国际接轨的梦想与希望,国内一些银行纷纷走上整体引进之路。 然而,在具体实施过程中,“引进一套国外系统,复制一家一流银行”似乎只是一种理想化的设想。实施国外核心业务系统项目后,国内银行往往投入大量资源,花费大量时间,项目实施计划一改再改,上线时间一推再推,系统却还是不能投入生产。有些银行经过一到两年的探索和尝试,最终还是放弃了国外产品,掉过头来转向国内IT厂商提供的软件。
    
            将国外系统移植到我国银行现有的生产关系环境中,“空气、阳光、土壤、水份”等都大为不同,如果系统的灵活性和适应性不强,结出的果子自然亦非当初所设想的样子。是南橘北枳,中国的银行完全不适于采用国外的系统?或仅仅是水土不服,只要经过本地化、客户化的改造后,国外系统还是能发挥其应有的效应?业内外人士都在密切关注——国外银行核心业务系统在中国实施本地化和客户化的难点究竟在哪里?
             引进国外银行核心业务系统产品,购买只是简单的第一步,如果不经过大量的本地化和客户化工作,系统根本无法发挥其功效。不同类型的国外软件在本地化和客户化过程中会遇到不同的问题。纯技术类软件主要面临技术问题,管理类软件除了技术问题外,更大的困难是文化、体制的差异。整体引进国外银行核心业务系统,虽然遇到很多技术问题,但根本原因还是在于国内外监管环境和体制流程方面的巨大差异。
             国外核心业务系统本地化和客户化是一项复杂的系统工程,很多人存在这样一个认识误区,认为软件本地化就是软件翻译,软件客户化就是按照客户需求加以修改。实际上,软件本地化是将一个软件产品按特定国家、地区或语言市场的需要进行加工,使之满足特定市场上的用户对语言和文化的特殊要求的软件生产活动;软件客户化是指在分析用户需求与产品差异的基础上,在满足客户需求和保证系统结构稳定的前提下,对软件进行的一系列开发、测试活动。因此,国外软件本地化是一项复杂的系统工程,不是一个简单的从外语到中文的翻译过程;客户化也不单单是按照客户需求去修改系统,否则就失去了购买成型产品的意义。
          国外银行核心业务系统在中国的本地化,主要包括本地化界面、国内环境接口、本地化报表、本地化文档及培训等方面。界面本地化包括:语言的汉化,将系统界面中的画面、菜单、操作符、提示信息等要素用中文进行表示;界面的易使用性,针对国外产品操作界面与国内风格的不同,通过适当修改、简化或进一步细化成一个容易使用的操作界面;用户操作习惯的满足,根据用户在旧系统上形成的较好的操作习惯,实现系统对应内容的差异最小化。
          与国内外环境的接口:包括人民银行现化支付系统、中央国债登记结算公司接口、上海证券登记结算公司接口、外管局国际收 支申报系统、人民币大额和可疑支付交易监测系统、人民币交易系统、结售汇系统、进口品报关单检查和 进口单位名录系统、各种本地数据交换信息接口等。
           本地化报表:国外核心业务系统报表功能高度参数化,因此报表本地化与报表的具体形式关联性并不十分紧密,工作量主要集中在内部数据的采集。
           本地化文档及培训:本地化文档包括用户手册,操作手册、技术手册等;本地化培训,包括详细客户培训、详细设计培训、技术标准培训等。
           国外银行核心业务系统在中国的客户化,主要包括需求差异分析、与内部系统的对接、第三方提供功能的集成等三个方面。需求差异分析是以国内银行现有业务或预期目标为基础,对照国外金融IT产品进行功能性分析,找出差异以及应对策略的过程;与银行内部系统对接要分析清楚现有系统与即将开发的新系统之间的详细关联关系,保证新旧系统平稳衔接;第三方提供功能的集成,是指在保证第三方提供的系统运行正常的基础之上,考虑与核心系统进行集成。这一般是由国外厂商在当地IT公司中选中的一家总集成商来完成。
            国内外银行监管环境的巨大差异增加本地化难度,国外银行核心业务系统模块多、规模大,业务范围涵盖银行业务的方方面面,其本地化和客户化过程对任何国家的任何银行而言,都不亚于一场革命。把它放到我国银行的背景环境之中,矛盾就会更加突出。我国金融市场化程度不高,监管框架、相关法规制度与国际标准还存在较大差异,银行治理结构的缺损、内部经营管理体制的僵化,操作方式落后,这些都加大了核心业务系统本地化和客户化的工作量。监管环境和相关法规是硬约束,为适应国内的财会准则以及人民银行、银监会等监管机构的监管要求,国外的核心业务系统必须做出适当修改。此类差异主要体现在以下几方面:
             国内外利率管制程度不同,系统在国内本地化和客户化时,某种程度上要牺牲系统的先进性。在国外核心业务系统中,利率就象一个魔方,其多维、立体的参数设置和组合,在打通银行及相关混业领域、联贯各产品方面发挥着灵活的作用。在国外发达的金融市场环境中,利率作为最核心、最重要的交易要素主要体现在价格功能。国内现阶段金融市场尚未完全放开,利率很大程度上是金融监管当局的管理工具。按照人民银行的利率管理办法,对于各种类型的存款或贷款,利率要求都不尽一致,特别是针对部分种类的存款和贷款更有特殊的规定。国内监管部门利率规定繁多,利息计算方法复杂,因此产生很多差异。这些差异应该按监管规定进行修改,但考虑到修改量太大会影响其稳定性,需要采取折衷作法。国内外对外汇管制程度的不同,造成核心业务系统本地化和客户化时,系统修改的难度和工作量加大。在外汇管制的背景下,结售汇是我国监管框架下的特殊业务。根据外汇局外汇管理的有关规定,每笔结售汇业务都涉及到:对客户是否在其“名录”中进行真实性的审核;需要对其贸易必备条件进行逐笔、逐级进行审批;还要进行询价、头寸申报、买卖外汇、结算、售汇报表等。国外由于外汇自由兑换,没有哪个模块有类似功能。如果走定制开发模式,可以考虑单独设置结售汇模块。但对国外核心业务系统而言,修改需求介于操作与报表之间,开发起来有一定难度。另外,根据外汇局要求,结售汇报表、大额可疑报表、经常账户报表要直接从业务系统中生成并报送,类似需求对国外系统的改动也很大。
             国外系统要与国内支付系统直联,需要对整个模块做彻底的修改。为实现资金清算的STP(直通式处理),核心业务系统应与现代化支付系统相连接。由于国外系统没有通过国内大额支付系统汇划处理业务的界面,需要按照人行的《中国现代化支付系统与商业银行行内系统接口方案》中规定的报文格式要求,包括支付报文、非支付报文、对账报文等,对系统做大量的改动和测试工作。从稳妥角度考虑,国内银行在建设核心业务系统过程中,一期可以先实现交易驱动账务核算,待系统稳定后再推进清算的直联工作。
           国内外会计管理理念和制度的差异,需要重新构架会计体制,实现会计管理的全面转型。国外核心业务系统的会计核算功能,靠交易驱动来实现系统自动化处理。这既是国外系统直通式处理和参数化灵活配置的优势体现,也是实施过程的难点所在。会计核算不仅要跨越管理理念的差距,而且要把大量的制度创新和方案设计的工作想在前头和做在前头。具体来说,就是对所有业务模块驱动会计核算的核算结果通过制度规范想在前面,对上万个会计参数通过严格的确认和配置做在前面,否则会直接影响系统自动化输出的会计核算的结果。这既要求业务归口部门及早改变传统的会计管理模式,又要组织起银行内部技术资源,扎扎实实地做好系统上线前后的各项准备工作。如果会计核算结果的准确性、效率性及安全性缺乏保障或受到置疑,就会动摇整个核心业务系统的根基。
    展开全文
  • 现阶段,许多公司都在引进新的面向客户的相关产品和服务以改善现有的产品,增加收益并且创造新的收益机会。根据跨国通讯公司沃达丰的M2M晴雨表数据,在已经应用 M2M 技术的企业中,有66%声称他们的战略侧重于外部...
  • 摘要:音视频技术领域的发展方向是数字化、高集成化、多功能化。我国目前应重点研发数字高清晰电视产业化中的关键技术,以此为龙头,带动我国数字音视频技术的发展。有机发光二极管 (OLED)属下一代显示技术,是显示...
  • 中国移动3G核心网SGSN/GGSN技术规范 适用于中国移动通信集团公司WCDMA系统核心技术试验,为设备引进、网络规划与设备制造、工程设计、网络运行、管理和维护等提供技术依据。
  • 美国国家半导体公司 (National Semiconductor Corporation)推出一款内含复杂模拟区段的高...这款集成电路内含全套声频路径 (业界标准数字讯号处理器核心及高效能模拟电路) 以及线路互连模块,其中包括CAN、UART
  • 中国尚未掌控的核心技术有哪些?(附清单) 2018-04-18 07:00 转载来源:鸣金网 综合自:高分子科学前沿、知乎(宋景)、天涯社区 1/A :半导体加工设备 基本被日本,美国霸占,看Intel的最佳供应商就知道...
  • 什么是.Net的核心技术

    千次阅读 2006-09-27 17:10:00
    .NET架构的核心技术■松散联接 跨越网络的分布应用程序逻辑的概念并不是一个新名词,但跨越Web的分布和集成应用程序逻辑的概念却是。 此前,像微软的DCOM (Distributed Component Object Model )、Object ...
  • 引进国外核心业务系统,要从多个角度思考对这些差异的系统处理方案。  内部核算、清算体制的差异。与国内银行实行的总分行多级核算体制不同,国外银行一般实行一级核算体系,对总分行清算资金往来系统只设一个...
  • 注意:公式中阻尼系数d在算法初始阶段是没有的,上述公式中d设置为1此处会发现6的权重为0,就出现了孤立页面,这时候便引进了阻尼系数d,d一般设值为0.85 修改之后公式 (0.15f + x._2._1.get * 0.85f) ,其意义是...
  • 支付清算系统是经济金融活动的基础性支撑。支付、清算体系建设是金融理论与实践的重点课题...同时也让对银行核心感兴趣的企业,多一些对业务和技术上的了解。总有人要做的,那就由愚笨的笔者来抛砖引玉吧!笔者小小的.
  • 中国目前还未掌握的核心技术有哪些? 1、A半导体加工设备 基本被日本,美国霸占,看intel的最佳供应商就知道了。不同的是中国想买有些国外设备,别人不卖。 目前蚀刻设备精度最高的是日立。其实看看英特尔的最佳...
  • 界定自主品牌的两个要素在于:企业是否拥有核心技术及属于这个国家的品牌。但目前自主品牌缺少良好氛围,一是国民观念问题,中国的国民对于自主品牌的观点比较淡,不可能像韩国和日本那样,靠自觉意识来推动国家自主...
  • (农历立春,纽约暴雪,银装素裹,天地苍茫。...这家位于佛罗里达的创业公司已经创业数十年,阵容豪华,规模庞大,但却对其核心技术讳莫如深,异常神秘。间或泄露几条演示视频,举世惊艳,旋即哗然。
  • 工业机器人有三大核心技术其实也就是三大核心零部件的关键技术: 控制器 (控制技术), 减速机 ,机器人专用 伺服电机及其控制技术 。 一线厂家包括 :发那科(Fanuc 日本)、安川(Yaskawa 日本)、ABB(瑞士)、...
  • 《图解基础设施设计模式》适合对基础设施缺乏经验的技术者(也包括应用程序开发者)、负责系统构建的项目经理、在企业的信息系统部门中对系统规划与引进具有决策权的人,以及负责评估和比较供应商提案和设计的人...
  • 倪光南院士在演讲中表示,中兴事件的重要教训是:在引进高新技术上不能抱任何幻想,关键核心技术是要不来、买不来、讨不来的。大国重器一定要掌握在自己手里。 中兴事件充分暴露了目前我们在供应链方面容易被人卡...
  • 我感觉这是有些人为了经济利益,迟迟阻碍引进该书的最新影印版。长此以往,国人的计算机水平只会越来越落后!我打算毕业后创立一个出版社,专门引进最新的各种专业图书,不求赚钱,只求国内的科技发展,坚决抵制各种...
  • 作者简介:曾宇先生,腾讯公司副总裁。 2002 年加入腾讯,曾负责腾讯研发线管理,...正文技术人员的核心素养腾讯的职业发展通道大概有 6 级,1 级是初入者,2 级是有经验者,3 级是骨干,4 级是专家,5 级和 6 级是权
  • 当前,我国的煤炭技术装备制造业在产品技术标准、产品设计理论、核心技术、产品寿命与可靠性、产品制造工艺、工艺研究等方面与国际煤炭技术装备制造业相比,还存在相当显著的差距。因此,通过坚持引进与自主研发相结合...
  • Flink中的一些核心概念

    万次阅读 2016-05-02 22:46:23
    Flink中的一些基础而又关键的核心概念。了解这些概念有助于更进一步理解Flink的设计。
  • 华夏银行新核心系统

    2014-08-14 16:11:34
    有关核心业务系统引进与改造的思辨,也由此进一步走向深入。 两年前,当华夏银行与德意志银行签署《全面长期战略合作协议》,洽谈产品合作时,由于新引进核心业务系统尚未上线,导致双方合作计划出现了一些不谐和...
  • 核心银行系统 之一 历史与发展

    千次阅读 2018-11-29 14:25:21
    核心银行系统是银行信息系统中实现客户关系管理、产品与服务、业务流程、财务核算与管理、风险管控、辅助管理与决策等银行业务最核心功能的系统,是银行信息系统的基础和核心核心银行系统的英文名字 CORE ...
  • 本标准规定了电信行业2G/3G/LTE融合核心网MME/SGSN设备业务和功能、性能、编号与互通、接口、计费...适用于电信行业核心技术试验,为设备引进、网络规划与设备制造、工程设计、网络运行、管理和维护等提供技术依据。
  • 国内银行核心系统建设情况调研报告 前言 核心业务系统,也称为综合业务系统,是银行信息化建设的核心部分,是银行业务经营的基础。随着世界金融环境的不断向前发展,拥有稳健、灵活、安全、可靠的核心业务系统是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 29,432
精华内容 11,772
关键字:

引进核心技术