印言
之前没有写过爬虫,最近被学长压迫,所以迅速学习了一波爬虫,这个过程十分的痛苦。
之前自己也没有发博客的习惯,- -仿佛发博客是上个世纪的事情,之前也有很多技术学习,但没有放到博客上。
希望以后学了什么技术可以发上来,既加深自己的印象,还帮助了大众。
其实java的爬虫也没有那么难,之前刚刚大一的时候以为爬虫只有python有,十分的low。
本质还是发HTTP请求,最简单的直接爬取页面,对于没有做反爬技术的网站还是很简单的。
只要是用HttpClient这个库基本上就够了,然后解析HTML使用Jsoup。
当然在学习的过程中发现了webmagic的爬虫框架,很庆幸是国人写的。
- 但是感觉那个框架目前对非Http get的请求的支持并不是那么好。(时间坐标2017.11.6)
- 相信这个框架会不断完善。
接下来说一说我爬取过程中遇到的坑。
- 我爬取了我们学校教务处的网站,说教务处,相信绝大多数都是相同的那一套。
- 第一个坑就是编码的坑,教务处编码采用GB2312,HttpClient默认采用UTF-(当然,中间还尝试了OkHttp),相比之下我觉得HttpClient对编码的处理更适合我。
- 第二个坑就是C#的坑,教务处的网站用.Net开发,由于我只懂java,一开始以为那个__viewstate是个不怎么重要的参数,但其实不然,如果post的__viewstate不正确,
返回码虽然是302(登录成功),但是response header里面的location却会把你定位到错误界面。
怎么解决这两个坑呢?
先不着急,我们先来看看怎么发起get,post请求。
CloseableHttpClient client = HttpClients.createDefault();
HttpGet get = new HttpGet("http://www.baidu.com");
CloseableHttpResponse response = client.execute(get);
这样就对百度发起了一次http的get请求。
这个response里面包含了header,页面内容等。
然后怎么获取Header中的信息,和页面内容呢?
String[] cookies = response.getHeaders("Set-Cookie");
String html = Utils.getHtml(response.getEntity.getContent,"GB2312");
这样就可以获得cookie,和html页面内容,当然还有其他方法,稍微看一下API就知道具体有什么方法了,基本从名字就可以看出来时干什么用的了。
然后Utils.getHtml是我自己的一个静态方法,代码如下。
public String getHtml(InputStream inputstream,String encoding)throws IOException{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];// 1K buffer
int len = 0;
while ((len = is.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
is.close();
return new String(bos.toByteArray(), encoding);
}
接下来是Post请求。
post请求你总是要post点东西的嘛,所以先构造Body的。
所以代码如下
HttpPost post = new HttpPost("http://www.baidu.com");
//开始构造Body
List<NameValuePair> postbody = new ArrayList<>();
postbody.add(new BasicNameValuePair("__VIEWSTATE",viewState));
postbody.add(new BasicNameValuePair("username",username));
postbody.add(new BasicNameValuePair("password",password));
postbody.addHeader("User-Agent",user-agent);
//Body构造结束,开始处理编码格式
UrlEncodedFormEntity GB_2312 = new UrlEncodedFormEntity(postbody,"GB2312");
post.setEntity(GB_2312);
//当然还可以给任何一个http使用代理,对我来说使用代理的好处是可以用burpsuite来看httphistory,查看自己发送的请求具体是什么。
post.setConfig(RequestConfig.custom().setProxy(proxy).build());
CloseableResponse postResponse = client.execute(postbody);
然后就拿到postResponse,用Jsoup解析。
String html = Utils.getHtml(postResponse.getEntity().getContext(),"GB2312");
Document document = Jsoup.parse(html);
Elements elements = document.select("input[name=__VIEWSTATE]");
然后就把需要的内容爬下来了。
以上代码基本手写,没有借助IDE,如果有什么小错误根据IDE提示稍微修改一下就可以。
不是说要解决那两个坑的吗?
- 稍微看仔细一点应该就知道,那两个坑已经解决了吧。
- 就到这里吧,如果在看到这篇博客的时候有什么困惑,我的邮箱:solomonchn1@Gmail.com。