httpclient 抓取网页(2021-05-24欢迎访问我的个人网站-广州图书馆)
优采云 发布时间: 2022-04-19 19:18httpclient 抓取网页(2021-05-24欢迎访问我的个人网站-广州图书馆)
2021-05-24
欢迎来到我的个人网站,如果能在GitHub上给网站的源码打个star就更好了。
在构建自己的网站时,我想记录我读过和借过的所有书。大学也爬过自己学校的借阅记录,但是数据库已经被删除了==,只有一张截图。所以你要珍惜你阅读的日子,记录你的借阅记录——广州图书馆,现在代码已经放到服务器上定期运行,结果查看我的网站(关于我)页面。整个代码使用HttpClient,存储在MySql中,定期使用Spring自带的Schedule。下面是爬取的过程。
1.页面跳转过程
一般是进入首页,点击进入登录页面,然后输入账号密码。从表面上看,它似乎并没有什么特别之处。事实上,在模拟登录的时候,并不仅仅是向链接发布请求那么简单。生成的响应将跳转回登录页面或无限制地重定向。
其实就是做单点登录的,如下图,广州图书馆的网址是:,登录的网址是:。网上很多人都很好的解释了原理。您可以阅读此 文章SSO 单点登录。
2.处理方式
解决方法不难,只要先模拟访问首页获取库的session,python获取代码如:session.get(""),打印cookie后如下:
[, , ]
整个登录和抓取过程如下:
这是:
(1)用户先点击广州图书馆首页,获取换站session,然后点击登录界面,解析html,获取lt(自定义参数,类似验证码),单点登录服务器会话。
(2)向目标服务器(单点登录服务器)提交post请求,请求参数包括username(用户名)、password(密码)、event(时间,默认为submit)、lt(自定义request parameters) ,服务器还需要对参数进行校验:refer(源页面)、host(主机信息)、Content-Type(类型)。
(3)打印响应,搜索自己的名字,如果有则表示成功,否则会跳转回登录页面。
(4)使用cookies访问其他页面,这里是借阅历史的爬取,所以访问的页面是:.
这是基本的模拟登录和获取,然后是对面的html的解析,得到书名、书索引等,然后封装成JavaBean,然后存入数据库。(没做过,不知道用什么方法比较好)
3.代码
3.1 在Java中,大部分的httpclients一般都是用来提交http请求的。一、需要导入的httpclient相关包:
org.apache.httpcomponents
httpclient
4.5.3
org.apache.httpcomponents
httpcore
4.4.7
3.2 构建和声明全局变量——上下文管理器,其中context是上下文管理器
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是按session存储的,本地浏览器使用cookies。只要本地不注销,也可以使用本地cookie访问,但是为了达到模拟登录的效果,这里不再赘述。
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)
分类:
技术要点:
相关文章: