**
jsoup爬虫实战详解之新浪
**
今天分享一个之前困扰了一段时间的关于jsoup爬取新浪网页信息的踩坑总结。
在实现以上功能的之前我门首先要了解两个重点:1.关于jsoup的爬取细节以及教程,爬取时所要了解jsoup的相关标签:具体的自己大家感兴趣的可以自行百度去详细了解下对应的教程。
2.第二点就是我们要了解爬取对面网站的页面构造,现在大体分为HTML形式的展示,还有一种是通过js异步加载所呈现页面效果的形式,js异步加载相对而言比较复杂,今天我们着重讲解下以html形式展示的jsoup实战使用,今天就以新浪为网页为例子进行讲解。
第一步:引入相应的pom文件内容:
第二步:了解新浪网页的基础的构造
我们进入新浪网页,例如我们点进到体育分类栏,进入体育分类页面右击查看网页源码,我们可以看到
对应的列表的构造基本是ul>li>a,我们就可以获取到对应标题进入详情的链接
上述我们可以获取对应分类的列表信息,我们随便点一个进入到对应的详情页面继续看下页面的构造情况:
对应的详情的基本结构就是以class为article为主导的基本数据的构造。今天我门就基本讲解将对应的标题内容信息进行抓取为功能的主导实现
上述就是新浪的对应的页面构造,下面我们直接进入业务代码:
1.通过模拟CHROME览器来获取页面的document信息,代码如下
url为对应的抓取的对应的路径信息,useHtmlUnit为是否使用HtmlUnit此处我们可以传值为false。
public static Document getHtmlFromUrl(String url, boolean useHtmlUnit) {
Document document = null;
if (!useHtmlUnit) {
try {
document = Jsoup.connect(url)
// 模拟火狐浏览器
.userAgent("Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)").get();
} catch (Exception e) {
}
} else {
// 模拟CHROME览器
WebClient webClient = new WebClient(BrowserVersion.CHROME);
webClient.getOptions().setJavaScriptEnabled(true);// 1 启动JS
webClient.getOptions().setCssEnabled(false);// 2 禁用Css,可避免自动二次请求CSS进行渲染
webClient.getOptions().setActiveXNative(false);
webClient.getOptions().setRedirectEnabled(true);// 3 启动重定向
webClient.setCookieManager(new CookieManager());// 4 启动cookie管理
webClient.setAjaxController(new NicelyResynchronizingAjaxController());// 5 启动ajax代理
webClient.getOptions().setThrowExceptionOnScriptError(false);// 6 js运行错误时,是否抛出异常
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
webClient.getOptions().setUseInsecureSSL(true);// 忽略ssl认证
webClient.getOptions().setTimeout(10000);// 7 设置超时
/** * 设置代理 ProxyConfig proxyConfig = webClient.getOptions().getProxyConfig(); proxyConfig.setProxyHost(listserver.get(0)); * proxyConfig.setProxyPort(Integer.parseInt(listserver.get(1))); */
HtmlPage htmlPage = null;
try {
htmlPage = webClient.getPage(url);
webClient.waitForBackgroundJavaScript(10000);
webClient.setJavaScriptTimeout(10000);
String htmlString = htmlPage.asXml();
return Jsoup.parse(htmlString);
} catch (Exception e) {
e.printStackTrace();
} finally {
webClient.close();
}
}
return document;
}
第二步核心代码
/** * * @param: @param 对应抓取的路径信息:http://sports.sina.com.cn/假定新浪的体育路径 * @param: @param 对应标签id 自己的对应的标签id,此处代表新浪 * @param: @param 上线数 * @param: @param 对应网页的标签规则:此处我们假定为:ul > li > a * @param: @return 数量标签如果为0则爬取结束 * @return: List<Map<String,String>> */
private static List<Map<String,String>> pullNews(String tagUrl,Integer tag,Integer num,String regex) {
//获取网页
Document html= null;
try {
html = BaseJsoupUtil.getHtmlFromUrl(tagUrl, false);
} catch (Exception e) {
}
List<Map<String,String>> returnList = new ArrayList<>();//定义返回的list
//jsoup获取<a>标签,不同的地址匹配不同的匹配规则
Elements newsATags = null;
//可以理解为上述的,上述我们关于体育的第一个页面的规则基本为:ul > li > a
if(Utils.notBlank(regex)) {
newsATags = html.select(regex);
}else {
System.out.println(tagUrl+"采集规则未设置");
return returnList;
}
//当规则不适用时
if(newsATags.isEmpty()) {
System.out.println(tagUrl+"规则不适用");
return returnList;
}
//从<a>标签中抽取url
List<Map<String,String>> list = new ArrayList<>();//定义存储url的list
//遍历我们体育专题的列表信息来获取通过对应的url获取对应的详情信息
for (Element a : newsATags) {
String articleTitle=a.text();//获取当前标题信息
String url = a.attr("href");//获取对应的标题的路径,也就是我上述所说的跳转对应详情的路径,我们通过进入详情来抓取我们想要的文章标题,图片等信息
if(url.contains("html")) {
if(url.indexOf("http") == -1) {
url = "http:" + url;
}
Map<String,String> map = new HashMap<>();
map.put("url", url);
map.put("title", articleTitle);
list.add(map);
}else {
continue;
}
}
//根据url访问页面获取内容
for(Map<String,String> m :list) {
Document newsHtml = null;
try {
//通过模拟器获取对应路径下的html信息,此处的url就是对应的详情的链接,通过模拟器获取对应的页面信息内容
newsHtml = BaseJsoupUtil.getHtmlFromUrl(m.get("url"), false);
String title=m.get("title");//获取标题
Elements newsContent=null;
String data;
newsContent=newsHtml.select(".article");//这里就是我上述讲解信息的第二个说的jsoup通过标签来进行信息抓取,上述的为class为article的抓取规则
if(newsContent!=null) {
String content=newsContent.toString();//获取对应的内容信息
//篇幅太短的文章不需要
if(content.length() < 200) {
//过滤过长的文章
break;
}
//时间过滤
if(Utils.isBlank(newsHtml.select(".date").text())) {
data=newsHtml.select(".time").text().replaceAll("年", "-").replaceAll("月", "-").replaceAll("日", "");
}else{
data=newsHtml.select(".date").text().replaceAll("年", "-").replaceAll("月", "-").replaceAll("日", "");
}
//指定路径时间过滤
if(tagUrl.equals("http://collection.sina.com.cn/")) {
data=newsHtml.select(".titer").text().replaceAll("年", "-").replaceAll("月", "-").replaceAll("日", "");
}else if(tagUrl.equals("https://finance.sina.com.cn/stock/") || tagUrl.equals("http://blog.sina.com.cn/lm/history/")) {
data=newsHtml.select(".time SG_txtc").text().replaceAll("年", "-").replaceAll("月", "-").replaceAll("日", "").replaceAll("(", "").replaceAll(")", "");
}
//获取到图片信息
List<String> imgSrcList = BaseJsoupUtil.getImgSrcList(content);
String coverImg = "";
if(!imgSrcList.isEmpty()) {
if(num == 0) {
break;//已达设定的采集数量上限
}
num --;
for(String url : imgSrcList){
String imgUrl = BaseJsoupUtil.downloadUrl(url.indexOf("http") == -1?"http:" + url:url);
content = Utils.isBlankStr(content)?content:content.replace(url, imgUrl);
if(Utils.isBlank(coverImg))coverImg = imgUrl.replace(FileConst.QINIU_FILE_HOST+"/", "");
}
//获取到我们想要的东西封装到map里面,这样就基本结束拉
Map<String,String> map = new HashMap<>();
map.put("title", title);//标题
map.put("date", data);//文章创建时间
map.put("content", HtmlCompressor.compress(content));//文章内容
map.put("tag", tag.toString());//标签id
map.put("coverImg", coverImg);//文章封面图
map.put("url", m.get("url"));//url
returnList.add(map);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return returnList;
}
上述就是jsoup抓取的基本逻辑,整体的总结就是熟悉对应jsoup的标签使用教程,想要抓取页面的具体规则,知道了这些基本就可以结合自己的业务逻辑来进行信息获取,这里关于新浪的抓取我们只做技术交流,希望大家不要用于商业使用。好了,今天就到这里了,后期继续分享自己的踩坑记录,有什么问题的可以留言。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/38568.html