不用OCR,如何实现图片验证码的自动识别

        闲暇之时偶然翻出了一个几年前用Java写的预约课程工具。看这创建时间,尘土已相当厚了。

* @version $$Id: Main, v 0.1 2018/5/9 12:49 

        在看到她的那一刻,瞬间勾起了有些遗憾的记忆。说起这位“老友”,当时还真帮了我的大忙。

        话说是因为要在网站上预约课程。预约课程的流程与在电商平台购物有些相似,登录,根据日期查询当天是否有可预约的课程,如果有则从列表中找到合适的时间段,最后预订。经过几次这样的操作后便觉得实在麻烦。程序员最怕的就是这样的麻烦!如果别人也觉得上述情况麻烦,那Ta只能忍着继续在页面上点来点去,但作为一名讨厌繁琐的程序员可不会惯着它。随即,F12走起。综上,我这位“老友”便诞生了,而且之后还给我带来了意外惊喜。

        这个预约课程工具本身很简单,只用了java.net包下与HTTP相关的类便很快搞定了登录和约课的功能,但这两个功能在操作时都需要将图片验证码中的字符一并提交给服务器。完成代码后,之前需要在页面上完成的输入,则改为在代码启动后的控制台进行输入。那图片验证码是怎么在控制台输出的?先来看看验证码图片的样子。

        这是放大了一千多倍的验证码图片,就是这样的。说白了,上面的每个像素点也只是不同的数字而已,数值越小则颜色越深。那么上面这个验证码图片经过代码处理后,打印到控制台就是下面这样的。

                  0                                     
0                                      0                
                                 0                      
                                                     0  
         0                              0               
                                              0         
              0000 000 000000000    000                 
              0000000  000000000    000                 
              00           0       0000                 
0    00    00 00           0       00 00      0         
   0  00   0  00000 0      0       0  00                
0     00  00  00 0000      0      00   00   0           
  0    0  00  00           00      000000               
    0  0000   000          00    00000000               
       0000  000           00    00     00              
        000   00           00   000     00              
        00    00          000   00      000             
                                          0             
                             0                          
                                                        

         怎么样,经过处理后打印出来还是很好辨识的吧。将肉眼辨识出来的验证码字符从控制台输入给程序后便可直接预定指定时间的课程,而登录,查询,浏览,选择这些在页面上预约操作所必不可少的步骤则被全部省略掉了。如果在自己指定的时间没有可供预定的课程,则程序给出相应提示,如果预约成功,则返回预约成功课程的时间地点等信息。在测试代码的过程中,还给了我前面提到的意外惊喜————程序可以预约在网站上查询不到的课程。这个意外收获直接让我提前完成了所有课程,简直有点降维打击的感觉,如同菜还没上桌,你已经在厨房吃饱了。不过作为程序员要注意,这虽然算不上是一个bug,但肯定算是一个缺陷,即前台与后台的没有统一。

        从这位“老友”第一次为我成功预定课程后,我就一直想着怎么再把她捯饬的漂亮些————把人肉识别图片验证码变成自动识别,这样就又可以省去敲四下键盘的巨大工作量了。为此,当时还特意买了一本《模式识别》。之所以买这本书而不是关于机器学习的书,是因为打算用数学模型将每个字符描述出来,而且第一感觉是描述字符的数学模型无法通过机器学习得到,得自己通过对字符的规律进行总结后给出(其实《模式识别》中的内容与机器学习的内容有很多相似之处)。不过后来随着课程的完毕,自动识别图片验证码的想法也就被搁置了,直到今天她又重见天日。如今某家要誓补当年之憾。

        前段时间抽空用Java弥补了下这个当年的遗憾,总的来说识别效果还不错。具体的识别方法也是在以下将要介绍的实现过程中几经调整。

        之所以人可以识别图片中的那些字符,是因为我们认识图片中的每一个字符,但如果让一个未识字的幼儿来指出这些字符是什么,那么他肯定是做不到的。如果想让他辨识字符,那就要先告诉他这些字符是什么。这时,计算机就是这个尚未识字的幼儿。首先要做的就是让计算机认识并记住它要识别的每个字符。这些字符包括0~9,a~z,A~Z。可以用数学模型或记录有效像素两种方法来让计算机认识它将要识别的字符。用数学模型给出每个字符的描述,也就是说要写出六十多个方程组,这工作量实在太可观了。虽然数学模型可以节省空间,并在识别效果不准时可对其进行参数调整,不过这种方法会出现与机器学习中的过拟合类似的问题,也就是对一个字符的某个样子识别准确了,但同一个字符的其他样子的识别能力就降低了,还可能把其他字符识别成这个字符,属于按下葫芦起了瓢,还是算了吧。那就只能用记录描述字符的有效像素的方法来让计算机认识每个字符了。这个方法的缺点是要记录每个字符的所有可能的样子,如果有一个样子没记录,那么就识别不出来或是识别成其他字符。不过也有优点,那就是简单,只要发现了未识别的字符,就将该字符的有效像素描述记录下来,并给与标记即可。总结就是,数学模型复杂但灵活,像素描述简单但死板。事儿就是这么个事儿,情况就是这么个情况。

        用记录字符有效像素(文中提到的有效像素指的是表示出字符轮廓的像素)这种方法则需要在识别验证码前保存同一个字符的所有可能的样子,我把这称为有效像素描述。以下就是以文本形式保存的字符像素描述的内容。

   0    00    000    00    000   00    0    000   00         000    
   0   0000   00     00   0000   00    0   0000   00    0   0000   0
   00  0000  000     000  0000   00    00  0000   00    00  0 00   0
   00  0000  00       00  0000  00     00  0000  00     00  0000  00
   00  00 0  00       00  0  0  00     00  00 0  00     00  00 00 00
   00000  00 00       00000  00 0      00  0  00 00     00  0  00 00
    0000  0000         0000  0000       0000  00 00      0000  00 00
    0000  0000         0000   000       0000  0000       0000   000 
    0000   000         0000   000       0000   000       0000   000 
    000    000         000    000       000    000       000    000 
     00    000          00     00        00    000        00    000 

        这是大写的“W”在图片验证码中可能的样子,当然这四个有效像素描述分别位于文件名中包含大写W的四个文件中,像下图这样。

         用这样的方法就需要在发现未能识别的字符时,将这个字符的有效像素描述保存为上图中的文件。缺点是,随着文件的增多,识别速度会变慢,而且会造成误识别为其他字符的情况增多。所以上述文件并不是越多越好。

        有了上面这些文件,就距离让计算机识别出图片中的验证码进了一步。此时计算机已经知道了每个字符在验证码图片中的样子了。接下来就可以开始进行比较了。在比较有效像素的过程中,同时计算与字符集中每个字符的相似度,并返回相似度最高的那个字符对应的文件名,从而也就识别出了图片中的字符。

        上面的文本文件中保存的是单个字符的有效像素描述,但验证码图片上的那些字符可是连接一起的。所以在与字符描述集中的字符进行比较前先得将图片中的字符切分成一个一个的,然后再进行比较。这也是图片验证码最常用的识别手段。现在,真正的重点来了————从图片中切分出可以识别的字符。

        从前面的图片可以看出,验证码图片上的字符间的像素值显然是高于用于显示字符轮廓像素的值的。因此,这自然的就成为了字符的切分标准。仿佛又接近了目标一步。然而,现实总是残酷的,如果能仅凭这个标准就可将所有图片都准确的切分成四个可供识别的部分那可就太美好了。来看下这张图片。

 K和W还好说,可是9和 j 的下方存在2个有效像素在同一X轴上,所以用有效像素个数为0的标准来拆分上面这个图时,只能切分出3个字符,即K,W,和9j,9和j是连接在一起的。如果这个切分标准放宽些,比如当X轴上有一个,两个或三个有效字符也允许切分,那确实可以将9和 j 切分开,但对于其他图片就有可能出现误切,比如下面这个两个图。

 如果以小于等于两个或三个有效像素的标准来切分上面两个图的话,则前一个图中的L和后一个图中的 m 将被拆分成两个以上且无法识别或是被识别成其他字符的部分。因此,要是切分后得到的字符少于或多余4个的话,就不宜再用有效像素法进行处理了,必须换个思路。

         最初所采用的切分方法是:当切分出的字符少于4个时,就找出其中最宽的那个,然后放宽切分条件再次进行切分。这种方法有一定的效果,但问题是最宽的那部分并非一定是由多个字符组成的。比如,三个小写 j 也没有一个大写的W宽,还是会出现误切分,那就换一种办法。从所有切分出的部分中找出在X轴上有效像素最少的那段,然后以这个X轴为界再次进行切分。只能说也有一定效果,但当识别出了一个图片后,对其他图片的识别能力便减弱了,这显然不行。随后,试着用这两种方法分别再次处理无法切分出4个字符的图片。因为这里要得到两种方法怎么交替结合运行才能给出最高相似度,看到“最”这个字,一下想到了用动态规划算法试试。之后结合动态规划,将上述两种方法结合了起来,效果还是不理想,而且代码也越来越复杂。不行,还得换思路。

        事实证明,当没有好的思路的时候,先暂时放下,干点别的事,也许灵感大爷自己就找上门来了。这不,骑车出去浪一圈,打会儿篮球,思路就有了。不是有个KMP算法吗,可以借鉴一下。既然更换切分标准会误伤友军,那干脆就不切分了,反正现在已经有了一堆字符描述文件,直接比对不就可以了。

        具体做法就是从候选字符集中取一个字符描述,然后根据这个字符描述的宽度,从图片右侧开始比对与该宽度相等的范围内所有像素,比对完之后计算出一个相似度,然后再取下一个字符描述重复这个过程,直到比对完全部字符集,随后便得到了最高相似度的那个字符描述,接着缩小图片范围,重复上述全部过程,直到图片范围缩小到0。核心代码如下。

    private static final float SIMILARITY_THRESHOLD = 0.9f;

    private void selectMaxSimilarityChar(CharRange charRange) {
        //从图片右侧开始依次比对字符集所有字符,取相似度最高者
        if (!charRange.alreadyMatched) {
            MatchedChar matchedChar = matchEqualsCharWidth(charRange);

            if (matchedChar != null && matchedChars.size() < CHAR_COUNT) {
                matchedChars.add(matchedChar);
            } else {
                charRange.alreadyMatched = true;
                stack.add(0, charRange);
            }
        } else {
            Map<CharRange, MatchedChar> recognizeResult = matchFromEndToStart(charRange, new CharRange(charRange.startX, charRange.endX));
            MatchedChar bestMatchedChar = new MatchedChar(null, 0, null);
            for (MatchedChar matchedChar : recognizeResult.values()) {
                if (matchedChar.similarity > bestMatchedChar.similarity && matchedChar.similarity > SIMILARITY_THRESHOLD) {
                    bestMatchedChar = matchedChar;
                }
            }
            if (bestMatchedChar.aChar != null) {
                matchedChars.add(bestMatchedChar);

                charRange.endX = bestMatchedChar.charRange.startX - 1;
                charRange.alreadyMatched = false;

                stack.add(0, charRange);
            } else {
                if (matchedChars.size() == CHAR_COUNT) {
                    return;
                }
                recognizeResult = matchFromStartToEnd(charRange);

                bestMatchedChar = new MatchedChar(null, 0, null);
                for (MatchedChar matchedChar : recognizeResult.values()) {
                    if (matchedChar.similarity > bestMatchedChar.similarity && matchedChar.similarity > SIMILARITY_THRESHOLD) {
                        bestMatchedChar = matchedChar;
                    }
                }
                if (bestMatchedChar.aChar != null) {
                    matchedChars.add(bestMatchedChar);

                    charRange.startX = bestMatchedChar.charRange.endX + 1;
                    charRange.alreadyMatched = false;
                    stack.add(0, charRange);
                } else {
                    log.out("未能给" + charRange + "匹配到任何字符");
                }
            }
        }
    }
    private MatchedChar calculateSimilarity(CharRange charRange) {
        MatchedChar bestMatchedChar = new MatchedChar(null, 0f, charRange);

        for (Map.Entry<boolean[][], Character> candidateChar : CharSetLoader.getCharDict().entrySet()) {
            int candidateCharWidth = candidateChar.getKey()[0].length, recognizeCharWidth = charRange.endX - charRange.startX + 1;
            //过滤掉宽度不一致的字符
            if (recognizeCharWidth != candidateCharWidth) {
                continue;
            }
            //以候选字符的矩阵进行比较,可以得到很高的相似度,但对于有重叠情况的字符有误判,如 q 和 o
            MatchedChar mc = calculateSimilarity(charRange, candidateChar);
            if (mc.similarity > bestMatchedChar.similarity) {
                bestMatchedChar = mc;
            }
        }
        return bestMatchedChar;
    }

    private MatchedChar calculateSimilarity(CharRange charRange, Map.Entry<boolean[][], Character> candidateChar) {
        float similarity = getBingoByCandidateChar(charRange, candidateChar) / (candidateChar.getKey().length * candidateChar.getKey()[0].length);
        return new MatchedChar(candidateChar.getValue(), similarity, charRange);
    }

        这个方法的效果要优于之前的两个方法,不过也存在误判,这取决于字符描述集中不同字符的相似程度,这也就是之前所说的,字符描述集合中的文件不易太多的原因,就像布隆过滤器一样,随着数据的增多,误判率也会随之增长。 

未识别文件:[{文件名:DBYc | 识别结果:DEYc} {文件名:ewfr | 识别结果:Efr} {文件名:jwwk | 识别结果:JWk} {文件名:l4am | 识别结果:AM} {文件名:phcw | 识别结果:HCw} {文件名:rmlf | 识别结果:rmf} ] 
共计 83.0 文件,识别正确数量:76.0 正确率:0.91566265

        程序识别的正确率还是比较邻人满意的。

        因为上述识别代码只是针对那一种图片而写的,为了验证识别程序的通用性,于是在网上找了一些与之前进行识别的不一样的验证码图片,比如下面这些。

  

 

         当然,一开始是没能成功识别的,问题出在对字符像素和背景像素的区分上,之后便重写了字符像素和背景像素的识别代码。终于,经过不断的调整,得到了一个更为通用的图片验证码识别程序。

      0000000000   000 00 0          000     0000         00
        00     0     00   00       000         000      000 
        00     0      0    0      00           000       00 
        00   0       00    0     00            0 00    0 00 
        00   0       00    00    0 000         0 00    0 00 
        000000       00   00    000  00        0 00   0  00 
        00   0        0000      00    0        0  00  0  00 
        00   0       00  0      00    00       0  00  0  00 
        00           00  00     00    00       0   000   00 
        00      0     0   0      0    00       0   000   00 
        00     0     00    0     00  00        0    0    00 
      0000000000    00000   0 0   0000       00000  0  00000


          0000            0000000000     0000                        
         000000           0000000000    0000000                      
        000   00                 000   000   00                      
        00    00                 00    00     00                     
       00          00 000       00     0      00              000000 
       00 000      00000       00             00         00000000000 
       00000000    000        00             00    00000000000       
      000    00    00         0             0000000000000            
      00      0   00         00         00000000000                  
      00      0   00        00     00000000000                       
      0      00   0        000000000000000                           
      00     00   0     00000000000    00                            
      000   000   00000000000         00                             
       0000000000000000000000000000   00000000                       
       000000000000     00000000000  000000000                       
  00000000000                                                        
  00000                                                              


    0000    00000     0000      000       
    0  00   00            0    0  00      
        0   00 00        0    00   0      
       0    00  00      00     00 00      
      0          0        0       00      
    00       0  00        0    0  00      
    00000     000     0000      000   

                               00000000000                                      000000              
                              0000000000000                                    00000000             
              0000000000     0000000000000                                    0000000000            
              000000000000   000000000000                                   000000000000            
               000000000000  000000000000            000000000             00000    000             
               000000000000  0000000 0000           0000000000             0000      00             
              000000  00000  0000    0000         0000000000000           00000                     
              00000   00000  0000   00000        0000000  000000         00000                      
              00000  000000         0000          0000000 000000         0000                       
              0000000000000         0000          0000000 000000         0000   000                 
            00000000000000          0000           00000  000000         0000   00000000            
            000000000000           00000           000000000000          0000   00000000            
            000000000000          000000           000000000000          0000   0000000             
            00000 00000           000000           0000000000            0000     0000              
            00000000000          000000            00000000000           000000   0000              
          0000000 00000          000000            000000000000          000000   0000              
         0000000  000000         00000             000000 000000          000000000000              
         000000000 0000000       000               000000 0000000000       000000000                
           0000000 0000000                         000000  000000000          000                   
            00000  0000000                          000000 0000000              0                   
                   00000                            0000000 000000                                  
                                                   00000000  00                                     
                                                   0000000                                          
                                                   000000                                    
                       000                                                  
                      00000                                                 
                    0000000                                                 
                    000  000                                                
           0       000   00                                                 
         00000    000  0000                           000                   
         000000   00   00         0000000            00000                  
0000     00 000   00  000        000000000           00000                  
00000    00  00   00  00         000   000  0000    000 000      00000      
0  0000  000 00  000 000 0       00  00000 000000    00 000   0000000000    
0   0000 000 00  00  0000000     00 00000  00 000    00  0000000000   000   
0     000000 000 00  000000000  000 000    00  00    000 0000000       000  
00 00  00000 000 00  00    0000 00  00     000 00    000 0000   000000  00  
00 000   000  00000         000 00  00     000 000    00 00000 00000000 000 
00 00000  000 00000    0000  00000 0000000  00 000    00  0000 000   00  00 
00 000000     00000   000000 00000 00000000 00  00    000 0000 000   00  00 
00  00 0000   00000   00  00 0000  000   000000 00    000 00000 0000000 000 
000 00  0000  000000 000 000  0000        00000 000    00 00000 000000  00  
000 000   000  00000  00000  000000000000  0000 000    00  0000 0000   000  
0000000    000 00000   0000  0000000000000 0000  00    000 00000     0000   
 0000000000000 000000       000  000   000  0000 00    000 00000  000000    
 00  0000000000000 0000   0000    000   00  0000 000   000 00000 00000      
 000 00   0000 00000000000000    000000000 00000 000   00  00 00  00        
 000 000    0000000000000000     00 00000  00 00  0000000  00 000 00        
  00 000    000000  000000000000 00  00   000 000  00000  000  00 000       
  00  00     00000       0000000000000000000   000       000   00  00       
  000000      000               0000000000000000000   000000   000 00       
  000000                           00000000000000000000000000000000000000000
   0000                                        00000000000000000000000000000
                                                                00000       
                                                                 000        

        该说不说的,那个空心的验证码实在是太损了!

        之后又顺便找了个签名网站,生成了偶像的Flag和姓名,测试效果也不错。

 

-----------------------------------------------------------------------------------------------------------------
---------##-----------------------#----------------##------------#-----------------------------------------------
--------###-----##---------------###---------------##-----------###----------------##----------------------------
--------###----###--------------####--------------###-----------##-----------------##----------------------------
--------###----###--##---------####---------------###-----------##-----------------##----------------------------
--------###---###--###---------####--------------####-----------##----------------##-----------------------------
--------###--####--##---------##-#-----------#---###------------##----------------##-----------------------------
--------######-##-------------###------##---###--###------------##----##---------###-#----##----#----------------
--------#####--##--------###--###-----###---###-###---------#--##----##-----###--##-##---###---####--###---------
--------#------#---##---####-#####---####--###--##----------##-##---####---###--###-#---####--#####-######-------
--------#-----##--###--###---##-##--#####--###--##----------##-##-######--###---##-##--##-##-###-##########------
-------##-----##-####-###--#######################-##--------#-#--##########--##########-######--###-###-###-----
-------##-----##---######-##-###-######-##--###--####--------###--###-###-##-##-###-###--###-######--##---##-----
--------#-----#--------####--##----###-----------------------###--##------####--##-------##---##-----#-----------
-----------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------
-----------##----###---------------------------------------------#-----------------#####-------------------------
----------###---####--------------------------------------------##-------------###########-----------------------
----------###---###----#---------------------------------------###------------##############---------------------
----------##----##----##---------------------------------------###-----------###---##----###---------------------
----------##---###----##---------------------------------------##------------##----##-----##---------------------
---------###--###---------------------------------------------##-------------###--###-----##---------------------
---------#######------##---#----------##---------------###----##---------------#--##------##----##---##---#------
---------#######-----###--###-###----####-------------#####-#######---------------##------##--#####-###-####-----
---------##--####----##--#-######---####-------------##--######-------------------##-----###-##--########-##-----
--------###---####---##---####-##--##---------------##---##--###-----------------###----###--##---######--##-----
--------###----###--##----###--##-##---#------------##---##--####----------------##########-##---##--##---#------
--------##-----####-##----###--##-#######-----------##---##-##--##---------------########---##---##--##--##------
--------##------######--#-##---######--###----------##--##--##--##---------------##---------##--##--###--##------
--------##-------#######-###---###----##------------#####---##--##--------------###----------####---#####--------
------------------------------------####--------------------##--#---------------##------------------##-----------
-----------------------------------##-##--------------------##-##---------------##------------------##-----------
-----------------------------------#-##---------------------####----------------###-----------------##-----------
----------------------------------####---------------------####----------------###------------------##-----------
----------------------------------###-----------------------#---------------------------------------#------------
----------------------------------------------------------------------------------------------------#------------
-----------------------------------------------------------------------------------------------------------------

                当然,以上输出都是缩小了4倍的结果,如果原图输出是不太利于展示的,比如下面这样。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值