zoukankan      html  css  js  c++  java
  • 网站自动刷帖,刷赞,刷评论等网络推广方式的基本实现

    上周写了一个腾讯旗下的一个小说网站的自动回帖程序:

      具体怎么实现的呢?      

      其实它就是一个,找到评论接口,然后利用程序模拟HTTP请求的过程。再结合爬虫的相关技术具体实现。 大概分为这么几步:

      第一步:先找到评论接口:

          使用chrome或者火狐浏览器,或者专业点的fiddler对评论过程抓包

    得到具体的请求为:

    POST http://chuangshi.qq.com/bookcomment/replychapterv2 HTTP/1.1
    Host: chuangshi.qq.com
    Connection: keep-alive
    Content-Length: 102
    Accept: application/json, text/javascript, */*; q=0.01
    Origin: http://chuangshi.qq.com
    X-Requested-With: XMLHttpRequest
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    Referer: http://chuangshi.qq.com/bk/xh/AGkEMF1hVjEAOlRlATYBZg-r-69.html
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.8
    Cookie: xxxxxx
    
    bid=14160172&uuid=69&content=%E4%B9%A6%E5%86%99%E7%9A%84%E4%B8%8D%E9%94%99&_token=czo4OiJJRm9TQ0RnbSI7

     

    第二步:模拟请求,它的逻辑是:首先通过频道页(玄幻·奇幻 武侠·仙侠 都市·职场 历史·军事 游戏·体育 科幻·灵异 二次元)抓取文章信息。

    如玄幻小说的频道页为:http://chuangshi.qq.com/bk/huan/ 

    然后提取文章标题、文章ID,章节ID等数据

     

    注入cookie等参数,模拟请求核心代码:

      1     public class AutoCommentService : AutoComment.service.IAutoCommentService 
      2     {
      3         public delegate void CommentHandler(Article article,Comment comment);
      4         public event CommentHandler Commented;
      5         bool stop;
      6         /// <summary>
      7         /// 是否停止服务
      8         /// </summary>
      9         public bool Stop
     10         {
     11             get { return stop; }
     12             set { stop = value; }
     13         }
     14 
     15         /// <summary>
     16         /// 初始化数据库
     17         /// </summary>
     18         public void InitDatabase()
     19         {
     20             SQLiteConnection.CreateFile(AppSetting.DB_FILE);//创建SQL文件  
     21             SQLiteConnection con = new SQLiteConnection();//建立连接  
     22             SQLiteConnectionStringBuilder sqlstr = new SQLiteConnectionStringBuilder();//构建连接字符串  
     23             sqlstr.DataSource = AppSetting.DB_FILE;
     24             con.ConnectionString = sqlstr.ToString();
     25             con.Open();//打开连接         
     26             string cmdStr = @"create table comment (
     27                                   id integer primary key autoincrement,
     28                                   content varchar(500),
     29                                   articleId varchar(50),
     30                                   articleName varchar(50),
     31                                   url varchar(50)
     32                                 )";
     33             SQLiteCommand cmd = new SQLiteCommand(cmdStr, con);
     34             cmd.ExecuteNonQuery();
     35             con.Close();//关闭连接  
     36         }
     37 
     38         /// <summary>
     39         /// 运行自动评论
     40         /// </summary>
     41         public void RunAutoComment()
     42         {
     43             this.Stop = false;
     44             List<string> articleTypes = AppSetting.articleType;
     45             while (!Stop)
     46             {
     47                 foreach (var type in articleTypes)
     48                 {
     49                     string url = AppSetting.WEB_HOME_URL + "/bk/" + type;
     50                     var list = GetArticles(url);
     51                     foreach (var article in list)
     52                     {
     53                         AddComment(article, new Comment(AppSetting.commentContent));
     54                         System.Threading.Thread.Sleep(AppSetting.waitSecond * 1000);
     55                         if (Stop)
     56                             break;
     57                     }
     58                     if (Stop)
     59                         break;
     60                 }
     61             }
     62         }
     63 
     64         public void StopAutoComment()
     65         {
     66             this.Stop = true;
     67         }
     68 
     69         /// <summary>
     70         /// 获取频道页下所有最新发布的文章
     71         /// </summary>
     72         /// <param name="typeUrl">玄幻,军事等频道页URL</param>
     73         /// <returns></returns>
     74         public List<Article> GetArticles(string typeUrl)
     75         {
     76             var html = HttpHelper.GetString(typeUrl);
     77             html = Regex.Match(html, "<div class="update_list">.*?(?=</div>)</div>").Value;
     78             var arcticleUrlMatch = "<a class='gray2' title='(?<title>[^']*)' href='(?<url>[^']*)'>";
     79             MatchCollection matches = Regex.Matches(html, arcticleUrlMatch);
     80             List<Article> articles = new List<Article>();
     81             if (matches != null)
     82             {
     83                 foreach (Match match in matches)
     84                 {
     85                     if (match != null)
     86                     {
     87                         string url = match.Groups["url"].Value;
     88                         string subTitle = match.Groups["title"].Value;
     89                         string title = match.Groups["title"].Value;
     90                         if (string.IsNullOrEmpty(url) == false)
     91                         {
     92                             Article article = new Article(title,subTitle,url);
     93                             articles.Add(article);
     94                         }
     95                     }
     96                 }
     97             }
     98             return articles;
     99         }
    100         
    101         /// <summary>
    102         /// 提交评论
    103         /// </summary>
    104         /// <param name="article"></param>
    105         /// <param name="comment"></param>
    106         /// <returns></returns>
    107         public bool AddComment(Article article, Comment comment)
    108         {
    109             bool successed = false;
    110             var html = HttpHelper.GetString(article.Url);
    111             article.BID = Regex.Match(html, "var bid = "(?<bid>[\d]+)"").Groups["bid"].Value;
    112             article.UUID = Regex.Match(html, "uuid = "(?<uuid>[\d]+)";").Groups["uuid"].Value;
    113             article.Title = Regex.Match(html, "<title>(?<title>[^<]+)</title>").Groups["title"].Value.Replace("_创世中文", "");
    114             dal.CommentDal dal = new dal.CommentDal();
    115             if (dal.CanComment(article))
    116             {
    117                 HttpRequestParam param = new HttpRequestParam();
    118                 string url = "http://chuangshi.qq.com/bookcomment/replychapterv2";
    119                 param.Cookie = AppSetting.Cookie;
    120                 param.Method = "post";
    121                 string token = AppSetting.Token;
    122                 string body = string.Format("bid={0}&uuid={1}&content={2}&_token={3}", article.BID, article.UUID, HttpHelper.UrlEncode(comment.Content), token);
    123                 param.Body = body;
    124                 var result = HttpHelper.GetHtml(url, param);
    125                 comment.Result = result.UnicodeToChinese();
    126                 successed = result.Contains("status":true");
    127                 if (successed)
    128                 {
    129                     comment.Successed = 1;
    130                     dal.AddComment(comment, article);
    131                 }
    132                 else
    133                 {
    134                     comment.Successed = 0;
    135                 }
    136 
    137                 if (Commented != null)
    138                 {                    
    139                     Commented(article, comment);
    140                 }
    141             }
    142             return successed;
    143         }
    144 
    145     }

      其他的刷赞、和刷收藏方法都类似,都是找到接口,然后再模拟请求。

      但大部分网站的这种类似登录,评论,刷赞等接口都是有一定的反机器人策略的。

      比如常见的策略:验证码、IP限制、账号限制、接口调用频次限制。

         但做数据挖掘,做爬虫和这种自动刷评论和系统方总是不断博弈。一方攻,一方守,也都有应对的策略,那就简单谈下攻守方式吧。

    一、验证码:

    验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的公共全自动程序
    防止恶意破解密码、刷票、论坛灌水、刷页。

    当然,种类繁多啊

     

     

    简单验证码自动识别:

    灰化》二值化》去噪》分割 》字符识别

    第一步:灰化

    就是把图片变成黑白色

    第二步:二值化

    通过指定筛选的阈值,将特定灰度的像素点转化成黑白两色。

    中值二值化:中值127为阈值

    均值二值化 :图片所有像素的平均值
    直方图二值化:使用直方图方法来寻找二值化阈值
    维纳滤波二值化:最小均方误差

    第三步:去噪

    删除掉干扰的冗余像素点,即为去噪

    第四步:分割

    将验证码根据边界切割成单个字符

    第五步:字符识别

    根据匹配字符库中的样本,取相似度最高的字符来实现识别。

    相关开源的ORC字符识别模块可参考google开源的

    二、IP限制

    这个的话,使用多台服务器、或者使用IP代理解决。

    三、账号限制

    那就多个账号呗,万能的淘宝,啥都有卖。两元一个的QQ号,几十块钱一大把的邮箱都是有的。有了账号后再使用代码实现自动登录,自动切换账号。

    其实自动切换账号,这个挺折腾的,尤其是大公司的网站。脚本写的非常复杂,你要想实现自动登录,你就必须先得看懂它的代码,提取它的登录逻辑就行封装。比如腾讯的WEB自动登录密码加密的方法:

    它会hash,MD5,位移,编码来来回回加密十来次,封装起来还是有点费劲的。

    function getEncryption(password, salt, vcode, isMd5) {
            vcode = vcode || '';
            password = password || '';
            var md5Pwd = isMd5 ? password : md5(password),
            h1 = hexchar2bin(md5Pwd),
            s2 = md5(h1 + salt),
            rsaH1 = $pt.RSA.rsa_encrypt(h1),
            rsaH1Len = (rsaH1.length / 2).toString(16),
            hexVcode = TEA.strToBytes(vcode.toUpperCase(), true),
            vcodeLen = Number(hexVcode.length / 2).toString(16);
            while (vcodeLen.length < 4) {
                vcodeLen = '0' + vcodeLen
            }
            while (rsaH1Len.length < 4) {
                rsaH1Len = '0' + rsaH1Len
            }
            TEA.initkey(s2);
            var saltPwd = TEA.enAsBase64(rsaH1Len + rsaH1 + TEA.strToBytes(salt) + vcodeLen + hexVcode);
            TEA.initkey('');
            setTimeout(function () {
                __monitor(488358, 1)
            }, 0);
            return saltPwd.replace(/[/+=]/g, function (a) {
                return {
                    '/': '-',
                    '+': '*',
                    '=': '_'
                }
                [
                    a
                ]
            })
        }
    

      

    四、接口次数限制

    降低接口调用速度再配合多账号可以解决问题。

    那么自己的网站怎么防止爬虫和恶意接口调用呢?

    验证码:使用更复杂的验证码,字母重叠的,连到一块的。

    IP限制:这个算了,限制没啥用。

    账号限制:一旦监测到机器人行为,根据情况封号,先封1小时、还敢调用封它一天,还敢?那永久封号,这招很狠的。

    核心接口使用HTTPS协议

     

    当然我遇到过的最牛逼的反爬系统则是阿里的钉钉了,据说是采用阿里最牛的加密技术做的。好奇的朋友可以去抓下包看看,真的是啥线索都没有。

     

  • 相关阅读:
    Mac保留Python2安装Python3(Anaconda3)
    Mybatis Plugin 以及Druid Filer 改写SQL
    Jackson替换fastjson
    Java单元测试 Http Server Mock框架选型
    应用中有多个Spring Property PlaceHolder导致@Value只能获取到默认值
    RabbitMQ Policy的使用
    Collectors.toMap不允许Null Value导致NPE
    php 删除标签
    php 替换标签
    jquery拼接html
  • 原文地址:https://www.cnblogs.com/cinser/p/6123864.html
Copyright © 2011-2022 走看看