现在在做一个毕设,目的从各个招聘网站上(比如智联招聘)爬取职位信息,并存到自己的数据库中。然后进行分析,去重。最后能利用这些数据给用户推荐职位,并绘制一些诸如职位在城市的分布,薪资情况等等的排名的图表出来。
现在使用到的技术有 SpringMVC + Spring + Hibernate 框架。
分布式采用了比较简单的Hessian。
HTML爬取和分析使用的Jsoup。
数据库MYSql。
前端暂时打算使用Bootstrap 但是还没定是不是自己做,有可能采用修改免费模板的方式。
这是利用以上搭建的环境爬取2940个职位信息的耗时情况。
惨不忍睹。
想问一下在这种架构的情况下如何能提高程序的效率?
以下是爬虫部分的代码:
@Component
public class Spider_ZhiLian implements Runnable{
private WorkDao workDao;
private static Logger logger = Logger.getLogger(Spider_ZhiLian.class);
public Spider_ZhiLian(WorkDao workDao)
{
this.workDao = workDao;
}
public Spider_ZhiLian()
{
}
public void run() {
// TODO Auto-generated method stub
getJobs();
}
public void getJobs()
{
int total = 0;
Calendar a=Calendar.getInstance();
final String YEAR = a.get(Calendar.YEAR)+"-";
List<Work> list = new ArrayList<Work>();
Element errorElements = null;
long startTime = System.currentTimeMillis(); //获取开始时间
long downTime = 0;//下载时间
long thinkTime = 0;//解析时间
long saveTime = 0;//存入数据库时间
for(int t = 0;t<50;t++)
{
list.clear();
try {
long point1start = System.currentTimeMillis(); //下载一个页面的时间
Document document = Jsoup.connect("http://sou.zhaopin.com/jobs/searchresult.ashx?jl=%E9%80%89%E6%8B%A9%E5%9C%B0%E5%8C%BA&isadv=0&sg=91bdb06d4b2c4871a1000b75fe7002b7&p="+t+1).userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31").post();
//System.out.println(document);
long point1end = System.currentTimeMillis(); //下载一个页面的时间
downTime += point1end-point1start;
long point2start = System.currentTimeMillis(); //解析一个页面的时间
Elements companyName = document.select("td.gsmc");//公司
Elements salary = document.select("td.zwyx");//月薪
Elements place = document.select("td.gzdd");//工作地点
Elements name = document.select("td.zwmc");//职位
Elements date = document.select("td.gxsj");//更新时间
Elements infomations = document.select("li.newlist_deatil_two");
//地点:重庆公司性质:股份制企业公司规模:1000-9999人学历:本科
//地点:重庆公司性质:民营公司规模:100-499人学历:不限职位月薪:15001-20000元/月
for(int i = 0;i< companyName.size() ;i++)
{
Work work = new Work();
errorElements = infomations.get(i);
String[] infos = infoSpliter(infomations.get(i).text());
work.setCompanyName(companyName.get(i).text());
work.setName(name.get(i).text());
work.setSalary(salary.get(i).text());
work.setPlace(place.get(i).text());
work.setCompanySize(infos[0]);
work.setDate(Date.valueOf(YEAR+date.get(i).text()));
work.setEducation(infos[1]);
work.setType(2);
work.setUrl(name.get(i).getElementsByTag("a").attr("href"));
total++;
list.add(work);
}
long point2end = System.currentTimeMillis(); //解析一个页面的时间
thinkTime += point2end-point2start;
long point3start = System.currentTimeMillis(); //存入页面的时间
workDao.saveWorkList(list);
long point3end = System.currentTimeMillis(); //存入页面的时间
saveTime += point3end-point3start;
} catch (Exception e) {
e.printStackTrace();
System.out.println(errorElements.text());
}
}
long endTime = System.currentTimeMillis(); //获取开始时间
logger.info("共有 " + total + "个职位,耗时: "+(endTime-startTime)/1000.0 + " 秒。 ");
logger.info("获取HTML耗时 "+downTime/1000.0 + " 秒。 耗时比重: "+ downTime*1.00/(endTime-startTime) *100 + "%");
logger.info("解析HTML耗时 "+thinkTime/1000.0 + " 秒。耗时比重: "+ thinkTime*1.00/(endTime-startTime) *100 + "%");
logger.info("存入数据库耗时 "+saveTime/1000.0 + " 秒。耗时比重: "+ saveTime*1.00/(endTime-startTime) *100 + "%");
logger.info("处理异常耗时 "+(endTime-startTime-saveTime-downTime-thinkTime)/1000.0 + " 秒。耗时比重: "+ (endTime-startTime-saveTime-downTime-thinkTime)*1.00/(endTime-startTime) *100 + "%");
}
//将网站中一串的信息处理成String数组的形式
private String[] infoSpliter(String info)
{
String[] result = new String[2];
String[] temp1 = info.split("公司规模:");
String[] temp2 = null;
if(temp1.length < 2)
{
result[0] = "未知";
}
else
{
temp2 = temp1[1].split("人");
result[0] = temp2[0];//人数(规模)
}
String[] temp3 = info.split("学历:");
String[] temp4 = temp3[1].split("职位月薪:");
result[1] = temp4[0];
return result;
}
}
大家无视我弱智的时间统计方式吧。。。AOP还不太会用。。只能先这么统计一下了。
最左面的电脑(也就是主机)来控制中间三台电脑的爬虫。
中间三台电脑和主机在同一局域网内,三台主机连接互联网爬虫的数据再通过内网传送到主机的数据库上。
我觉得这样的方式应该能提高不少速度。
还有一种想法是在各个爬虫节点上配置数据库,爬虫之后直接存在自己的数据库中,然后主机访问三个爬虫节点的数据库。但是有个问题是数据的重复问题。
很感谢您能看到这里。
大概就是以上的情况,希望有大神能提出宝贵的建议让我的程序提高些效率。不然这样上百万的数据真的会跑到崩溃。
或者不是效率问题,其他方面有好的建议也欢迎提出。
再次感谢!
你的耗时分析里已经指出了问题,“获取HTML耗时”占的比重是90%,再看你的代码,业务逻辑是
并不清楚SSH框架中如何处理这个'''getJobs()'''这个函数,但看起来是单线程的,耗时这么久也就不足为奇了。
所以,应该把下载页面和处理内容两部分的工作分开来。这就是一个生产者-消费者问题了啊:页面下载的功能是生产者,网络IO明显比处理页慢,可以多开几个线程来进行下载页面工作,放入队列里;内容的分析处理部分是消费者,从队列里拿出页面解析就好,看情况要不要多线程。