一、webmagic入门程序(原理图)

使用方法
1)创建工程
2)添加jar包

<dependencies><!--WebMagic--><dependency><groupId>us.codecraft</groupId><artifactId>webmagic-core</artifactId><version>0.7.3</version></dependency><dependency><groupId>us.codecraft</groupId><artifactId>webmagic-extension</artifactId><version>0.7.3</version></dependency><!--WebMagic对布隆过滤器的支持--><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>16.0</version></dependency></dependencies>注意:0.7.3版本对SSL的并不完全,如果是直接从Maven中央仓库下载依赖,在爬取只支持SSL v1.2的网站会有SSL的异常抛出。
解决方案:
1.等作者的0.7.4的版本发布
2.直接从github上下载最新的代码,安装到本地仓库课堂提供的本地仓库中是已经修复完成的,可以直接使用
3)创建一个PageProcess对象,需要实现PageProcessor接口创建实现类。
4)在实现类中实现页面解析的业务逻辑。和设置解析参数
public class MyPageProcessor implements PageProcessor {/*** 页面解析的业务逻辑* @param page 下载结果封装到Page对象中*/public void process(Page page) {//抓取传智播客首页打印htmlHtml html = page.getHtml();String strHtml = html.toString();//把解析结果传递给pipeline/*ResultItems resultItems = page.getResultItems();resultItems.put("html", strHtml);*/page.putField("html", strHtml);Selectable url = page.getUrl();}/*** 抓取站点信息的参数配置* 抓取的频率* 超时时间* 编码格式* 。。。* @return*/public Site getSite() {//没有设置参数,使用默认参数return Site.me();}
5)创建一个main方法,在方法中初始化爬虫并启动。
public static void main(String[] args) {Spider.create(new MyPageProcessor())//设置起始的url.addUrl("http://www.itcast.cn")//启动爬虫//同步方法,在当前线程中启动爬虫//.run();//异步方法,创建新的线程启动爬虫.start();}

二、组件介绍
1、Downloader组件
下载器组件,从互联网现在html页面,并封装成Page对象,传递给PageProcess组件。
就是使用HttpClient实现。
如果没有特殊需求,此组件无需自定义。
2、PageProcess组件
爬虫的核心组件,PageProcessor负责解析页面,抽取有用信息,以及发现新的链接,使用爬虫时,此组件 必须自定义。
1)Site
站点参数的配置。
抓取的间隔时间
超时时间
编码格式
UserAgent

一般情况下使用默认参数即可。
返回一个Site对象,使用Site.me();

具体修改代码参照:
private Site site = Site.me().setCharset("UTF-8")//编码.setSleepTime(1)//抓取间隔时间.setTimeOut(1000*10)//超时时间.setRetrySleepTime(3000)//重试时间.setRetryTimes(3);//重试次数


2)Page,可以理解为分发器,把自己内部的属性,分发给响应组件。
Html:Downloader组件抓取的页面封装成Html对象。也是一个Selectable对象
url:当前页面对应的url地址,是一个Selectable对象
ResultItems:从PageProcess向pipeline传递数据的对象。
本质上就是一个map
Request:一个Request就是一个url。
page对象:
addTargetRequest:向队列中添加一个url
addTargetRequests:向队列中批量添加url

3)Selectable对象-- Html对象支持使用Jsoup原生apicss选择器解析页面:css()、$()使用xpath解析页面:xpath()解析xml的一种方法。使用正则表达式regex()解析页面不推荐使用正则表达式。推荐使用css选择器。

*3.正则表达式
正则表达式则是一种通用的文本抽取语言。在这里一般用于获取url地址。
正则表达式学习难度要大一些,大家可以参考课堂资料《正则表达式系统教程.CHM》
下面的例子就是获取https://www.jd.com/moreSubject.aspx这个页面中
所有符合https://www.jd.com/news.\w+?.
正则表达式的url地址
并将这些链接加入到待抓取的队列中去

 把Selectable对象转换成字符串:toString()、get()如果结果是一个列表的话,只取第一个元素。all()可以吧Selectable转换成字符串,转换成一个List<String>links()取当前节点中所有的链接地址。nodes()选择节点,返回一个List<Selectable>对象

public void process(Page page) {Html html = page.getHtml();//解析titleDocument document = html.getDocument();String title = document.select("title").text();//传递给pipelinepage.putField("title", title);//使用css选择器解析Selectable selectable = html.css("title", "text");//String title2 = selectable.toString();String title2 = selectable.get();page.putField("title2", title2);//选择metaString meta = html.css("meta").get();page.putField("meta", meta);List<String> metaList = html.css("meta").all();page.putField("metaList", metaList);//取链接地址列表List<String> linkList = html.$("div.city_con").links().all();page.putField("linkList", linkList);//nodes方法List<Selectable> nodes = html.css("meta").nodes();for (Selectable node : nodes) {String s = node.get();System.out.println(s);}//取节点的属性List<String> metaNameList = html.css("meta", "name").all();page.putField("metaNameList", metaNameList);}

3、pipeline
数据持久化组件。
框架默认提供三个实现。
ConsolePipeline:框架默认使用,向控制台输出
FilePipeline:向磁盘输出,可以把抓取到结果保存到磁盘。
JsonFilePipeline:向磁盘输出保存json数据。
Pipeline的功能比较固定,更容易做成通用组件
每个页面的抽取方式千变万化,但是后续处理方式则比较固定,例如保存到文件、保存到数据库这种操作,这些对所有页面都是通用的。
在WebMagic里,一个Spider可以有多个Pipeline,使用Spider.addPipeline()即可增加一个Pipeline。这些Pipeline都会得到处理,例如可以使用
spider.addPipeline(new ConsolePipeline()).addPipeline(new FilePipeline())
实现输出结果到控制台,并且保存到文件的目标。
3.2.2. 已有的Pipeline
WebMagic中就已经提供了控制台输出、保存到文件、保存为JSON格式的文件几种通用的Pipeline。

使用方法:
如果需要把数据保存到数据库,需要自定义pipeline。
需要实现Pipeline接口即可。

@Component
public class JobPipeLie implements Pipeline {@Autowiredprivate JobDao jobDao;@Override@Transactionalpublic void process(ResultItems resultItems, Task task) {Job job = resultItems.get("job");//执行保存数据库jobDao.save(job);}
}

4、Scheduler是WebMagic中进行URL管理的组件。一般来说,Scheduler包括两个作用:

对待抓取的URL队列进行管理。
对已抓取的URL进行去重。
实现方法:QueueScheduler:java内存队列(默认使用)FileCacheQueueScheduler:使用文件做缓存的队列。RedisScheduler:使用redis做队列,解决分布式爬虫问题
向队列中添加url时需要去重1)使用java的hashset去重(默认使用)2)使用redis的set去重3)使用布隆过滤器去重。(原理图)

优点:成本低效率高速度快占内存小缺点:可能误判不能删除元素
布隆过滤器的使用方法:1)创建一个QueryScheduler对象2)创建一个布隆过滤器的对象。3)给Scheduler对象设置布隆过滤器。4)使用Spider初始化爬虫时,使用自定义的scheduler。布隆过滤器需要一个jar包guava<!--WebMagic对布隆过滤器的支持--><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>16.0</version></dependency>
  public static void main(String[] args) {//创建一个Pipeline对象FilePipeline filePipeline = new FilePipeline();//数据保存到哪个目录下filePipeline.setPath("D:\\temp\\term331\\html");//创建一个Scheduler(十该久能)过滤,地址队列,对象QueueScheduler scheduler = new QueueScheduler();//创建一个布隆过滤器对象//构造参数就是布隆过滤器的容量。容量因实际情况可变BloomFilterDuplicateRemover remover = new BloomFilterDuplicateRemover(10000000);scheduler.setDuplicateRemover(remover);Spider.create(new MyPageProcessor4())//设置pipeline组件.addPipeline(filePipeline).addPipeline(new ConsolePipeline())//设置自定义的scheduler.setScheduler(scheduler)//设置起始的url.addUrl("http://www.itcast.cn").start();}

3.3.1.三种去重方式
去重就有三种实现方式,那有什么不同呢?

HashSet
使用java中的HashSet不能重复的特点去重。优点是容易理解。使用方便。
缺点:占用内存大,性能较低。

Redis去重
使用Redis的set进行去重。优点是速度快(Redis本身速度就很快),而且去重不会占用爬虫服务器的资源,可以处理更大数据量的数据爬去。
缺点:需要准备Redis服务器,增加开发和使用成本。

布隆过滤器(BloomFilter)
使用布隆过滤器也可以实现去重。优点是占用的内存要比使用HashSet要小的多,也适合大量数据的去重操作。
缺点:有误判的可能。没有重复可能会判定重复,但是重复数据一定会判定重复。

布隆过滤器 (Bloom Filter)是由Burton Howard Bloom于1970年提出,它是一种space efficient的概率型数据结构,用于判断一个元素是否在集合中。在垃圾邮件过滤的黑白名单方法、爬虫(Crawler)的网址判重模块中等等经常被用到。
哈希表也能用于判断元素是否在集合中,但是布隆过滤器只需要哈希表的1/8或1/4的空间复杂度就能完成同样的问题。布隆过滤器可以插入元素,但不可以删除已有元素。其中的元素越多,误报率越大,但是漏报是不可能的。

5、Spider工具类
初始化爬虫,可以装配各个组件,同时设置一些参数。
启动爬虫。

 public static void main(String[] args) {//创建一个Pipeline对象FilePipeline filePipeline = new FilePipeline();filePipeline.setPath("D:\\temp\\term331\\html");//创建一个Scheduler对象QueueScheduler scheduler = new QueueScheduler();//创建一个布隆过滤器对象//构造参数就是布隆过滤器的容量。BloomFilterDuplicateRemover remover = new BloomFilterDuplicateRemover(10000000);scheduler.setDuplicateRemover(remover);Spider.create(new MyPageProcessor4())//设置pipeline组件.addPipeline(filePipeline).addPipeline(new ConsolePipeline())//设置自定义的scheduler.setScheduler(scheduler)//设置起始的url.addUrl("http://www.itcast.cn").start();}

三、51jop招聘网站综合案例
1、需求
抓取51job网站的招聘信息,把招聘信息保存到数据库。
2、功能分析
数据库:
job_info
步骤:
1)访问职位列表页面
2)解析职位详情的url地址,添加到队列中。
3)解析“下一页”的url,添加到队列中。
4)解析页面的业务逻辑中,判断是列表页面还是详情页面。
5)如果是列表页面,执行2-3的动作。
6)如果是详情页面,解析职位详情信息
7)把职位详情保存到数据库。
3、功能实现
1)创建工程
1、创建一个Springboot工程
2、添加依赖
添加SpringDataJpa的起步依赖
添加web模块的起步依赖
mysql数据库驱动
webmagic相关的jar包。

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.2.RELEASE</version></parent><dependencies><!--SpringMVC--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--SpringData Jpa--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!--MySQL连接包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--WebMagic核心包--><dependency><groupId>us.codecraft</groupId><artifactId>webmagic-core</artifactId><version>0.7.3</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions></dependency><!--WebMagic扩展--><dependency><groupId>us.codecraft</groupId><artifactId>webmagic-extension</artifactId><version>0.7.3</version></dependency><!--WebMagic对布隆过滤器的支持--><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>16.0</version></dependency><!--工具包--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency></dependencies>
 3、创建一个配置文件application.properties配置数据库连接信息
#DB Configuration:
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/crawler-331
spring.datasource.username=root
spring.datasource.password=123#JPA Configuration:
spring.jpa.database=MySQL
spring.jpa.show-sql=true
 4、对应数据库的表创建Entity、dao


5、创建一个引导类。

6、实现爬虫的业务逻辑
4、爬虫的业务逻辑
需要自定义的组件:
PageProcess

import com.itheima.entity.Job;
import com.itheima.utils.MathSalary;
import org.jsoup.nodes.Document;
import org.springframework.stereotype.Component;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.selector.Selectable;import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;@Component
public class JobPageProcessor implements PageProcessor {@Overridepublic void process(Page page) {Html html = page.getHtml();//1)判断是列表页面还是详情页面List<Selectable> nodes = html.css("#resultList div.el p.t1").nodes();if (nodes.size() > 0) {//2)如果是列表页面,解析职位详情url列表List<String> urlList = html.css("#resultList div.el p.t1").links().all();//3)把列表添加到访问队列中。page.addTargetRequests(urlList);//4)解析下一页的url,添加到访问队列中。String nextPageUrl = html.css("#rtNext", "href").get();page.addTargetRequest(nextPageUrl);//由于不是职位详情页面,所以没有取东西,// 没有东西交给pipeline所以,跳过pipeline处理page.setSkip(true);} else {//调用职位详情解析业务逻辑parseJobInfo(page);//5)如果是详情页面//6)解析职位详情信息//7)封装到Job对象中。//8)把job对象传递给pipeline。}}@Overridepublic Site getSite() {//设置参数return Site.me();}/*** 职位详情解析业务逻辑* @param page*/private void parseJobInfo(Page page) {//取html对象Html html = page.getHtml();//公司名称String compName = html.css("div.tHeader.tHjob p.cname a.catn", "text").get();//公司联系方式String compAddr = html.css(".tCompany_main > div:nth-child(2) > div:nth-child(2) > p:nth-child(1)", "text").get();//公司信息String compInfo = html.css("div.tBorderTop_box div.tmsg.inbox", "text").get();//职位名称String jobName = html.css("h1", "text").get();//工作地点String jobLine = html.css("div.tHeader.tHjob div.in div.cn p.msg.ltype", "title").get();//通过竖线分割String[] elems = jobLine.split("\\|");String jobAddr = "";if (elems.length > 0) {jobAddr = elems[0];}//职位信息Document document = html.getDocument();String jobInfo = document.select("div.tCompany_main div.tBorderTop_box div.bmsg.job_msg.inbox").text();//薪资范围,最小String salaryStr = html.css(".cn > strong:nth-child(2)", "text").get();Integer[] salary = MathSalary.getSalary(salaryStr);int salaryMin = salary[0];//薪资范围,最大int salaryMax = salary[1];//招聘信息详情页urlString jobUrl = page.getUrl().get();//职位最近发布时间//用Strem流的lambda表达式,判断数组中有没有发布的字符,//有,就把这个数组的元素,收录到timeList集合中,List<String> timeList = Stream.of(elems).filter(e -> e.contains("发布")).collect(Collectors.toList());//如果集合长度大于0,就是有发布字符,就把发布时间给timeString time = "";if (timeList.size() > 0) {time = timeList.get(0);}//把职位信息封装到Job对象中Job job = new Job();job.setCompanyName(compName);job.setCompanyAddr(compAddr);job.setCompanyInfo(compInfo);job.setJobName(jobName);job.setJobAddr(jobAddr);job.setJobInfo(jobInfo);job.setSalaryMin(salaryMin);job.setSalaryMax(salaryMax);job.setUrl(jobUrl);job.setTime(time);//把job对象传递给pipelinepage.putField("job", job);}}
 Pipeline把数据保存到数据库
 @Component
public class JobPipeLie implements Pipeline {@Autowiredprivate JobDao jobDao;@Override@Transactionalpublic void process(ResultItems resultItems, Task task) {Job job = resultItems.get("job");//执行保存数据库jobDao.save(job);}
}

创建爬虫

@Component
public class JobSpider {//    PageProcessor解析参数对象@Autowiredprivate JobPageProcessor jobPageProcessor;
//    数据解析的接收方参数对象@Autowiredprivate JobPipeLie jobPipeLie;//爬虫起始地址private String URL = "https://search.51job.com/list/010000,000000,0100,00,9,99," +"java,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99" +"&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0" +"&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=" +"&specialarea=00&from=&welfare=";public void run(){//        通过spider工具,自定义一个爬虫(胃)解析对象,
// 再添加自定义的解析后装数据的车(屎壳郎),
// 再给爬虫工具类,一个从哪里开始吃的地址,之后,鸣炮,开始吃和拉。Spider.create(jobPageProcessor).addPipeline(jobPipeLie).addUrl(URL).start();}}

通过Controller 地址访问启动爬虫

@RestController
public class JobController {@Autowiredprivate JobSpider jobSpider;@RequestMapping("/start")public String start(){jobSpider.run();return "ok";}}

day75,爬虫02,webmagic入门程序,组件介绍:Downloader,PageProcess,pipeline,Scheduler,51jop招聘网站综合案例相关推荐

  1. 微信小程序全栈开发实践 第二章 微信小程序组件介绍及使用 -- 2.3 rich-text 组件,以及如何单击预览它的节点图片并保存

    一.rich-text组件 nodes: [{name: 'div',attrs: {class: 'div_class',style: 'line-height: 20px;padding:20px ...

  2. Ansible入门及组件介绍

    Ansible简介 Ansible是自动化运维的工具,基于Python开发,实现了批量系统配置.批量程序部署.批量运行命令等功能. Ansible是基于模块工作的,ansible提供一个框架,通过模块 ...

  3. 微信小程序全栈开发实践 第二章 微信小程序组件介绍及使用 -- 2.9 页面链接组件,如何自定义一个导航栏?

    一.小程序中的导航组件 functional-page-navigator 仅在插件中有效,用于跳转到插件功能页. navigator 小程序标准的导航组件 小程序插件是对一些js接口.自定义组件或页 ...

  4. 微信小程序全栈开发实践 第二章 微信小程序组件介绍及使用 -- 2.10 image组件,如何实现图片懒加载?

    一.与image组件有关的技术问题 1.1 什么是WebP? webp是image组件的一个boolean属性,开启这个属性之后,代表url可以设置webp这种格式的图片.webP是一种同时提供了有损 ...

  5. 微信小程序全栈开发实践 第二章 微信小程序组件介绍及使用 -- 2.5 可移动容器及可移动区域,以及如何实现侧滑删除功能

    一.学习使用moveable-view与movable-area组件 1.1 关于元素的定位 static 静态定位 元素在页面流动的当前位置定位,这个时候它的top.left.right.botto ...

  6. 微信小程序全栈开发实践 第二章 微信小程序组件介绍及使用 -- 2.6 scroll-view组件,在小程序中如何实现滚动锚定,如何渲染一个滚动的长列表?

    scroll-view 是一个可以滚动的视图区域的容器组件. 一.重要属性 scroll-view 的滚动属性,实现了两套功能 左右或上下滚动 下拉更新 1.1 与滚动有关的属性: scroll-x ...

  7. 前端学习从入门到高级全程记录之8 (PS基本使用综合案例)

    本期学习目标 本期我们将学习PS的基本使用并且运用以前所学的CSS和HTML的技术来完成一个综合案例. 1.Photoshop基本使用 早在第一期我就让大家去安装PS,不知道安装了没有,没有安装的尽快 ...

  8. Python爬虫之Scrapy框架系列(1)——初识Scrapy框架【安装+简介+运行流程+组件介绍】

    目录: 1.Scrapy模块安装 2.Scrapy框架简介 2.1 Scrapy是个啥? 2.2 我们为啥要用这玩意呢? 3.运行流程 3.1 引入: 3.2 进入正题: 3.3 数据流: 3.4 中 ...

  9. MyBatis 简介及入门程序

    MyBatis 简介及入门程序 文章目录 MyBatis 简介及入门程序 1 基本概念 2 MyBatis 与 Hibernate 3 MyBatis 的核心接口与对象 3.1 SqlSessionF ...

最新文章

  1. python控制台输出颜色
  2. SAP配置webdynpro完全手册
  3. 使用httpd-2.2和httpd-2.4实现指定httpd服务
  4. 如何在几分钟内安装Red Hat Container Development Kit(CDK)
  5. gprs连接中断记录_请收好!脉搏波血压计连接天天血压APP使用指南
  6. Latex笔记(一)—— 复杂表格的制作
  7. 进入已经打开的pyrebox_PyREBox-可用Python编写脚本的逆向工程沙盒
  8. CRC32/CRC16算法C#中的实现
  9. CMD中文显示为乱码
  10. 几款实用Chrome插件
  11. Excel对于筛选后单元格进行“复制”与“粘贴”
  12. 【转•科普】为什么Nikola Tesla是迄今为止最伟大的极客(爱迪生啊爱迪生)
  13. 计算机无法加入域请确保域名,处理计算机无法加入域的错误一则Server2008
  14. mysql 安装gbk字符_mysql安装gbk字符集
  15. 解决mac备忘录会自动将英文双引号转化为中文双引号
  16. 学习日记day31 平面设计 字体构图风格2
  17. android dialog隐藏虚拟按键,Android应用开发之Android dialog 去除虚拟按键的解决方法...
  18. 每天一个医药小故事②神农和药王
  19. 计算机辅助技术衡量国家,机械计算机辅助技术(CAD)及其发展趋势
  20. Chrome浏览器怎么保存整个网页为图片

热门文章

  1. 笔顺、拼音查询小工具推介
  2. 修改HTK代码,让其支持中文
  3. Google Map开发之实战
  4. 使用pyaudio播放无损音乐(wav)
  5. 171002 逆向-Reversing.kr(AutoHotKey)
  6. 朱会灿:搜索引擎演变史 视频及PPT放出 - 讲堂活动 - 腾讯大讲堂
  7. 覃卫平java,广西外国语学院与柳州市柳江区实验高中、柳城县中学签订优质生源基地协议并圆满完成挂牌仪式...
  8. 怎么画出好的架构图,架构师必备。。
  9. matlab做的脑网络分析,eeg脑网络分析
  10. matlab cdf 曲线不平滑,拟合经验CDF曲线以找到确切的值