欢迎访问我的个人网站,要是能在GitHub上对网站源码给个star就更好了。

搭建自己的网站的时候,想把自己读过借过的书都想记录一下,大学也做过自己学校的借书记录的爬取,但是数据库删掉了==,只保留一张截图。所以还是要好好珍惜自己阅读的日子吧,记录自己的借书记录——广州图书馆,现在代码已经放在服务器上定时运行,结果查看我的网站(关于我)页面。整个代码采用HttpClient,存储放在MySql,定时使用Spring自带的Schedule,下面是抓取的过程。

1.页面跳转过程

一般都是进入首页http://www.gzlib.gov.cn/,点击进登陆页面,然后输入账号密码。表面上看起来没什么特别之处,实际上模拟登陆的时候不仅仅是向链接post一个请求那么简单,得到的response要么跳回登陆页面,要么无限制重定向。

事实上,它做了单点登录,如下图,广州图书馆的网址为:www.gzlib.gov.cn,而登陆的网址为:login.gzlib.gov.cn。原理网上很多人都讲的很好了,可以看看这篇文章SSO单点登录

2.处理方法

解决办法不难,只要先模拟访问一下首页即可获取图书馆的session,python的获取代码如:session.get("http://www.gzlib.gov.cn/"),打印cookie之后如下:

  1. [<Cookie JSESSIONID=19E2DDED4FE7756AA9161A52737D6B8E for .gzlib.gov.cn/>, <Cookie JSESSIONID=19E2DDED4FE7756AA9161A52737D6B8E for www.gzlib.gov.cn/>, <Cookie clientlanguage=zh_CN for www.gzlib.gov.cn/>]

整个登陆抓取的流程如下:

即:

(1)用户先点击广州图书馆的首页,以获取改网址的session,然后点击登录界面,解析html,获取lt(自定义的参数,类似于验证码),以及单点登录服务器的session。

(2)向目标服务器(单点登录服务器)提交post请求,请求参数中包含username(用户名),password(密码),event(时间,默认为submit),lt(自定义请求参数),同时服务端还要验证的参数:refer(来源页面),host(主机信息),Content-Type(类型)。

(3)打印response,搜索你自己的名字,如果有则表示成功了,否则会跳转回登陆页面。

(4)利用cookie去访问其他页面,此处实现的是对借阅历史的抓取,所以访问的页面是:http://www.gzlib.gov.cn/member/historyLoanList.jspx。

基本的模拟登陆和获取就是这些,之后还有对面html的解析,获取书名、书的索引等,然后封装成JavaBean,再之后便是保存入数据库。(去重没有做,不知道用什么方式比较好)

3.代码

3.1 Java中,一般用来提交http请求的大部分用的都是httpclient,首先,需要导入的httpclient相关的包:

  1. <dependency>
  2. <groupId>org.apache.httpcomponents</groupId>
  3. <artifactId>httpclient</artifactId>
  4. <version>4.5.3</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.apache.httpcomponents</groupId>
  8. <artifactId>httpcore</artifactId>
  9. <version>4.4.7</version>
  10. </dependency>

3.2 构建声明全局变量——上下文管理器,其中context为上下文管理器

  1. public class LibraryUtil {
  2. private static CloseableHttpClient httpClient = null;
  3. private static HttpClientContext context = null;
  4. private static CookieStore cookieStore = null;
  5. static {
  6. init();
  7. }
  8. private static void init() {
  9. context = HttpClientContext.create();
  10. cookieStore = new BasicCookieStore();
  11. // 配置超时时间
  12. RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(12000).setSocketTimeout(6000)
  13. .setConnectionRequestTimeout(6000).build();
  14. // 设置默认跳转以及存储cookie
  15. httpClient = HttpClientBuilder.create()
  16. .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
  17. .setRedirectStrategy(new DefaultRedirectStrategy()).setDefaultRequestConfig(requestConfig)
  18. .setDefaultCookieStore(cookieStore).build();
  19. }
  20. ...

3.3 声明一个get函数,其中header可自定义,此处不需要,但是保留着,做成一个通用的吧。

  1. public static CloseableHttpResponse get(String url, Header[] header) throws IOException {
  2. HttpGet httpget = new HttpGet(url);
  3. if (header != null && header.length > 0) {
  4. httpget.setHeaders(header);
  5. }
  6. CloseableHttpResponse response = httpClient.execute(httpget, context);//context用于存储上下文
  7. return response;
  8. }

3.4 访问首页以获得session,服务器上会话是使用session存储的,本地浏览器使用的是cookie,只要本地不退出,那么使用本地的cookie来访问也是可以的,但是为了达到模拟登陆的效果,这里就不再阐述这种方式。

  1. CloseableHttpResponse homeResponse = get("http://www.gzlib.gov.cn/", null);
  2. homeResponse.close();

此时,如果打印cookie,可以看到目前的cookie如下:

  1. <RequestsCookieJar[
  2. <Cookie JSESSIONID=54702A995ECFC684B192A86467066F20 for .gzlib.gov.cn/>,
  3. <Cookie JSESSIONID=54702A995ECFC684B192A86467066F20 for www.gzlib.gov.cn/>,
  4. <Cookie clientlanguage=zh_CN for www.gzlib.gov.cn/>]>

3.5 访问登陆页面,获取单点登录服务器之后的cookie,解析网页,获取自定义参数lt。这里的解析网页使用了Jsoup,语法和python中的BeautifulSoup中类似。

  1. String loginURL = "http://login.gzlib.gov.cn/sso-server/login?service=http%3A%2F%2Fwww.gzlib.gov.cn%2Flogin.jspx%3FreturnUrl%3Dhttp%253A%252F%252Fwww.gzlib.gov.cn%252F%26locale%3Dzh_CN&appId=www.gzlib.gov.cn&locale=zh_CN";
  2. CloseableHttpResponse loginGetResponse = get(loginURL, null);
  3. String content = toString(loginGetResponse);
  4. String lt = Jsoup.parse(content).select("form").select("input[name=lt]").attr("value");
  5. loginGetResponse.close();

此时,再次查看cookie,多了一个(www.gzlib.gov.cn/sso-server):

  1. <RequestsCookieJar[
  2. <Cookie JSESSIONID=54702A995ECFC684B192A86467066F20 for .gzlib.gov.cn/>,
  3. <Cookie JSESSIONID=54702A995ECFC684B192A86467066F20 for www.gzlib.gov.cn/>,
  4. <Cookie clientlanguage=zh_CN for www.gzlib.gov.cn/>,
  5. <Cookie JSESSIONID=9918DDF929757B244456D4ECD2DAB2CB for www.gzlib.gov.cn/sso-server/>]>

3.6 声明一个post函数,用来提交post请求,其中提交的参数默认为

  1. public static CloseableHttpResponse postParam(String url, String parameters, Header[] headers)
  2. throws IOException {
  3. System.out.println(parameters);
  4. HttpPost httpPost = new HttpPost(url);
  5. if (headers != null && headers.length > 0) {
  6. for (Header header : headers) {
  7. httpPost.addHeader(header);
  8. }
  9. }
  10. List<NameValuePair> nvps = toNameValuePairList(parameters);
  11. httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
  12. CloseableHttpResponse response = httpClient.execute(httpPost, context);
  13. return response;
  14. }

3.7 登陆成功后,如果没有声明returnurl,即登录链接为(http://login.gzlib.gov.cn/sso-server/login),那么只是会显示成功登录的页面:

后台应该是定义了一个service用来进行链接跳转的,想要获取登录成功之后的跳转页面可修改service之后的链接,这里将保持原始状态。此时,查看cookie结果如下:

  1. <RequestsCookieJar[
  2. <Cookie JSESSIONID=54702A995ECFC684B192A86467066F20 for .gzlib.gov.cn/>,
  3. <Cookie JSESSIONID=54702A995ECFC684B192A86467066F20 for www.gzlib.gov.cn/>,
  4. <Cookie clientlanguage=zh_CN for www.gzlib.gov.cn/>,
  5. <Cookie CASTGC=TGT-198235-zkocmYyBP6c9G7EXjKyzgKR7I40QI4JBalTkrnr9U6ZkxuP6Tn for www.gzlib.gov.cn/sso-server>,
  6. <Cookie JSESSIONID=9918DDF929757B244456D4ECD2DAB2CB for www.gzlib.gov.cn/sso-server/>]>

其中,出现CASTGC表明登陆成功了,可以使用该cookie来访问广州图书馆的其他页面,在python中是直接跳转到其他页面,而在java使用httpclient过程中,看到的并不是直接的跳转,而是一个302重定向,打印Header之后结果如下图:

认真研究一下链接,就会发现服务器相当于给了一张通用票ticket,即:可以使用该ticket访问任何页面,而returnUrl则是返回的页面。这里我们直接访问该重定向的url。

  1. Header header = response.getHeaders("Location")[0];
  2. CloseableHttpResponse home = get(header.getValue(), null);

然后打印页面,即可获取登陆之后跳回的首页。

3.8 解析html

获取session并跳回首页之后,再访问借阅历史页面,然后对结果进行html解析,python中使用了BeautifulSoup,简单而又实用,java中的jsoup也是一个不错的选择。

  1. String html = getHTML();
  2. Element element = Jsoup.parse(html).select("table.jieyue-table").get(0).select("tbody").get(0);
  3. Elements trs = element.select("tr");
  4. for (int i = 0; i < trs.size(); i++) {
  5. Elements tds = trs.get(i).select("td");
  6. System.out.println(tds.get(1).text());
  7. }

输出结果:

  1. 企业IT架构转型之道
  2. 大话Java性能优化
  3. 深入理解Hadoop
  4. 大话Java性能优化
  5. Java EE开发的颠覆者:Spring Boot实战
  6. 大型网站技术架构:核心原理与案例分析
  7. Java性能权威指南
  8. Akka入门与实践
  9. 高性能网站建设进阶指南:Web开发者性能优化最佳实践:Performance best practices for Web developers
  10. Java EE开发的颠覆者:Spring Boot实战
  11. 深入理解Hadoop
  12. 大话Java性能优化

点击查看源码

总结

目前,改代码已经整合进个人网站之中,每天定时抓取一次,但是仍有很多东西没有做(如分页、去重等),有兴趣的可以研究一下源码,要是能帮忙完善就更好了。感谢Thanks♪(・ω・)ノ。整个代码接近250行,当然...包括了注释,但是使用python之后,也不过25行=w=,这里贴一下python的源码吧。同时,欢迎大家访问我的个人网站,也欢迎大家能给个star

  1. import urllib.parse
  2. import requests
  3. from bs4 import BeautifulSoup
  4. session = requests.session()
  5. session.get("http://www.gzlib.gov.cn/")
  6. session.headers.update(
  7. {"Referer": "http://www.gzlib.gov.cn/member/historyLoanList.jspx",
  8. "origin": "http://login.gzlib.gov.cn",
  9. 'Content-Type': 'application/x-www-form-urlencoded',
  10. 'host': 'www.gzlib.gov.cn',
  11. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'
  12. }
  13. )
  14. baseURL = "http://login.gzlib.gov.cn/sso-server/login"
  15. soup = BeautifulSoup(session.get(baseURL).text, "html.parser")
  16. lt = soup.select("form")[0].find(attrs={'name': 'lt'})['value']
  17. postdict = {"username": "你的身份证",
  18. "password": "密码(默认为身份证后6位)",
  19. "_eventId": "submit",
  20. "lt": lt
  21. }
  22. postdata = urllib.parse.urlencode(postdict)
  23. session.post(baseURL, postdata)
  24. print(session.get("http://www.gzlib.gov.cn/member/historyLoanList.jspx").text)

广州图书馆借阅抓取——httpClient的使用的更多相关文章

  1. [Java]使用HttpClient实现一个简单爬虫,抓取煎蛋妹子图

    第一篇文章,就从一个简单爬虫开始吧. 这只虫子的功能很简单,抓取到”煎蛋网xxoo”网页(http://jandan.net/ooxx/page-1537),解析出其中的妹子图,保存至本地. 先放结果 ...

  2. 使用HttpClient 4.3.4 自动登录并抓取中国联通用户基本信息和账单数据,GET/POST/Cookie

    一.什么是HttpClient? HTTP 协议可能是现在 Internet 上使用得最多.最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源.虽然在 JDK 的 ...

  3. HttpClient 4.x 执行网站登录并抓取网页的代码

    HttpClient 4.x 的 API 变化还是很大,这段代码可用来执行登录过程,并抓取网页. HttpClient API 文档(4.0.x), HttpCore API 文档(4.1) pack ...

  4. 使用java开源工具httpClient及jsoup抓取解析网页数据

    今天做项目的时候遇到这样一个需求,需要在网页上展示今日黄历信息,数据格式如下 公历时间:2016年04月11日 星期一 农历时间:猴年三月初五 天干地支:丙申年 壬辰月 癸亥日 宜:求子 祈福 开光 ...

  5. HttpClient抓取网页内容简单介绍

    版本HttpClient3.1 1.GET方式 第一步.创建一个客户端,类似于你用浏览器打开一个网页 HttpClient httpClient = new HttpClient(); 第二步.创建一 ...

  6. 利用HttpClient抓取话费详单等信息

    由于项目需要,需要获取授权用户的在运营商(中国移动.中国联通.中国电信)那里的个人信息.话费详单.月汇总账单信息(需要指出的是电信用户的个人信息无法从网上营业厅获取).抓取用户信息肯定是要模仿用户登录 ...

  7. HTTPCLIENT抓取网页内容

    通过httpclient抓取网页信息. public class SnippetHtml{ /** * 通过url获取网站html * @param url 网站url */ public Strin ...

  8. HttpClient+Jsoup 抓取网页信息(网易贵金属为例)

    废话不多说直接讲讲今天要做的事. 利用HttpClient和Jsoup技术抓取网页信息.HttpClient是支持HTTP协议的客户端编程工具包,并且它支持HTTP协议. jsoup 是一款基于 Ja ...

  9. HttpClient(一)HttpClient抓取网页基本信息

    一.HttpClient简介 HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的.最新的.功能丰富的支持 HTTP 协议的客户端编程工具包, 并且它支 ...

随机推荐

  1. AmpLab Tachyon and Shark update

    一个开源的文件系统,拿来主义,先收藏,用得到细品. 简介:https://www.youtube.com/watch?v=cAZ624-69PQ 官网:http://tachyon-project.o ...

  2. css预处理器less和scss之less介绍(一)

    第一次发的标题有误,重发一遍,抱歉了 一.less基础语法 1.声明变量:@变量名:变量值 使用变量:@变量名 例如 @color : #ff0000; @length : 100px; #div1{ ...

  3. 团队作业8——Beta 阶段冲刺1st day

    一.今日站立式会议照片 二.每个人的工作 (1) 昨天已完成的工作: 今天是冲刺的第一天,昨天完成的是团队成员任务的分配 (2) 今天计划完成的工作: 界面的完善 (3) 工作中遇到的困难: 对于界面 ...

  4. 201521123083《Java程序设计》第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己 ...

  5. 201521123071 《JAVA程序设计》第六周学习总结

    第6周-接口.内部类与Swing 1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多 ...

  6. Java中如何引入结对编程

    引自微信: 很多同学说: 我程序写得好,ACM比赛能得分, 就好了,软件工程讲的那些有用么? 有些学校的 <软件工程>课,由于要求太简单,反而不能说明软件工程的价值. 其实好办, 让学生结 ...

  7. 201521123010 《Java程序设计》第12周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student对象(属性:int id, String name,int age,doubl ...

  8. openfire:Openfire源代码在eclipse中的运行配置 + 与spark结合进行二次开发

    1.下载源代码:http://www.igniterealtime.org/downloads/source.jsp 2.把源代码解压出的openfire_src文件夹放至eclipse workpl ...

  9. json:JSONObject包的具体使用(JSONObject-lib包是一个beans,collections,maps,java arrays和xml和JSON互相转换的包)

    1.JSONObject介绍 JSONObject-lib包是一个beans,collections,maps,java arrays和xml和JSON互相转换的包. 2.下载jar包 http:// ...

  10. 多线程面试题系列(12):多线程同步内功心法——PV操作上

    上面的文章讲解了在Windows系统下实现多线程同步互斥的方法,为了提高在实际问题中分析和思考多个线程之间同步互斥问题的能力,接下来将讲解PV操作,这也是操作系统中的重点和难点.本文将会先简要介绍下P ...