Jsoup可以解析请求返回的HTML页面,因为有些页面中的数据不是通过接口的形式返回的,它是在服务器中就已经把数据和页面渲染好了,然后直接返回,用WebDriver的方法可以通过无头浏览器获取网站的页面结构,从而通过Jsoup来解析页面获取数据。
就像这样,接口中并没有返回相应的数据
但是我们可以通过Jsoup的方式获取到HTML页面中的信息,所以使用Jsoup的前提就是需要掌握一些HTML的知识
/**
* 小红书 通过url获取文章
* @param url
* @return
*/
private CompositionResult xiaohongshuCopositionResult(String url) {
CompositionResult compositionResult =null;
// 这里从分享的小红书连接中提取出URL
Matcher m = Pattern.compile("(?i)(http|https)://[^\u4e00-\u9fa5]+").matcher(url);
String realUrl = "";
// 解析url
while(m.find()){
realUrl = m.group();
logger.info(realUrl);
if(realUrl.endsWith(",")) {
realUrl = realUrl.substring(0, realUrl.length() - 1);
logger.info(realUrl);
}
}
Document doc = null;
Map<String,Object> driverMap = null;
try {
// 获取浏览器
driverMap = chromeDriverService.getDriver();
// 发起请求
String chromeDriver = chromeDriverPage(realUrl, TargetPlatformEnums.XIAOHONGSHU,driverMap);
// 用Jsoup进行解析无头浏览器返回的页面信息
doc = Jsoup.parse(chromeDriver);
logger.info(doc.toString());
//这个方法就是获取元素中属性名和值相应的元素,取第一个
Element script = doc.getElementsByAttributeValue("type", "application/ld+json").first();
// 有一些网络语法,JSONObject解析不了,就要先从中替换了解析不了的地方
String dataStr = script.data().trim().replace("@", "");
JSONObject dataObj = JSONObject.parseObject(dataStr);
// 自己封装的方法,用来判断返回值是否为空
Assert.isNotNull(dataObj, ErrorCodeUtil.PARAMETER_NULL);
JSONObject authorObj = dataObj.getJSONObject("author");
Assert.isNotNull(authorObj, ErrorCodeUtil.PARAMETER_NULL);
String authorUrl = authorObj.getString("url");
String[] split = authorUrl.split("/");
String id = split[split.length - 1];
// 通过class名获取元素,通常获取到的是一个数组
Elements nameElement=doc.getElementsByClass("name-detail");
String name = nameElement.get(0).text();
logger.info("名字:"+nameElement.get(0).text());
Elements likeElement=doc.getElementsByClass("like");
String like = likeElement.get(0).text();
logger.info("点赞:"+likeElement.get(0).text());
Elements commentElement=doc.getElementsByClass("comment");
String comment = commentElement.get(0).text();
logger.info("评论:"+commentElement.get(0).text());
Elements starElement=doc.getElementsByClass("star");
String collect = starElement.get(0).text();
logger.info("收藏:"+starElement.get(0).text());
}catch (Exception e) {
logger.error(e.getMessage(),e);
int failNum = (Integer)driverMap.get("failNum");
driverMap.put("failNum", ++failNum);
throw new IllegalParameterException(ErrorCodeUtil.FAILURE_TO_OBTAIN_INFORMATION);
}finally {
// 归还浏览器
chromeDriverService.returnDriver(driverMap);
}
return compositionResult;
}
注意:如果页面是相同的,可以直接通过这种方法爬取大量数据,但如果页面结构不同,则需要根据相应的元素位置做出相应的改变
在爬取B站信息的时候,就遇到了兼容性的问题,有些视频是一个UP主进行制作的,而有些是团队协作的,原本up主的位置是只显示一个人的,而现在会显示一堆人
这样就需要做一个兼容,当然还会有其他各种各样的不同的页面,之后遇到也会在添加的
// 发起请求
String chromeDriver = chromeDriverPage(url, TargetPlatformEnums.BILIBILI,driverMap);
Document doc = Jsoup.parse(chromeDriver);
Element userInfoElement = doc.getElementsByAttributeValueContaining("id", "v_upinfo").first();
// 个人up主
if(userInfoElement != null) {
Elements nameElement=doc.getElementsByClass("name");
name = nameElement.get(0).getElementsByAttributeValueContaining("report-id", "name").text();
logger.info("昵称:"+nameElement.get(0).getElementsByAttributeValueContaining("report-id", "name").text());
// 获取up主的主页链接
homePageUrl = nameElement.get(0).getElementsByAttributeValueContaining("report-id", "name").attr("href");
}else{
// 团队up主
Element memberInfoElement = doc.getElementsByAttributeValueContaining("id", "member-container").first();
if(memberInfoElement != null) {
Element userFirstElement = doc.getElementsByClass("name-text").first();
name = userFirstElement.text();
logger.info("团队第一up昵称:" + name);
// 这里是获取up主的主页链接
homePageUrl = userFirstElement.attr("href");
}else {
throw new IllegalParameterException(ErrorCodeUtil.FAILURE_TO_OBTAIN_INFORMATION);
}
}
关于Jsoup的api网上有很多,这里就不再详细介绍了