标签:
记得以前刷hdu的时候总是发现有人能一分钟内提交很多次 而且还ac 感觉不可思议。后来百度搜了搜 原来是网络爬虫
带着这一届acm成员集训的时候有成员说hdu炸了 一直判断中 我就说是爬虫。。。然后就想了想 自己能不能写而且要用java写
结果一天没吃饭(因为感觉我能做出来)。。。直到晚上6点多 测试一个数据 A了 那种感觉 无法用言语表达。。。比吃了任何东西都快乐。
一直对自己的自学能力很有自信的 可怕的就是没有方向 四处乱撞 唉
给做题的人说声对不起 我知道这是不道德的行为 我已经让线程睡眠了10S 就是为了不耽误你们做题
仅仅是为了学习 如果为了刷排名 不推荐啊~~
AC率不高的原因是提交时间间隔太短 以至于代码结果还没出来就提交下一道了 。。。不想改了。
进入正题:
1.遍历所有题目,使用url模拟http的get请求向服务器发送页面请求
2.获得返回页面源码 使用正则表达式筛选出csdn网站的网址放入集合
3.同1,进入筛选出的csdn网站
4.从csdn网站的源码中筛选出所需要的试题代码答案。
5.对获得的代码答案进行编码处理(具体HTML元素符号的换成> <...等)
6.使用http的post请求提交向hdu网站提交代码。
7.最后提交后进行检测 如果是Accept就执行下一道题目 否则遍历集合中的下一个网址
具体做法
1.遍历所有题目,使用url模拟http的get请求向服务器发送页面请求
-
-
public static String sendGet(String url) {
-
-
String res = "";
-
-
BufferedReader in = null;
-
try {
-
-
URL readURL = new URL(url);
-
-
<span style="white-space:pre"> </span>try {
-
trustAllHttpsCertificates();
-
} catch (Exception e) {
-
-
e.printStackTrace();
-
}
-
<span style="white-space:pre"> </span> HttpsURLConnection.setDefaultHostnameVerifier(hv);
-
-
URLConnection connection = readURL.openConnection();
-
connection.setRequestProperty("User-Agent",
-
"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
-
-
connection.connect();
-
-
in = new BufferedReader(new InputStreamReader(
-
connection.getInputStream()));
-
-
String line = "";
-
while ((line = in.readLine()) != null) {
-
res += line;
-
res+="\n";
-
}
-
} catch (MalformedURLException e) {
-
-
e.printStackTrace();
-
} catch (IOException e) {
-
-
e.printStackTrace();
-
} finally {
-
try {
-
if (in != null) {
-
in.close();
-
}
-
} catch (IOException e) {
-
-
e.printStackTrace();
-
}
-
}
-
return res;
-
}
大家可以看到我上面有两个标记mark1 ,mark1.其实第一天我没有加这两句话 也能够访问360搜索的
可是第二天突然出现了 sun.security.validator.ValidatorException:
PKIX path building failed 这个异常
百度搜索说是证书的问题 加上两个方法就OK了。
-
static HostnameVerifier hv = new HostnameVerifier() {
-
public boolean verify(String urlHostName, SSLSession session) {
-
System.out.println("Warning: URL Host: " + urlHostName + " vs. "
-
+ session.getPeerHost());
-
return true;
-
}
-
};
-
-
private static void trustAllHttpsCertificates() throws Exception {
-
javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
-
javax.net.ssl.TrustManager tm = new miTM();
-
trustAllCerts[0] = tm;
-
javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
-
.getInstance("SSL");
-
sc.init(null, trustAllCerts, null);
-
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc
-
.getSocketFactory());
-
}
-
-
static class miTM implements javax.net.ssl.TrustManager,
-
javax.net.ssl.X509TrustManager {
-
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
-
return null;
-
}
-
-
public boolean isServerTrusted(
-
java.security.cert.X509Certificate[] certs) {
-
return true;
-
}
-
-
public boolean isClientTrusted(
-
java.security.cert.X509Certificate[] certs) {
-
return true;
-
}
-
-
public void checkServerTrusted(
-
java.security.cert.X509Certificate[] certs, String authType)
-
throws java.security.cert.CertificateException {
-
return;
-
}
-
-
public void checkClientTrusted(
-
java.security.cert.X509Certificate[] certs, String authType)
-
throws java.security.cert.CertificateException {
-
return;
-
}
-
}
2.获得返回页面源码
使用正则表达式筛选出csdn网站的网址放入集合
至于我们为什么要访问360搜索而不用百度呢
是发现在使用百度搜索结果的源码中 对网址链接进行了加密
想来就是防止爬虫获得网址的。。
然后我们进入360搜索 查看搜索的源码 你发现了什么
对的 在红线上方不就是csdn博客的网址吗
使用正则表达式 很轻松的就能够得到了
哈哈 真是太聪明了 有人会说里面还有%2f等等什么的符号
仔细想想这是什么?http://blog.csdn.net 懂了吧
也就是把://等转换为了url编码 解码就好了
然后把筛选后的网址放入集合中即可
具体代码如下:
-
public static void getCsdnUrl(String str) {
-
String regex="http%3A%2F%2Fblog.csdn.net.{10,100}&q";
-
Pattern p = Pattern.compile(regex);
-
Matcher m = p.matcher(str);
-
while (m.find()) {
-
csdnURL.add(m.group(0).substring(0, m.group().length()-2));
-
}
-
}
url解码代码就是这一句:
-
string=URLDecoder.decode(string, "utf-8");
3.同1,进入筛选出的csdn网站
直接调用sendGet方法即可 返回Csdn页面源码
4.从csdn网站的源码中筛选出所需要的试题代码答案。
看到了我们需要的代码了吗?
同样使用强大的正则表达式筛选出我们需要的代码
在这里我们只选择#include开头的然后以</结束(一般以</pre>,也有以</textarea>的,也有其它的
所以我们就以</字符为结束)
具体代码如下:
-
-
static String getCode(String str) {
-
int pos = str.indexOf("#include");
-
String res = "";
-
if (pos == -1)
-
return "";
-
boolean isCode = false;
-
for (int i = pos; i < str.length(); i++) {
-
if (str.charAt(i) == ‘<‘ && str.charAt(i + 1) == ‘/‘)
-
break;
-
if (str.charAt(i) == ‘i‘ && str.charAt(i + 1) == ‘n‘
-
&& str.charAt(i + 2) == ‘t‘ && str.charAt(i + 3) == ‘ ‘
-
&& str.charAt(i + 4) == ‘m‘ && str.charAt(i + 5) == ‘a‘
-
&& str.charAt(i + 6) == ‘i‘ && str.charAt(i + 7) == ‘n‘) {
-
isCode = true;
-
}
-
res += str.charAt(i);
-
}
-
if (isCode)
-
return res;
-
else
-
return "";
-
}
5.对获得的代码答案进行编码处理(具体HTML元素符号的换成>
<...等)
然后我们把代码中出现的具有html符号的元素改为我们熟悉的符号
-
-
static String replaceDiv(String str) {
-
String res = "";
-
int len = str.length();
-
for (int i = 0; i < len; i++) {
-
if (i + 3 < len && str.charAt(i) == ‘&‘ && str.charAt(i + 1) == ‘l‘
-
&& str.charAt(i + 2) == ‘t‘ && str.charAt(i + 3) == ‘;‘) {
-
res += ‘<‘;
-
i += 3;
-
} else if (i + 3 < len && str.charAt(i) == ‘&‘
-
&& str.charAt(i + 1) == ‘g‘ && str.charAt(i + 2) == ‘t‘
-
&& str.charAt(i + 3) == ‘;‘) {
-
res += ‘>‘;
-
i += 3;
-
} else if (i + 1 < len && str.charAt(i) == ‘/‘
-
&& str.charAt(i + 1) == ‘n‘) {
-
res += "\\n";
-
i += 1;
-
} else if (i + 4 < len && str.charAt(i) == ‘&‘
-
&& str.charAt(i + 1) == ‘a‘ && str.charAt(i + 2) == ‘m‘
-
&& str.charAt(i + 3) == ‘p‘ && str.charAt(i + 4) == ‘;‘) {
-
res += ‘&‘;
-
i += 4;
-
} else if (i + 5 < len && str.charAt(i) == ‘&‘
-
&& str.charAt(i + 1) == ‘q‘ && str.charAt(i + 2) == ‘u‘
-
&& str.charAt(i + 3) == ‘o‘ && str.charAt(i + 4) == ‘t‘
-
&& str.charAt(i + 5) == ‘;‘) {
-
res += ‘\"‘;
-
i += 5;
-
} else if (str.charAt(i) == ‘&‘ && str.charAt(i + 1) == ‘n‘
-
&& str.charAt(i + 2) == ‘b‘ && str.charAt(i + 3) == ‘s‘
-
&& str.charAt(i + 4) == ‘p‘ && str.charAt(i + 5) == ‘;‘) {
-
res += ‘ ‘;
-
i += 5;
-
} else if (i + 4 < len && str.charAt(i) == ‘&‘
-
&& str.charAt(i + 1) == ‘#‘ && str.charAt(i + 2) == ‘4‘
-
&& str.charAt(i + 3) == ‘3‘ && str.charAt(i + 4) == ‘;‘) {
-
res += ‘+‘;
-
i += 4;
-
} else if (i + 4 < len && str.charAt(i) == ‘&‘
-
&& str.charAt(i + 1) == ‘#‘ && str.charAt(i + 2) == ‘3‘
-
&& str.charAt(i + 3) == ‘9‘ && str.charAt(i + 4) == ‘;‘) {
-
res += ‘\‘‘;
-
i += 4;
-
} else if (i + 3 < len && str.charAt(i) == ‘<‘
-
&& str.charAt(i + 1) == ‘b‘ && str.charAt(i + 2) == ‘r‘
-
&& str.charAt(i + 3) == ‘>‘) {
-
res += "\n";
-
i += 3;
-
-
} else if (i + 4 < len && str.charAt(i) == ‘&‘
-
&& str.charAt(i + 1) == ‘#‘ && str.charAt(i + 2) == ‘1‘
-
&& str.charAt(i + 3) == ‘6‘ && str.charAt(i + 4) == ‘0‘) {
-
res += " ";
-
i += 4;
-
} else
-
res += str.charAt(i);
-
}
-
return res;
-
}
现在所有的准备工作都已经做好了
就剩下向hdu提交了
6.使用http的post请求提交向hdu网站提交代码。
既然想提交 那么我们就要知道当我们点击了submit后发生了什么
post的网页数据是什么
在这里介绍给你一个神器 下载地址我会放在下面
用fiddler抓包,使用java的post请求模拟网页的post数据即可
举个例子:
这就是我提交一道题目后
使用用fiddler抓包 获取的数据
我们可以获得提交的题目是hdu1022
语言就是GCC usercode就是我们代码(url编码)
模拟http的post请求把抓到的数据比着葫芦画瓢再写一遍就好了
尤其是Cookie 重启一次浏览器 就要更改一下Cookie。否则提交不上哦
具体代码如下
-
-
URL postUrl = new URL("http://acm.hdu.edu.cn/submit.php?action=submit");
-
-
HttpURLConnection connection = (HttpURLConnection) postUrl
-
.openConnection();
-
connection.setDoOutput(true);
-
connection.setDoInput(true);
-
-
connection.setRequestMethod("POST");
-
-
-
connection.setUseCaches(false);
-
-
connection.setInstanceFollowRedirects(true);
-
-
-
connection.setRequestProperty("Host", "acm.hdu.edu.cn");
-
connection.setRequestProperty("Connection", "Keep-Alive");
-
connection.setRequestProperty("Content-Length", code.length() + "");
-
connection.setRequestProperty("Pragma", "no-cache");
-
connection.setRequestProperty("Cache-Control", "no-cache");
-
connection
-
.setRequestProperty(
-
"Accept",
-
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
-
connection.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8");
-
-
connection.setRequestProperty("Content-Type",
-
"application/x-www-form-urlencoded");
-
-
connection
-
.setRequestProperty(
-
"User-Agent",
-
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.22 Safari/537.36 SE 2.X MetaSr 1.0");
-
connection.setRequestProperty("DNT", "1");
-
connection.setRequestProperty("Upgrade-Insecure-Requests"," 1");
-
connection.setRequestProperty("Referer",
-
"http://acm.hdu.edu.cn/submit.php?pid=" + problemID);
-
connection.setRequestProperty("Accept-Encoding", "gzip, deflate");
-
connection
-
.setRequestProperty(
-
"Cookie",
-
"exesubmitlang=1; PHPSESSID=vla6d2llv1q25tipnva019stg4; CNZZDATA1254072405=1258731135-1470215877-%7C1470998268");
-
-
-
connection.connect();
-
DataOutputStream out = new DataOutputStream(
-
connection.getOutputStream());
-
-
String urlCode = URLEncoder.encode(code, "utf-8");
-
String content = "check=0&problemid=" + problemID
-
+ "&language=0&usercode=" + urlCode;
-
out.writeBytes(content);
-
out.flush();
-
out.close();
-
BufferedReader reader = new BufferedReader(new InputStreamReader(
-
connection.getInputStream()));
-
reader.close();
-
connection.disconnect();
7.最后提交后进行检测
如果是Accept就执行下一道题目 否则遍历集合中的下一个网址
检查我们提交的代码可以再http://acm.hdu.edu.cn/status.php这里查看
我们只要根据当前题号查找 然后在源代码中再根据正则表达式 判断判断是否Accepted 如果接受了就返回true 否则false
具体怎么做我就不说了 如果你看了上面的肯定能懂。
具体代码如下
-
public static boolean checkRes(int problemID) {
-
String url = "http://acm.hdu.edu.cn/status.php?first=&pid=" + problemID
-
+ "&user=&lang=0&status=0";
-
String msg = Main.sendGet(url);
-
String regex = "red>Accepted.{100,200}1142819049";
-
Pattern p = Pattern.compile(regex);
-
Matcher m = p.matcher(msg);
-
boolean state = m.find();
-
System.out.println(problemID + " " + state);
-
return state;
-
}
好了 大功告成。
奉上一句话。。刷题一时爽,封号就OVER
我的这个账号已经被封了 才刷到5400多到 。。突然发现不能提交了 唉
在登录就是密码错误。。
在这里再给HDU道个歉 对不起,,仅仅是为了学习。希望能接受。
fiddler
神器下载
教你小小JAVA爬虫爬到HDU首页(只为学习)
标签:
原文地址:http://blog.csdn.net/su20145104009/article/details/52198355