参考文档地址
webmagic中文文档:http://webmagic.io/docs/zh/
一:引入依赖
pom.xml中添加
<properties> <webmagic.version>0.7.3webmagic.version> properties> <dependency> <groupId>us.codecraftgroupId> <artifactId>webmagic-coreartifactId> <version>${webmagic.version}version> <exclusions> <exclusion> <groupId>org.slf4jgroupId> <artifactId>slf4j-log4j12artifactId> exclusion> exclusions> dependency> <dependency> <groupId>us.codecraftgroupId> <artifactId>webmagic-extensionartifactId> <version>${webmagic.version}version> dependency> <dependency> <groupId>us.codecraftgroupId> <artifactId>webmagic-saxonartifactId> <version>${webmagic.version}version> dependency> <dependency> <groupId>us.codecraftgroupId> <artifactId>webmagic-seleniumartifactId> <version>${webmagic.version}version> dependency> |
二:实现PageProcessor
/** * 解析器,基础处理类 * * @author zhangjianzhong * */ public class BasePageAdapters implements PageProcessor { private Site site; protected CrwlerTaskVO task;// 包含采集的规则 public static final String KEY_PARSER = "parser";
public BasePageAdapters(Site site, CrwlerTaskVO task) { this.site = site; this.task = task; this.site = Site.me(); // 设置重试次数 this.site.setRetryTimes(3); // 抓取间隔时间 this.site.setSleepTime(5000); this.site.setTimeOut(5000); this.site.setCycleRetryTimes(10); }
@Override public void process(Page page) { // TODO Auto-generated method stub try { Request request = page.getRequest(); // 获取当前页面的数据信息,这个信息会贯穿整个数据请求串
ParserVO parser = (ParserVO) request.getExtra(KEY_PARSER);// 获取解析器 // 如果也没有传递进来解析器 if (parser == null) { List for (ParserVO p : parsers) { // 如果能找到解析器,那么处理该请求 this.analysis(page, p); } } else {// 如果有解析器跟着解析器处理 // 因为没有infoID所有认为这是一条新的信息 this.analysis(page, parser); } } catch (Exception e) { // TODO: handle exception }
}
private void analysis(Page page, ParserVO parser) {
Html html = page.getHtml(); ParserEntity pe = parser.getParser(); // 获取数据区域 Selectable area = html.$(pe.getArea());// 数据所在区域 Selectable group = null; if (pe.getItemSelector() != null) { group = area.$(pe.getItemSelector());// 数据项的选择器 // 说明有列表项目 } else { group = area; } List } @Override public Site getSite() { // TODO Auto-generated method stub return this.site; } } |
三:启动采集
@Service public class PageReptilesService { /** * 线程数量 */ private int threadNum = 1; private String configPath; private String chromedriverPath;
public PageReptilesService() { String basePath = System.getProperty("user.dir"); this.configPath = basePath + File.separator + "configs/selenuim_config.ini"; System.setProperty("selenuim_config", this.configPath);
String drivers = basePath + File.separator + "drivers"; this.chromedriverPath = drivers + File.separator + "chromedriver.exe"; }
/** * 启动采集 * * @param rule 规则 * @param parser 解析器 * @author JYInfo */ public void startReptile(RuleEntity rule, BasePageAdapters parser) {
Spider spider = Spider.create(parser);
// 比如从"https://www.baidu.com"开始抓 // this.seedUrl(spider, rule);
spider.addUrl(""); List // 根据访问方式类型写入不同的监听器 BasePageListener basePageListener = new BasePageListener(); spiderListeners.add(basePageListener);
SeleniumDownloader seleniumDownloader = new SeleniumDownloader(this.chromedriverPath); if (rule.getSleepTime() != null) {// 设置等待页面初始换时间 seleniumDownloader.setSleepTime(rule.getSleepTime()); // 例如天气页面是通过js渲染,需等待1-2s. } spider.setDownloader(seleniumDownloader); SeleniumPageListener spListener = new SeleniumPageListener(seleniumDownloader); spiderListeners.add(spListener);
// 写入监听器 spider.setSpiderListeners(spiderListeners); // // 开启5个线程抓取 spider.thread(threadNum); spider.run(); } } |
四:实现页面启动停止
private Map public synchronized MySpiderMonitor register(Spider... spiderStatuses.put(spider.getUUID(),spiderStatusMBean);)
|
public Spider getSpider() { return this.spider; } |
MySpiderMonitor spiderMonitor = MySpiderMonitor.instance(); spider.setUUID(uuID); spiderMonitor.register(spider); |
//获取到注册的spiderStatus MySpiderMonitor spiderMonitor = MySpiderMonitor.instance(); Map MySpiderStatus spiderStatus = spiderStatuses.get(uuID); //既然有了spiderStatus就可以在页面上控制开、关和查看过程信息了。 (1)spiderStatus.getSpider().run();//掉它启动 (2)spiderStatus.stop();//掉它关闭 (3)//获取启动过程中详细信息 spiderStatus.getTotalPageCount(); spiderStatus.getStatus(); …
|
//通过反射拿到队列中没有执行完的请求信息 QueueScheduler b = ((QueueScheduler) spiderStatus.getSpider().getScheduler()); Class> classes = b.getClass(); Field[] fs = classes.getDeclaredFields(); for (Field f : fs) { f.setAccessible(true); @SuppressWarnings("unchecked") BlockingQueue if (queue.size() > 0) { Set queue.forEach(qu -> { sss.add(qu);//放到set中 }); redisUtil.set(ruleId, sss);//存入redis或序列化之后写入数据库或者本地文件都可以 } } // 停止 spiderStatus.stop(); //再次启动的时候把这些请求add进去就ok了 |
以上修改实现了页面端直接调用启动、关闭爬虫任务。