网站自动刷帖,刷赞,刷评论等网络推广方式的基本实现
上周写了一个腾讯旗下的一个小说网站的自动回帖程序:
具体怎么实现的呢?
其实它就是一个,找到评论接口,然后利用程序模拟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协议
当然我遇到过的最牛逼的反爬系统则是阿里的钉钉了,据说是采用阿里最牛的加密技术做的。好奇的朋友可以去抓下包看看,真的是啥线索都没有。