WebMagic爬虫框架及javaEE SSH框架将数据保存到数据库(二)

关于一些基本内容可查看上一篇博客:http://blog.csdn.net/u013082989/article/details/51176073

一、首先看一下爬虫的内容:

(1)学科类型、课程、课程对应章节、课程对应参考教材(主要是要将课程章节对应到上一级爬取的课程上,还有就是课程教材的爬取比较麻烦,下面会讲到)

课程章节:

课程教材

教材内容

二、实体类的设计:

(1)课程类、课程对应章节类(一对多),课程对应教材类(一对多),关于hibernate映射文件就不说明了。

三、爬取课程及对应章节

(1)与上篇博客一样,实现PageProcessor接口

<strong><span style="font-size:18px;">public class CourseSpider implements PageProcessor</span></strong>

以及其中的方法

(2)分析学科类型,就是li标签下对应一个超链接,学科类型比较少,我是单独写了一个爬虫将其存入数据库的(其实手打都可以....)。主要是下面可以将其作为待爬取链接然后请求。

(3)然后分析课程,以哲学学科为例,链接为:域名+/category/01,但是是有分页的

点击第二页,发现链接为:域名+/category/01/2/24,所以2就对应第二页,24就是前2页的记录数

所以我们可以通过改变url地址方式,加载所有的内容。

(4)分析课程章节,就是一个li标签对应一章节,也比较简单

(5)实现代码:

1、获取所需的service

	private ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
	// 获取service
	ISpiderCourseService spiderCourseService = (ISpiderCourseService) ac.getBean("spiderCourseServiceImpl");
	ISpiderProfessionTypeService spiderProfessionTypeService = (ISpiderProfessionTypeService) ac.getBean("spiderProfessionTypeServiceImpl");
	ISpiderChapterService spiderChapterService = (ISpiderChapterService) ac.getBean("spiderChapterServiceImpl");
	ISpiderDocumentService spiderDocumentService = (ISpiderDocumentService) ac.getBean("spiderDocumentServiceImpl");

2、定义site,可以将setTimeOut设置的长一点,因为我们通过改变url访问的记录条数比较多,否则可能出现错误。

private Site site = Site.me().setRetryTimes(5).setSleepTime(3000).setTimeOut(23000);

3、process方法,满足对应的正则表达式表示进入第几层爬虫,调用对应的方法。

	@Override
	public void process(Page page) {
		// 格式:http://mooc.chaoxing.com/category/01/0/1000
		if (page.getUrl().regex("http://mooc\\.chaoxing\\.com/category/\\d+/\\d/\\d+")
				.toString() != null) {
			System.out.println("第一层");
			crawerCourse(page);
		}
		// 格式:http://mooc.chaoxing.com/course/55672.html
		else if (page.getUrl().regex("http://mooc\\.chaoxing\\.com/course/\\d+\\.html")
				.toString() != null) {
			System.out.println("第二层");
			crawCourseInfo(page);
		}

	}

4、爬取课程信息的方法:

一些解析html的就不说了,我用的xpath,WebMagic还提供了很多解析的方法。

我们将爬取的信息封装成课程对象, 并将课程的url作为待爬取的链接(及第二层),将课程对象放到request中(因为第二层爬取章节,需要找到对应的课程类),设置请求的优先级为1(数越小优先级越高,先爬取第一层,再爬取第二层)。

	/**
	 * 爬去课程信息
	 */
	public void crawerCourse(Page page) {
		// <div class="label">
		// 哲学 </div>

		// 筛选专业类型
		String professionType = page.getHtml()
				.xpath("//div[@class='label']/text()").toString();
		// <li class="ans-slow-anim">
		// <div class="picArea ans-slow-anim"><a href="/course/198413.html"
		// target="_blank">
		// <img
		// src="http://p.ananas.chaoxing.com/star/258_153c/1384413396917gvcrs.jpg"
		// width="178" height="109"></a>
		// </div>
		// <div class="introArea"><a href="/course/198413.html" target="_blank"
		// title="中华传统思想-对话先秦哲学">中华传统思想-对话先秦哲学</a></div>
		// <div class="introArea2" title="万献初 李景林 郭齐勇 夏可君  陈炎   武汉大学">
		// 万献初等
		// 武汉大学
		//
		// </div>
		// </li>
		// 筛选名称
		List<String> courseNameList = page.getHtml()
				.xpath("//div[@class='introArea']/a/html()").all();
		// page.putField("courseNameList", courseNameList);
		// 筛选url
		List<String> courseUrlList = page.getHtml()
				.xpath("//div[@class='introArea']/a/@href").all();
		// page.putField("courseUrlList", courseUrlList);
		// 筛选信息
		List<String> infoList = page.getHtml()
				.xpath("//div[@class='introArea2']/@title").all();
		// page.putField("infoList", infoList);

		if (courseNameList.size() > 0) {
			for (int i = 0; i < courseNameList.size(); i++) {
				SpiderCourse model = new SpiderCourse(courseNameList.get(i)
						.toString().trim(), courseUrlList.get(i).toString()
						.trim(), infoList.get(i).toString(), professionType);
				spiderCourseService.save(model);

				// Request request2=new
				// Request(courseUrlList.get(i)).setPriority(1).putExtra("courseModel",
				// model);
				// page.putField("model", model);
				// 设置优先级为1
				page.addTargetRequest(new Request(courseUrlList.get(i))
						.setPriority(1).putExtra("courseModel", model));
			}
		}
		 List<SpiderProfessionType> list =
		 spiderProfessionTypeService.findAll();
		 for (int j = 2; j < list.size(); j++) {
		 // 设置优先级为0
		 page.addTargetRequest(new Request(list.get(j).getUrl()+"/0/1000")
		 .setPriority(0));
		 }

		// List<String> urlList=new ArrayList<String>();
		// for(int j=2;j<list.size();j++){
		// urlList.add(list.get(j).getUrl()+"/0/1000");
		// }
		// //将后续urls作为请求
		// page.addTargetRequests(urlList);
	}

5、爬取课程对应的章节:

可以通过

page.getRequest().getExtra("courseModel");

得到上级设置的课程对象,每个page中是有一个request的。

	/**
	 * 爬取课程对应的章节
	 */
	public void crawCourseInfo(Page page) {
		/**
		 * 得到上级传来的model,用户保存对应的课程
		 */
		SpiderCourse courseModel = (SpiderCourse) page.getRequest().getExtra(
				"courseModel");
		// <div class="mt10 f33 l g5">
		// <span>木结构设计</span>
		// </div>
		// 筛选课程名
		String courseName = page.getHtml()
				.xpath("//div[@class='mt10 f33 l g5']/span/text()").toString();
		// <li class="mb15 course_section fix">
		// <!--<a class="wh"
		// href="/nodedetailcontroller/visitnodedetail?knowledgeId=789300"
		// target="_blank">-->
		// <a class="wh"
		// href="/nodedetailcontroller/visitnodedetail?knowledgeId=789300">
		// <div class="f16 chapter_index l">1.1</div>
		// <div class="f16 pct80 pr10 r">和的哲学(一)</div>
		// </a>
		// </li>
		/**
		 * 爬取章节
		 */
		// 筛选url
		List<String> chapterUrlList = page
				.getHtml()
				.xpath("//li[@class='mb15 course_section fix']/a[@class='wh']/@href")
				.all();
		// page.putField("chapterUrlList", chapterUrlList);
		// 筛选章节号
		List<String> chapterNumList = page.getHtml()
				.xpath("//div[@class='f16 chapter_index l']/text()").all();
		// page.putField("chapterNumList", chapterNumList);
		// 筛选章节名
		List<String> chapterNameList = page.getHtml()
				.xpath("//div[@class='f16 pct80 pr10 r']/text()").all();
		// page.putField("chapterNameList", chapterNameList);

		if (chapterUrlList.size() > 0) {
			for (int i = 0; i < chapterUrlList.size(); i++) {
				SpiderChapter model = new SpiderChapter(chapterNumList.get(i)
						.toString(), chapterNameList.get(i).toString(),
						chapterUrlList.get(i).toString(), courseName,
						courseModel);
				spiderChapterService.save(model);
			}
		}

	}

这样爬取课程及对应的章节就完成了,后面和爬取参考教材的一块测试。

四、爬取课程对应的参考教材,这个相对复杂一点

(1)分析界面

参考教材的显示是通过一个iframe,嵌套了一个html,尝试和上面一样的方法想获取对应的信息,通过调试发现是获取不到的,它应该是通过js然后拼接的html代码,我们爬虫不会得到js执行过后的html代码,所以就比较麻烦。看网上也有一些工具可以得到js执行过后的html代码,但是肯定会降低爬取的效率。

试着获取一个div下的所有节点信息,发现会得到iframe的信息,我们看到iframe中有一个data属性,对应的是一个json格式的信息,所以它应该是通过解析这个json格式的信息,然后拼接的html代码显示参考教材。(json中的bookname,author等信息是unicode编码,刚开始我还纠结是不是获取后要转为汉字,它就是一个编码方式,不用管,获取到就行了)

还有就是json中的url地址试着访问时不对的,然后分析发送的请求发现url地址也是通过js拼接的

url信息,所以我们获取后再进行处理。分析完毕。

(2)代码:

代码其实并不多,但是分析的过程还是很麻烦的。

		/**
		 * 爬取课程对应的章节文档 ,这个有点特殊,它是一个iframe
		 * 并且通过分析之后得出iframe里有个data属性,是json格式的数据,然后网站再通过js拼接html代码
		 * 汉字采用的是unicode编码
		 */

		// 得到的是json格式的字符串
		// 格式:
		// {"readurl":"http://resapi.chaoxing.com/realRead?dxid=000006873411&ssid=12553309&d=BD6EECD6198FDD693FD0E87F715B5F05",
		// "coverurl":"http://cover.duxiu.com/cover/Cover.dll?iid=6768656B6B696569666F3839393335393236",
		// "bookname":"\u5148\u79e6\u54f2\u5b66",
		// "author":"\u66fe\u4ed5\u793c\u7f16\u8457",
		// "publisher":"\u6606\u660e\u5e02\uff1a\u4e91\u5357\u5927\u5b66\u51fa\u7248\u793e",
		// "publishdate":"2009.09",
		// "id":"ext-gen1223"}

		List<String> allInfoList = page.getHtml().xpath("//iframe/@data").all();

		if (allInfoList.size() > 0) {
			for (int i = 0; i < allInfoList.size(); i++) {
				// String转为json
				JSONObject json = JSONObject.fromObject(allInfoList.get(i)
						.toString());
				String realUrl = json.getString("readurl");
				//http://resapi.chaoxing.com/realRead?dxid=000006873411&ssid=12553309&d=BD6EECD6198FDD693FD0E87F715B5F05
				//连接中realRead替换为innerurl,并加上后缀&unitid=7719&readstyle=4&tp=flip&rotate=true&cpage=1
				realUrl = realUrl.replace("realRead", "innerurl")+ "&unitid=7719&readstyle=4&tp=flip&rotate=true&cpage=1";

				SpiderDocument model = new SpiderDocument(
						json.getString("bookname"), realUrl,
						json.getString("author"), json.getString("publisher"),
						json.getString("publishdate"),
						json.getString("coverurl"), courseModel);
				spiderDocumentService.save(model);
			}
		}

五:测试

信息对应正确。

六、总结

虽然爬虫中遇到了一些麻烦,但我还是挺享受这个过程的,并且也从中学到很多东西。

时间: 2024-10-31 11:19:20

WebMagic爬虫框架及javaEE SSH框架将数据保存到数据库(二)的相关文章

javaEE SSH框架 qq第三方登录及用户绑定

前几天刚申请好域名,下面实现网站的qq第三方登录的功能,javaEE的SSH框架.(一些细节问题没有处理,只是大体上实现) 一:首先说一下需求,第一次使用qq第三方登录的用户需要绑定已有的网站用户名,绑定成功后进入首页.以后再使用qq第三方登录就直接进入网站首页. 二:要想使用qq第三方首先需要申请应用(需要有自己的域名) (1)登录qq互联网站申请应用,http://connect.qq.com/ (2)创建应用 (3)创建好之后还是可以修改的,这里回调地址我用的是域名+back.jsp界面(

[JavaEE] SSH框架笔记_eclipse搭建SSH框架详解

SSH框架是最常用的框架之一,在搭建SSH框架的时候总有人遇到这样,那样的问题.下面我介绍一下SSH框架搭建的全过程. 第一步:准备工作. 下载好eclipse,Struts2,Spring,Hibernate. 1.eclipse:eclipse下载的时候建议下载JavaEE版的eclipse. 当然你也可以下载eclipse-SDK.(下载eclipse-SDK需要下载Web,Tomcat等plugins) 2.Struts2:http://struts.apache.org/downloa

javaEE SSH框架 qq第三方登录及用户绑定(java sdk版)

之前有位朋友用js sdk实现了 SSH框架下的qq第三方登录功能,但是我发现使用js sdk 有些无法克服的安全问题,所以我改用java sdk来实现这个功能! 如图,使用java sdk时,回调地址应设置为一个.action链接.(注意!修改回调地址的话,官方不会及时给你审核通过,有的人修改回调地址后一年 官方都没给他审核通过,这意味着[修改回调地址不如 要重新申请一个域名!重新申请一次网站接入]) 使用官方给定的Sdk4J.jar时 控制台会打印许多log信息,这严重影响项目的运行效率,所

javaEE SSH框架使用ChartDirector绘图

最近做毕设想要在web端显示图表,网上有很多图表的插件,JFreeChart也不错,不过我选择的是ChartDirector. 一.需求:分页显示学生访问对应课程次数的柱状图,(之前我爬取了网站上的一些课程,并记录了用户访问的记录) 二.实现: (1)ChartDirector自带一个jsp文件,复制到项目中,还有将ChartDirector.jar包引入项目中 (2)要显示图表的jsp界面,其中chart1URL和imageMap1是Action层处理好传递过来的数据,分页的代码可以忽略掉,其

scrapy爬虫成长日记之创建工程-抽取数据-保存为json格式的数据

在安装完scrapy以后,相信大家都会跃跃欲试想定制一个自己的爬虫吧?我也不例外,下面详细记录一下定制一个scrapy工程都需要哪些步骤.如果你还没有安装好scrapy,又或者为scrapy的安装感到头疼和不知所措,可以参考下前面的文章安装python爬虫scrapy踩过的那些坑和编程外的思考.这里就拿博客园来做例子吧,抓取博客园的博客列表并保存到json文件. 环境:CentOS 6.0 虚拟机 scrapy(如未安装可参考安装python爬虫scrapy踩过的那些坑和编程外的思考) 1.创建

[JavaEE] SSH框架搭建所需要的包

struts2commons-logging-1.0.4.jar 主要用于日志处理freemarker-2.3.8.jar 模板相关操作需要包ognl-2.6.11.jar ognl表达示所需包,xwork-2.0.7.jar xwork核心包struts2-core-2.0.14.jar struts2核心包struts2-spring-plugin-2.0.14.jar struts2整合spring所需要的包如果还需要整合其它框架或者插件,再导入其它的包 hibernateHibernat

JavaEE SSH框架整合(四) 日志处理Spring结合 log4j、slf4j [转]

1. 加入log4j和slf4j的jar包 2. web.xml: [html] view plaincopyprint? <context-param> <!--log4j配置地址 --> <param-name>log4jConfigLocation</param-name> <!-- <param-value>/WEB-INF/classes/log4j.properties</param-value> --> &l

JavaEE SSH框架整合(四) 日志处理Spring结合 log4j、slf4j

1. 加入log4j和slf4j的jar包 2. web.xml: <context-param> <!--log4j配置地址 --> <param-name>log4jConfigLocation</param-name> <!-- <param-value>/WEB-INF/classes/log4j.properties</param-value> --> <param-value>classpath:l

JavaEE SSH框架整合(二) struts2 加载本地dtd文件,action配置

1. 加载struts2的dtd文件,使struts.xml不用联网就能验证,并在eclipse中有提示 在src下创建struts.xml: <?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPE strutsPUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://strut