声明:本文为原创,转载请注明出处
本文总共三章,前面两章废话吐槽比较多,想看结果的话,直接看第三章(后续会更新,最近忙着毕设呢,毕设也是我自己做的,关于射频卡的,有时间我也放上来,哈哈)。
- 一,系统总体结构
首先吐槽一下,标题取得好水,原谅我是一枚耿直的工科男。系统框图如下所示,简单看一下,对整体有个把握,总体由4个部分组成
上图中,装载URL队列的是先进先出的队列,整个爬虫系统的设计就是基于宽度优先遍历的原则设计的。所以,对于执行整个下载任务的引擎而言,它只是启动一个线程池,然后机械的从队列里面拿出链接,下载网页,然后再将网页中的链接放到队列里面,循环上面的操作。由于每一个站点都有其自身布局的特点,比如特定的编码,特定的URL格式,面向站点的模板需要提供这些特点,以方便爬取效率和自己想要得到的效果。对于一张网页,我们真正关心的,讲个实话,只是一部分数据,所以在模板获取数据之前,是先需要对数据进行过滤,排版等相关处理的,面向数据处理的模型就是为了解决这个问题而产生的。(我去感觉这段话,有种催眠的感觉,发现自己表达能力好差。)
- 二,设计思想及核心流程图
说点题外话,关于爬虫的的实现,网上很多,但是只要你不是我这样的大老粗,你仔细看就会发现,所有的实现基本都是机械抓取URL,最为致命的是抓取的URL还有可能是相对URL。那什么获取个性化数据就有点大海捞针的感觉了。哈哈,自恋一下,本爬虫就可以大海捞针(你也可以当笑话看,否则这玩意太枯燥了)。其实我感觉的话,爬虫的核心无非就两个:一是要能很好的处理URL,二是方便获取想要的数据。至于什么效率,鄙人认为,在这个计算机处理能力飞速提示的年代,不是那么重要。
下面是整个引擎执行流程图:
上图十分清楚的描述了整个引擎的执行流程图,现在一看好像很简单,但是当时写起来,那个问题,不想说了,不利于弘扬社会主义核心价值观,哈哈。至于到底是怎么用我会把代码放出来(留言qq索取也行,githup还没有建仓库呢),有了这个图大家看起来,也方便些。接下来,实在是不想废话了,直接看使用demo。
- 三,实践
正所谓实践是检验真理的唯一标准,这里以抓取阿里巴巴旗下蚂蚁金服的基金数据为例子,进行简单讲解一下。
3.1 定义一个基于该网站的引擎类。此类需要导入我开发的包,然后继承自Spider。Spider有几个函数是用于子类重载的。主要的也就是下面的三个重载子函数.详情看注释
public class AliFundtion extends Spider { private WebClient webClient=new WebClient(); private Pattern HREF=Pattern.compile("href="(.*?)""); public AliFundtion(int maxSize,int threadSize){ super(maxSize,threadSize); initWebOptions(); } private void initWebOptions(){ webClient.setAjaxController(new NicelyResynchronizingAjaxController()); webClient.getOptions().setJavaScriptEnabled(true); webClient.getOptions().setCssEnabled(false); webClient.getOptions().setTimeout(35000); webClient.getOptions().setThrowExceptionOnScriptError(false); } /** * 通过重载这个函数,我们这里只抓取蚂蚁金服首页展示的基金数据,因为它首页包含了所有的基金, * 这个函数决定了URL队列里面到底有哪些链接,是引擎的抓取的来源 * @param html 抓取到的网页 * @param url 该网页对应的URL * @param que URL队列 */ @Override protected void allHrefEnQueue(String html, String url, SpiderQueue que) { if(url.equals("http://www.fund123.cn/fund")){//断定是首页 List<String> hrefs=RegexUtil.getAllMatcher(html,1,HREF); for(String href:hrefs){ String absoUrl=Browser.relative2TrUri(href,url);//转化为绝对路径 if(absoUrl.startsWith("http://www.fund123.cn/matiaria?fundCode")){//这正是我们需要的基金数据 que.enQueue(absoUrl); } } } } /** * 这个函数决定了,通过URL获取网页的方式,对于需要执行js代码的网页而言,重载这个函数是必须得,比如这里就是基于htmlUnit重载了Spider的这个函数 * @param url 即将抓取的URL * @param charset 所用的字符编码 * @return 返回抓取到的数据 * @throws IOException */ @Override synchronized protected String toGetHtmlPage(String url, String charset) throws IOException { HtmlPage page=webClient.getPage(url); return page.asXml(); } /** * 注意这里必须调用父类的close()方法,来释放一些资源 */ @Override protected void close() { super.close(); webClient.close(); } }
3.2 主程序调用步骤
public class Main { public static void main(String[] args) { //step1: 创建一个你自己定义的爬虫引擎,第一个参数表示队列的最大容量,第二个参数表示开启线程池中线程数量 AliFundtion aliFundtion=new AliFundtion(50,6); //step2:定义你自己的站点模板 ICrawlTemplate temp=new AbstractTemplate() { @Override public void crawlValue(String html, String url) { //todo 在这里写下你想做的事,比如将得到的数据持久化到数据库,或者保存到磁盘,其中html表示被数据模型修饰后的数据,url是该html对应的链接 System.out.println(html); } @Override public String getBaseSite() { return "http://www.fund123.cn/fund"; } @Override public String getCharset() { return null; } @Override public boolean filterUrl(String url) { return true; } }; //step3:采用正则表达式进行数据建模 //<_%></_%>这是一对表示这个一个正则表达式的标签 //index 属性 就是该正则表达式需要提取的组 StringBuilder sb=new StringBuilder(); sb.append("基金名称:").append("<_% index="1">").append("<span class="fundmatiaria-title-fundname">(.*?)</span>").append("</_%>"); sb.append("基金代码:").append("<_% index="1">").append("<span class="fundmatiaria-title-fundcode">(.*?)</span>").append("</_%>"); sb.append("基金净值:").append("<_% index="1">").append("<p class="fundmatiaria-fundinfo-value".*?>(.*?)</p>").append("</_%>"); RegexModel model=new RegexModel(sb.toString()); model.getOptions().setAbsoJs(true);//表示将所有js路径转化为绝对路径 model.getOptions().setAbsoImage(true);//表示将所有image路径转化为绝对路径 model.getOptions().setAbsoCss(true);//表示将所有css路径转化为绝对路径 aliFundtion.setModel(model); //step4:下载模板 aliFundtion.downLoadArtcle(temp); } }
3.3 看一下结果:
基金名称:南方原油(QDII-FOF)
基金代码:(501018)
基金净值:1.1502 +1.42% -1.57%
基金名称:广发道琼斯美国石油开发与生产指数(QDII-LOF)A
基金代码:(162719)
基金净值:1.1371 +1.65% +0.04%
基金名称:银华心诚灵活配置混合
基金代码:(005543)
基金净值:0.9507 +1.79% +1.79%