第11课-NAND FLASH

注:以下内容学习于韦东山老师arm裸机第一期视频教程


一.NAND_FLASH操作原理

    1.1 NAND FLASH是一个存储芯片

        那么: 这样的操作很合理"读地址A的数据,把数据B写到地址A"

        问1. 原理图上NAND FLASH和S3C2440之间只有数据线,

             怎么传输地址?

        答1.在DATA0~DATA7上既传输数据,又传输地址

             当ALE为高电平时传输的是地址,

        问2. 从NAND FLASH芯片手册可知,要操作NAND FLASH需要先发出命令

             怎么传入命令?

        答2.在DATA0~DATA7上既传输数据,又传输地址,也传输命令

             当ALE为高电平时传输的是地址,

             当CLE为高电平时传输的是命令

             当ALE和CLE都为低电平时传输的是数据

        问3. 数据线既接到NAND FLASH,也接到NOR FLASH,还接到SDRAM、DM9000等等

             那么怎么避免干扰?

        答3. 这些设备,要访问之必须"选中",

             没有选中的芯片不会工作,相当于没接一样

        问4. 假设烧写NAND FLASH,把命令、地址、数据发给它之后,

             NAND FLASH肯定不可能瞬间完成烧写的,

             怎么判断烧写完成?

        答4. 通过状态引脚RnB来判断:它为高电平表示就绪,它为低电平表示正忙

        问5. 怎么操作NAND FLASH呢?

        答5. 根据NAND FLASH的芯片手册,一般的过程是:

             发出命令

             发出地址

             发出数据/读数据

                      NAND FLASH                                    S3C2440

        发命令    选中芯片                   

                      CLE设为高电平                              NFCMMD=命令值     

                      在DATA0~DATA7上输出命令值

                      发出一个写脉冲

                    

        发地址    选中芯片                                       NFADDR=地址值

                      ALE设为高电平

                      在DATA0~DATA7上输出地址值

                      发出一个写脉冲

        发数据    选中芯片                                       NFDATA=数据值

                      ALE,CLE设为低电平

                      在DATA0~DATA7上输出数据值

                      发出一个写脉冲

        读数据    选中芯片                                       val=NFDATA

                      发出读脉冲

                      读DATA0~DATA7的数据


        1.2用UBOOT来体验NAND FLASH的操作:


        1.2.1  读ID

                                                   S3C2440                       u-boot

            选中                           NFCONT的bit1设为0   md.l 0x4E000004 1; mw.l 0x4E000004  1

            发出命令0x90                   NFCMMD=0x90         mw.b 0x4E000008 0x90

            发出地址0x00                    NFADDR=0x00          mw.b 0x4E00000C 0x00

            读数据得到0xEC                 val=NFDATA             md.b 0x4E000010 1

            读数据得到device code      val=NFDATA             md.b 0x4E000010 1

            退出读ID的状态                 NFCMMD=0xff           mw.b 0x4E000008 0xff

                

        1.2.2 读内容: 读0地址的数据

            使用UBOOT命令:

            nand dump 0

            Page 00000000 dump:

                    17 00 00 ea 14 f0 9f e5  14 f0 9f e5 14 f0 9f e5

                                                           S3C2440                 u-boot

            选中                           NFCONT的bit1设为0   md.l 0x4E000004 1; mw.l 0x4E000004  1

            发出命令0x00                   NFCMMD=0x00         mw.b 0x4E000008 0x00

            发出地址0x00                   NFADDR=0x00         mw.b 0x4E00000C 0x00

            发出地址0x00                   NFADDR=0x00         mw.b 0x4E00000C 0x00

            发出地址0x00                   NFADDR=0x00         mw.b 0x4E00000C 0x00

            发出地址0x00                   NFADDR=0x00         mw.b 0x4E00000C 0x00

            发出地址0x00                   NFADDR=0x00         mw.b 0x4E00000C 0x00

            发出命令0x30                   NFCMMD=0x30         mw.b 0x4E000008 0x30

            读数据得到0x17                 val=NFDATA          md.b 0x4E000010 1

            读数据得到0x00                 val=NFDATA          md.b 0x4E000010 1

            读数据得到0x00                 val=NFDATA          md.b 0x4E000010 1

            读数据得到0xea                 val=NFDATA          md.b 0x4E000010 1

            退出读状态                     NFCMMD=0xff         mw.b 0x4E000008 0xff

            

二.NAND FLASH时序及初始化

    2.1 对于存储芯片的编程

        2.1.1 初始化--------->主控芯片NAND FLASH控制器的初始化

        2.1.2 识别----------->读取ID

        2.1.3 读------------->一次读取一个页(page)

        2.1.4 写------------->一次写一个页(page)

        2.1.5 擦除----------->一次擦除一个块(block,64个页)

    

    2.2 NAND FLASH时序及初始化的编程

        由于NAND FLASH控制器会外接不同型号的NAND FLASH,因此需要根据芯片手册调整时序参数

        

        2.2.1 在2440芯片手册的NAND FLASH控制器章节找到如下时序图

            

              TACLS代表CLE/ALE信号发出之后需要等待多长时间才能发出写脉冲

              TWRPH0表示写脉冲维持的时间

              TWRPH1表示写脉冲恢复后需要维持多长时间CLE/ALE信号才能恢复

        

        2.2.2 在NAND FLASH芯片手册中找到对应的时序图如下

            

              同时找到这些值需要设置为多少的表格如下

              

              TACLS = tCLS(tALS) - tWP >= 0 (tCLS(tALS)>=12ns, tWP >= 12ns),即写信号可以和命令/地址信号同时发出

              TWRPH0 = tWP >= 12ns

              TWRPH1 = tCH(tALH) >= 5ns

                

        2.2.2 这些参数的设置在NFCONF寄存器中,如下图

                

              bit[13:12] : Duration = HCLK x TACLS = 10ns * TACLS >= 0 ===> 设置为0即可

              bit[10:8]  : Duration = HCLK x ( TWRPH0 + 1 ) = 10ns * ( TWRPH0 + 1 ) >= 12 ===> 设置为1即可

              bit[6:4]   : Duration = HCLK x ( TWRPH1 + 1 ) = 10ns * ( TWRPH1 + 1 ) >= 5  ===> 设置为0即可

              

        2.2.3 设置NFCONT寄存器使能NAND FLASH控制器,初始化ECC,禁止片选

            

        代码如下:

        void nand_init(void)
        {
        #define  TACLS   0
        #define  TWRPH0  1
        #define  TWRPH1  0
            /*设置NAND FLASH的时序*/
            NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
            /*使能NAND FLASH控制器,初始化ECC,禁止片选*/
            NFCONT = (1<<4) | (1<<1) | (1<<0);
        }

三.读取NAND FLASH芯片的ID    

        读ID操作时序如下,NAND FLASH控制器会帮助我们完成这些复杂的时序控制,我们在发命令时只需要将命令写入NFCCMD寄存器,地址写入NFADDR寄存器

    

        根据时序图可以知道读取ID操作步骤:

            1. 发出0x90命令

            2. 发出0x00地址

            3. 读取数据,每次读取一个字节

                数据的具体含义如下图:

                    

               第一个数据是ec,表示厂家ID

               第二个数据是da,表示设备ID

               第四个数据里面包含有页大小和块大小,我们可以根据得到的第4个数据将页大小,块大小打印出来

               

        具体代码如下:

            void nand_select(void)
            {
                /*使能片选*/
                NFCONT &=~(1<<1);
            }

            void nand_deselect(void)
            {
                /*禁止片选*/
                NFCONT |= (1<<1);
            }

            void nand_cmd(unsigned char cmd)
            {
                volatile int i;
                NFCCMD = cmd;
                for(i=0; i<10; i++);
            }

            void nand_addr_byte(unsigned char addr)
            {
                volatile int i;
                NFADDR = addr;
                for(i=0; i<10; i++);
            }

            unsigned char nand_data(void)
            {
                return    NFDATA;
            }

            void nand_chip_id(void)
            {
                unsigned char buf[5]={0};
                
                nand_select();
                nand_cmd(0x90);
                nand_addr_byte(0x00);

                buf[0] = nand_data();
                buf[1] = nand_data();    
                buf[2] = nand_data();
                buf[3] = nand_data();
                buf[4] = nand_data();    
                nand_deselect();     

                printf("maker   id  = 0x%x\n\r",buf[0]);
                printf("device  id  = 0x%x\n\r",buf[1]);    
                printf("3rd byte    = 0x%x\n\r",buf[2]);        
                printf("4th byte    = 0x%x\n\r",buf[3]);            
                printf("page  size  = %d kb\n\r",1  <<  (buf[3] & 0x03));    
                printf("block size  = %d kb\n\r",64 << ((buf[3] >> 4) & 0x03));    
                printf("5th byte    = 0x%x\n\r",buf[4]);
                
            }    
           

三.NAND FLASH数据读取

    3.1 NAND FLASH的页读取

        3.1.1 nand flash结构图如下

           
           

           其中,每一页有2K的页数据(0-2047),和64字节的OOB区

           a.地址问题:

               注意:当CPU要读取第2048个数据,会访问到Page1的第0个数据,而不是OOB区域的第0个数据(CPU在寻址时根本看不到OOB区域)

               

               nand flash读一页数据或者写一页数据的时候可能某一位会反转,因此写一页数据的时候会产生ECC校验码,然后将校验码写入OOB区,

               在读取数据的时候可能某一位是错误的,然后再次读出OOB区域的校验码,使用校验码来修正里面的数据.

               OOB的存在只是为了解决NAND FLASH的缺陷而存在。CPU只关心数据,不需要看到OOB。

               

                CPU大爷: 小nand啊,你的性能比不上小nor啊,听说你有位反转的毛病

                Nand   : 是的,大爷,位反转是我天生的毛病,时有时无

                CPU大爷: 靠,你说你价格便宜容量大,这不是害我嘛

                Nand   : 没事,我有偏方,用OOB就可以解决这问题

                CPU大爷: 得得得,你那偏方是什么也别告诉我,我只管能读写正确的数据

                Nand   : 是的,大爷,我这OOB偏方也就我自个私下使用。

                         您就像使用nor一样使唤我就可以了

        

        3.1.2 读操作的时序图如下

            

            对应代码:

                void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
                {
                    int i = 0;
                    int page = addr / 2048;
                    int col  = addr & (2048 - 1);
                    
                    nand_select();

                    while (i < len)
                    {
                        /* 发出00h命令 */
                        nand_cmd(00);

                        /* 发出地址 */
                        /* col addr */
                        nand_addr_byte(col & 0xff);
                        nand_addr_byte((col>>8) & 0xff);

                        /* row/page addr */
                        nand_addr_byte(page & 0xff);
                        nand_addr_byte((page>>8) & 0xff);
                        nand_addr_byte((page>>16) & 0xff);

                        /* 发出30h命令 */
                        nand_cmd(0x30);

                        /* 等待就绪 */
                        wait_ready();

                        /* 读数据 */
                        for (; (col < 2048) && (i < len); col++)
                        {
                            buf[i++] = nand_data();            
                        }
                        if (i == len)
                            break;

                        col = 0;
                        page++;
                    }

            读操作的改进,跳过坏块(根据读取的OOB区域是否是0xff)

                void nand_addr(unsigned int addr)
                {
                    unsigned int col  = addr % 2048;
                    unsigned int page = addr / 2048;
                    volatile int i;

                    NFADDR = col & 0xff;
                    for (i = 0; i < 10; i++);
                    NFADDR = (col >> 8) & 0xff;
                    for (i = 0; i < 10; i++);
                    
                    NFADDR  = page & 0xff;
                    for (i = 0; i < 10; i++);
                    NFADDR  = (page >> 8) & 0xff;
                    for (i = 0; i < 10; i++);
                    NFADDR  = (page >> 16) & 0xff;
                    for (i = 0; i < 10; i++);    
                }

                void nand_page(unsigned int page)
                {
                    volatile int i;
                    
                    NFADDR  = page & 0xff;
                    for (i = 0; i < 10; i++);
                    NFADDR  = (page >> 8) & 0xff;
                    for (i = 0; i < 10; i++);
                    NFADDR  = (page >> 16) & 0xff;
                    for (i = 0; i < 10; i++);    
                }

                void nand_col(unsigned int col)
                {
                    volatile int i;

                    NFADDR = col & 0xff;
                    for (i = 0; i < 10; i++);
                    NFADDR = (col >> 8) & 0xff;
                    for (i = 0; i < 10; i++);
                }


                void nand_wait_ready(void)
                {
                    while (!(NFSTAT & 1));
                }

                unsigned char nand_data(void)
                {
                    return NFDATA;
                }

                int nand_bad(unsigned int addr)
                {
                    unsigned int col  = 2048;
                    unsigned int page = addr / 2048;
                    unsigned char val;

                    /* 1. 选中 */
                    nand_select();
                    
                    /* 2. 发出读命令00h */
                    nand_cmd(0x00);
                    
                    /* 3. 发出地址(分5步发出) */
                    nand_col(col);
                    nand_page(page);
                    
                    /* 4. 发出读命令30h */
                    nand_cmd(0x30);
                    
                    /* 5. 判断状态 */
                    nand_wait_ready();

                    /* 6. 读数据 */
                    val = nand_data();
                    
                    /* 7. 取消选中 */        
                    nand_deselect();


                    if (val != 0xff)
                        return 1;  /* bad blcok */
                    else
                        return 0;
                }


                void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
                {
                    int col = addr % 2048;
                    int i = 0;
                        
                    while (i < len)
                    {

                        if (!(addr & 0x1FFFF) && nand_bad(addr)) /* 一个block只判断一次 */
                        {
                            addr += (128*1024);  /* 跳过当前block */
                            continue;
                        }

                        /* 1. 选中 */
                        nand_select();
                        
                        
                        /* 2. 发出读命令00h */
                        nand_cmd(0x00);

                        /* 3. 发出地址(分5步发出) */
                        nand_addr(addr);

                        /* 4. 发出读命令30h */
                        nand_cmd(0x30);

                        /* 5. 判断状态 */
                        nand_wait_ready();

                        /* 6. 读数据 */
                        for (; (col < 2048) && (i < len); col++)
                        {
                            buf[i] = nand_data();
                            i++;
                            addr++;
                        }
                        
                        col = 0;


                        /* 7. 取消选中 */        
                        nand_deselect();
                        
                    }
                }

                    
                    nand_deselect();     

    3.2 实现从NAND FLASH启动

        2440一上电之后,NAND FLASH里面的4K会被自动复制到4K的RAM中去,我们需要使用这4K的代码将全部代码复制到SDRAM中去执行

        首先需要确保复制的代码位于前4K内容,因此修改Makefile,将Start.o interrupt.o init.o nand.o放在最前面进行链接

        

        拷贝代码如下:

        void copy2sdram(void)
        {
            /* 要从lds文件中获得 __code_start, __bss_start
             * 然后从0地址把数据复制到__code_start
             */

            extern int __code_start, __bss_start;

            volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
            volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
            volatile unsigned int *src = (volatile unsigned int *)0;
            int len;

            len = ((int)&__bss_start) - ((int)&__code_start);

            if (isBootFromNorFlash())
            {
                while (dest < end)
                {
                    *dest++ = *src++;
                }
            }
            else
            {
                nand_init();
                nand_read(src, dest, len);
            }
        }

四.NAND FLASH的擦除和烧写

    擦除(以块为单位)操作时序图如下:

        

    代码如下:    

        int NandErase(unsigned int addr, unsigned int len)
        {    
            int page;

            if ((addr & (0x20000-1)))
            {
                printf("Nand erase err, addr should be block align\n\r");
                return -1;
            }
            
            if ((len & (0x20000-1)))
            {
                printf("Nand erase err, len should be block align\n\r");
                return -1;
            }

            /* 1.Chip Select */
            NandSelect();

            while (len)
            {
                page = addr / 2048;
            
                /* 2.Send cmd 0x60 */
                NandCmd(0x60);        

                /* 3.Send row addr */        
                NandAddr(page & 0xff);
                NandAddr((page >> 8) & (0xff));
                NandAddr((page >> 16) & (0xff));

                /* 4.Send cmd 0xD0 */
                NandCmd(0xD0);        

                /* 5. Wait*/
                WaitReady();

                /* 7.Send cmd 0x70 */
                NandCmd(0x70);

                addr += (128 * 1024);
                len -= (128 * 1024);
            }

                NandDeSelect();
                return 0;
            }

    烧写操作时序图如下:

    

    代码如下:

        void NandWrite(unsigned int addr, unsigned char *buf, unsigned int len)
        {
            int page = addr / 2048;
            /* 也可以写成 int col = addr & (2048 - 1); */
            int col = addr % 2048;
            int i = 0;
            
            /* 1.Chip Select */
            NandSelect();

            while (1)
            {
                /* 2.Send cmd 0x80 */
                NandCmd(0x80);

                /* 3.Send addr */
                
                /* 3.1 Send col addr */
                NandAddr(col & 0xff);
                NandAddr((col >> 8) & 0xff);

                /* 3.2 Send Row addr */
                NandAddr(page & 0xff);
                NandAddr((page >> 8) & (0xff));
                NandAddr((page >> 16) & (0xff));

                for (; (col < 2048) && (i < len);col++)
                {
                    NandDataWrite(buf[i++]);
                }
                /* 4.Send cmd 0x10 */
                NandCmd(0x10);
                
                /* 5. Wait*/
                WaitReady();
                    
                if (i == len)
                    break;
                else
                {
                    col = 0;
                    page++;        
                }

            }

            NandDeSelect();

        }

                

MySQL数据库从入门实战课

12-31
限时福利1:购课进答疑群专享柳峰(刘运强)老师答疑服务。 限时福利2:购课后添加学习助手(微信号:csdn590),按消息提示即可领取编程大礼包! 注意:原价129的课程,最后2天限时秒杀仅需49元!! 为什么说每一个程序员都应该学习MySQL? 根据《2019-2020年中国开发者调查报告》显示,超83%的开发者都在使用MySQL数据库。 使用量大同时,掌握MySQL早已是运维、DBA的必备技能,甚至部分IT开发岗位也要求对数据库使用和原理有深入的了解和掌握。 学习编程,你可能会犹豫选择 C++ 还是 Java;入门数据科学,你可能会纠结于选择 Python 还是 R;但无论如何, MySQL 都是 IT 从业人员不可或缺的技能! 【课程设计】 在本课程中,刘运强老师会结合自己十多年来对MySQL的心得体会,通过课程给你分享一条高效的MySQL入门捷径,让学员少走弯路,彻底搞懂MySQL。 本课程包含3大模块:  一、基础篇: 主要以最新的MySQL8.0安装为例帮助学员解决安装与配置MySQL的问题,并对MySQL8.0的新特性做一定介绍,为后续的课程展开做好环境部署。 二、SQL语言篇: 本篇主要讲解SQL语言的四大部分数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL,学会熟练对库表进行增删改查等必备技能。 三、MySQL进阶篇: 本篇可以帮助学员更加高效的管理线上的MySQL数据库;具备MySQL的日常运维能力,语句调优、备份恢复等思路。  

Python入门到实战一卡通

06-09
<span><span><span><span> <p class="ql-long-24357476"> <span> </span> </p> <p class="ql-long-24357476"> 【课程特色】 </p> <p class="ql-long-24357476"> <span class="ql-author-24357476">1、超强师资+体系全面+ 1 对 1 答疑+离线缓存+永久有效,无限回放</span> </p> <p class="ql-long-24357476"> 2、知识全面系统,从Python入门到逐步进阶到爬虫、数据分析、Web框架、人工智能应用 </p> <p class="ql-long-24357476"> <br> </p> <p class="ql-long-24357476"> <span class="ql-author-24357476">【优惠说明】</span> </p> <p class="ql-long-24357476"> <span class="ql-author-24357476">1、8大课程,250余节视频课,原价998元,今日联报立减800,仅需198元</span> </p> <p class="ql-long-24357476"> <span class="ql-author-24357476">2、</span>现在购课,就送价值800元的编程大礼包! </p> <p class="ql-long-24357476"> 备注:请添加微信:itxy41,按提示获取讲师答疑服务。 </p> <p> <br> </p> <p class="ql-long-24357476"> 讲师介绍:裴帅帅,前百度资深架构师,现爱奇艺算法架构师全程亲自授课。 </p> <p> <br> </p> <p class="ql-long-24357476"> 【为什么要学习这门套餐课?】 </p> <p class="ql-long-24357476"> Python无论是在web/爬虫/人工智能/大数据/机器学习/测试/运维/数据分析等等领域都有大量的应用,但是作为小白来讲,很难确定最适合自己的应用方向。 </p> <p> <br> </p> <p class="ql-long-24357476"> 在这门课程中,将带你从零入门Python,并向你讲授实战 Python 各个应用方向的核心知识点,同时应用于实战项目。 </p> <p> <br> </p> <p class="ql-long-24357476"> 【学完后我将达到什么水平?】 </p> <p class="ql-long-24357476"> 你将能够熟练掌握 Python 在人工智能时代的多种技能,具备使用 Python 编写代码完成 Web 后台开发、网络爬虫、数据分析、机器学习、推荐系统等多种项目实战的能力,掌握 Python 全栈工程师的核心能力。 </p> <p> <br> </p> <p class="ql-long-24357476"> 【课程学习路径】 </p> <p class="ql-long-24357476"> 本套课以市场就业和职位需求为核心,从 Python 入门到多领域实战,并结合 Python 全栈工程师的进阶路线,共分为八大模块,分别是:Python 基础、Python Web 开发、Python 爬虫、Numpy 数据计算、Pandas 数据分析、Python数据可视化、Tensorflow 深度学习、推荐系统实战应用模块。 </p> <p> <br> </p> <p class="ql-long-24357476"> 套餐中一共包含8门Python课程(共246讲)助你从零进阶Python全栈工程师! </p> <p class="ql-long-24357476"> 课程1:《Python零基础入门视频教程》 </p> <p class="ql-long-24357476"> 课程2:《Python爬虫从入门到实战》 </p> <p class="ql-long-24357476"> 课程3:《Python使用Flask开发Web服务》 </p> <p class="ql-long-24357476"> 课程4:《Python使用Numpy入门数据计算》 </p> <p class="ql-long-24357476"> 课程5:《Python使用Pandas入门数据分析》 </p> <p class="ql-long-24357476"> 课程6:《Python数据图表可视化》 </p> <p class="ql-long-24357476"> 课程7:《Tensorflow深度学习从入门到实战》 </p> <p class="ql-long-24357476"> 课程8:《推荐系统技术入门到实战》 </p> <p> <br> </p> <p class="ql-long-24357476"> 【面向人群】 </p> <p class="ql-long-24357476"> 1、在校计算机专业或者对软件编程感兴趣的学生; </p> <p class="ql-long-24357476"> 2、想要使用数据分析、网络爬虫提升职场竞争力升职加薪的各行各业的企业白领; </p> <p class="ql-long-24357476"> 3、想要转方向成为数据分析师、大数据开发、机器学习算法、推荐系统工程师的职场码农; </p> <p class="ql-long-24357476"> 4、准备从事人工智能、Python开发的程序员。 </p> </span> <p> <br> </p> <p class="ql-long-24357476"> <br> </p> <p> <br> </p> <p class="ql-long-24357476"> 【课程知识体系图】 </p> </span></span></span> <p> <img src="https://img-bss.csdnimg.cn/202006100818561687.png" alt=""> </p>

150讲轻松搞定Python网络爬虫

05-16
【为什么学爬虫?】        1、爬虫入手容易,但是深入较难,如何写出高效率的爬虫,如何写出灵活性高可扩展的爬虫都是一项技术活。另外在爬虫过程中,经常容易遇到被反爬虫,比如字体反爬、IP识别、验证码等,如何层层攻克难点拿到想要的数据,这门课程,你都能学到!        2、如果是作为一个其他行业的开发者,比如app开发,web开发,学习爬虫能让你加强对技术的认知,能够开发出更加安全的软件和网站 【课程设计】 一个完整的爬虫程序,无论大小,总体来说可以分成三个步骤,分别是: 网络请求:模拟浏览器的行为从网上抓取数据。 数据解析:将请求下来的数据进行过滤,提取我们想要的数据。 数据存储:将提取到的数据存储到硬盘或者内存中。比如用mysql数据库或者redis等。 那么本课程也是按照这几个步骤循序渐进的进行讲解,带领学生完整的掌握每个步骤的技术。另外,因为爬虫的多样性,在爬取的过程中可能会发生被反爬、效率低下等。因此我们又增加了两个章节用来提高爬虫程序的灵活性,分别是: 爬虫进阶:包括IP代理,多线程爬虫,图形验证码识别、JS加密解密、动态网页爬虫、字体反爬识别等。 Scrapy和分布式爬虫:Scrapy框架、Scrapy-redis组件、分布式爬虫等。 通过爬虫进阶的知识点我们能应付大量的反爬网站,而Scrapy框架作为一个专业的爬虫框架,使用他可以快速提高我们编写爬虫程序的效率和速度。另外如果一台机器不能满足你的需求,我们可以用分布式爬虫让多台机器帮助你快速爬取数据。   从基础爬虫到商业化应用爬虫,本套课程满足您的所有需求! 【课程服务】 专属付费社群+每周三讨论会+1v1答疑
©️2020 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值