c httpclient抓取网页(广州图书馆处理方法 )
优采云 发布时间: 2021-10-09 09:49c httpclient抓取网页(广州图书馆处理方法
)
欢迎访问我的个人网站,如果你能在GitHub上给网站的源代码一个star就更好了。
当我建立自己的网站时,我想记录我所有阅读和借阅的书籍。大学也爬了我学校的图书馆记录,但是数据库被删了==只保留了一个。截图。所以你要珍惜阅读的日子,记录你的借阅记录——广州图书馆。现在代码已经放在服务器上可以正常运行了。结果,检查我的网站(关于我)页面。整个代码使用HttpClient,存储在MySql中,定期使用Spring自带的Schedule。以下是爬取过程。
1.页面跳转过程
一般是进入首页,点击进入登录页面,然后输入账号密码。从表面上看,并没有什么特别之处。实际上,在模拟登录时,并不只是向链接发布请求那么简单。获得的响应要么跳回登录页面,要么不受限制地重定向。
其实是做单点登录的,如下图,广州图书馆网址是:,登录网址是:。原理网上很多人讲的很好,可以看看这篇文章SSO单点登录。
2.如何处理
解决方法不难,只要访问模拟的主页获取库会话,python的获取代码如:session.get(""),打印cookie后如下:
[, , ]
整个登录和抓包流程如下:
即:
(1) 用户首先点击广州图书馆首页获取修改后的URL的session,然后点击登录界面,解析html,获取lt(自定义参数,类似验证码),和单点登录服务器会话。
(2)向目标服务器(单点登录服务器)提交post请求,请求参数包括username(用户名)、password(密码)、event(时间,默认为submit)、lt(自定义请求) parameters) 同时服务器要验证的参数:refer(源页面)、host(主机信息)、Content-Type(类型)。
(3)打印响应,搜索自己的名字,如果有就成功,否则会跳回登录页面。
(4)使用cookies访问其他页面,这里实现的是抓取借阅历史,所以访问的页面是:。
这就是基本的模拟登录和检索。之后就是对html的解析,书名的检索,书的索引等,然后封装成JavaBean,再存入数据库。(我没有做繁重的工作,不知道哪种方式更好)
3.代码
3.1 Java中一般使用httpclient来提交http请求。首先是需要导入的httpclient相关包:
org.apache.httpcomponents
httpclient
4.5.3
org.apache.httpcomponents
httpcore
4.4.7
3.2 构建并声明全局变量-上下文管理器,其中上下文为上下文管理器
public class LibraryUtil {
private static CloseableHttpClient httpClient = null;
private static HttpClientContext context = null;
private static CookieStore cookieStore = null;
static {
init();
}
private static void init() {
context = HttpClientContext.create();
cookieStore = new BasicCookieStore();
// 配置超时时间
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(12000).setSocketTimeout(6000)
.setConnectionRequestTimeout(6000).build();
// 设置默认跳转以及存储cookie
httpClient = HttpClientBuilder.create()
.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
.setRedirectStrategy(new DefaultRedirectStrategy()).setDefaultRequestConfig(requestConfig)
.setDefaultCookieStore(cookieStore).build();
}
...
3.3 声明一个get函数,可以自定义header。这里不需要它,但保留它并使其成为通用目的。
public static CloseableHttpResponse get(String url, Header[] header) throws IOException {
HttpGet httpget = new HttpGet(url);
if (header != null && header.length > 0) {
httpget.setHeaders(header);
}
CloseableHttpResponse response = httpClient.execute(httpget, context);//context用于存储上下文
return response;
}
3.4 访问主页获取会话。服务器上的会话是使用 session 存储的。本地浏览器使用 cookie。只要不在本地注销,也可以使用本地cookies来访问,但是为了达到模拟登录的效果,这里就不解释了。
CloseableHttpResponse homeResponse = get("http://www.gzlib.gov.cn/", null);
homeResponse.close();
此时,如果打印cookie,可以看到当前cookie如下:
3.5 访问登录页面,获取单点登录服务器背后的cookie,解析网页,获取自定义参数lt。这里的解析网页使用的是Jsoup,语法类似于python中的BeautifulSoup。
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";
CloseableHttpResponse loginGetResponse = get(loginURL, null);
String content = toString(loginGetResponse);
String lt = Jsoup.parse(content).select("form").select("input[name=lt]").attr("value");
loginGetResponse.close();
此时,再次检查cookie,多一个():
3.6 声明一个post函数提交post请求,提交的参数默认为
public static CloseableHttpResponse postParam(String url, String parameters, Header[] headers)
throws IOException {
System.out.println(parameters);
HttpPost httpPost = new HttpPost(url);
if (headers != null && headers.length > 0) {
for (Header header : headers) {
httpPost.addHeader(header);
}
}
List nvps = toNameValuePairList(parameters);
httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost, context);
return response;
}
3.7 登录成功后,如果没有声明returnurl,即登录链接为(),则只显示登录成功的页面:
后端应定义链接重定向服务。如果想在登录成功后得到重定向页面,可以修改服务后的链接,这里会保持原来的状态。此时查看cookie的结果如下:
其中CASTGC的出现表示登录成功,可以使用cookie访问广州图书馆的其他页面。在python中是直接跳转到其他页面,但是在java中使用httpclient的过程中,看到的并不是直接跳转。,但是一个302重定向,打印Header后的结果如下:
仔细研究一下链接,你会发现服务器就相当于给了一张普通的票券,即可以使用该票券访问任何页面,而returnUrl就是返回的页面。这里我们直接访问重定向的url。
Header header = response.getHeaders("Location")[0];
CloseableHttpResponse home = get(header.getValue(), null);
然后打印页面,得到登录后跳转的首页。
3.8 解析 html
获取session后跳回首页,访问借阅历史页面,然后在html中解析结果。在python中使用了BeautifulSoup,简单实用,java中的jsoup也是不错的选择。
String html = getHTML();
Element element = Jsoup.parse(html).select("table.jieyue-table").get(0).select("tbody").get(0);
Elements trs = element.select("tr");
for (int i = 0; i < trs.size(); i++) {
Elements tds = trs.get(i).select("td");
System.out.println(tds.get(1).text());
}
输出结果:
企业IT架构转型之道
大话Java性能优化
深入理解Hadoop
大话Java性能优化
Java EE开发的颠覆者:Spring Boot实战
大型网站技术架构:核心原理与案例分析
Java性能权威指南
Akka入门与实践
高性能网站建设进阶指南:Web开发者性能优化最佳实践:Performance best practices for Web developers
Java EE开发的颠覆者:Spring Boot实战
深入理解Hadoop
大话Java性能优化
点击查看源代码
总结
目前修改后的代码已经集成到个人网站中,每天抓一次,但是还有很多事情没有做(比如分页、去重等)。如果你有兴趣,你可以研究源代码,如果你能帮助改进它。甚至更好。谢谢♪(・ω・)ノ。整个代码接近250行,当然……包括注释,但是使用python后,只有25行=w=,这里是python源代码。同时欢迎大家访问我的个人网站,也欢迎大家给个star。
import urllib.parse
import requests
from bs4 import BeautifulSoup
session = requests.session()
session.get("http://www.gzlib.gov.cn/")
session.headers.update(
{"Referer": "http://www.gzlib.gov.cn/member/historyLoanList.jspx",
"origin": "http://login.gzlib.gov.cn",
'Content-Type': 'application/x-www-form-urlencoded',
'host': 'www.gzlib.gov.cn',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'
}
)
baseURL = "http://login.gzlib.gov.cn/sso-server/login"
soup = BeautifulSoup(session.get(baseURL).text, "html.parser")
lt = soup.select("form")[0].find(attrs={'name': 'lt'})['value']
postdict = {"username": "你的*敏*感*词*",
"password": "密码(默认为*敏*感*词*后6位)",
"_eventId": "submit",
"lt": lt
}
postdata = urllib.parse.urlencode(postdict)
session.post(baseURL, postdata)
print(session.get("http://www.gzlib.gov.cn/member/historyLoanList.jspx").text)