神刀安全网

Spring Boot 全栈开发:解析器实现

Spring Boot 全栈开发:解析器实现

parser.png

功能分析

不同的URL对应的不同的资源, 拿视频来说,视频网站很多,腾讯视频、优酷/土豆、爱奇艺、慕课网等等,我们需要根据URL通过爬虫来获取我们需要的资源, 如(视频标题,视频背景图片,视频在线播放地址),每个网站的爬虫规则肯定是不一样的,但大体步骤有很多类似,所以有了如下的解决方案。

1、抽象 解析器

public interface Parser<T> {    /**    * 从某个Url中解析数据到对应的模型    * @param url 资源地址    * @return 数据模型(如VIDEO,ARTICLE等等)    */   T parse(String url);    /**    * 从某个Url中解析相关联的数据    * @param url 资源地址    * @return 相关资源索引 + 地址    */   List<Episode> parseEpisodes(String url);  }

说明:泛型 T 是解析器解析得到的对象,如Video,Article等等

2、实现具体的爬虫逻辑,以慕课网为例

/**  * 慕课网  * Created by Silence on 2017/3/15.  */ public class Imooc implements Parser<Video>{   private static final String PROVIDER = "慕课网";   private static final String IMAGE_REGEX = "course.imageUrl=/"(.*?)/"";   private static final String PLAY_REGEX = "course.videoUrl=/"(.*?)/"";   private static final String COOKIES = "___rl__test__cookies=1489561521278; imooc_uuid=ba94bc99-83c7-41c9-aa1a-7d254bd02d94; imooc_isnew_ct=1489302235; OUTFOX_SEARCH_USER_ID_NCOO=1083121786.8991733; loginstate=1; apsid=RjNWI3NTE3ZWQwODg5YWVjMzA5YmZmMjc2Mjc1MDYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzI0NDAwNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBjYWNlYWE1ZDM5ZmJjZjcxZDAxMWFmZjhiMjdlNDA0ah7FWGoexVg%3DOG; PHPSESSID=j2e9escm60fu58n6ss2g51hsf1; Hm_lvt_c92536284537e1806a07ef3e6873f2b3=1489313259,1489561480,1489561512; Hm_lpvt_c92536284537e1806a07ef3e6873f2b3=1489561958; IMCDNS=0; Hm_lvt_f0cfcccd7b1393990c78efdeebff3968=1489302235,1489405517,1489561418; Hm_lpvt_f0cfcccd7b1393990c78efdeebff3968=1489562818; imooc_isnew=2; cvde=58c8e74952b51-41";    @Override   public Video parse(String url) {     Video video = new Video();     video.setProvider(PROVIDER);     video.setValue(url);     video.setParserName("沧海云");     video.setParser("http://ictgu.cn");     video.setType("H5");     url = url.replace("www","m");     Document document = JsoupUtils.getDocWithPhone(url, COOKIES);     String title = document.select("title").text();     video.setTitle(title);     Matcher matcher = Pattern.compile(IMAGE_REGEX).matcher(document.html());     if (matcher.find()){       String image = matcher.group(1);       video.setImage(image);     }     matcher = Pattern.compile(PLAY_REGEX).matcher(document.html());     if (matcher.find()){       String playUrl = matcher.group(1);       video.setPlayUrl(playUrl);     }     return video;   }    @Override   public List<Episode> parseEpisodes(String url) {     List<Episode> episodes = new ArrayList<>();     url = url.replace("www","m");     Document document = JsoupUtils.getDocWithPhone(url, COOKIES);     Elements elements = document.select("ul.course-sections li");     int i = 0;     for (Element element : elements){       Episode episode = new Episode();       String index = ++i < 10 ? "0" + i : "" + i;       episode.setIndex(index);       String value = "http://www.imooc.com" + element.select("a").attr("href");       episode.setValue(value);       episodes.add(episode);     }     return episodes;   }  }

在下图中可以很清楚的看到一个Video需要的信息,通过正则表达式可以匹配到这些信息,并赋值到对象中。

Spring Boot 全栈开发:解析器实现

慕课网-网页源代码

3、解析器管理器

面对如此之多的解析器对象,如何使URL与之一一对应,达到完美解析的结果呢?

@Component @Log4j public class ParseManager {    @Autowired   private StringRedisTemplate redisTemplate;    private Map<String, Parser> parserMap;    public ParseManager(){     parserMap = new HashMap<>();     parserMap.put("iqiyi.com", new Iqiyi());     parserMap.put("le.com", new Letv());     parserMap.put("mgtv.com", new Mgtv());     parserMap.put("sohu.com", new Sohu());     parserMap.put("youku.com", new Youku());     parserMap.put("qq.com", new Qq());     parserMap.put("imooc.com", new Imooc());   }    public Parser getVideoParse(String key){     return parserMap.get(key);   }    public Video parseVideo(String url){     String cacheValue = redisTemplate.opsForValue().get(url);     Video video;     if (StringUtils.isEmpty(cacheValue)){       log.info("开始解析:" + url);       String key = UrlUtils.getTopDomain(url);       Parser videoParse = this.getVideoParse(key);       video = (Video) videoParse.parse(url);       this.cacheVideoInfo(url, video);     }else {       log.info("开始获取缓存信息:" + url);       video = JSONObject.parseObject(cacheValue, Video.class);     }     log.debug("VIDEO: "+ JSONObject.toJSONString(video));     return video;   }    @Async   private void cacheVideoInfo(String url, Video video){     log.info("缓存视频:" + url);     String value = JSONObject.toJSONString(video);     redisTemplate.opsForValue().set(url, value);     redisTemplate.expire(url, 3, TimeUnit.HOURS);   }  }

把URL的顶级域名当做map的key,解析器当做value,通过取URL的顶级域名就能快速得到对应的解析器实例,然后使用@Component注解,就可以在其他地方使用@Autowire注解使用此解析器管理器了

Github地址

地址: https://github.com/ChinaSilence/any-video

演示地址:

地址:http://www.ictgu.cn

相关文章

Spring Boot 全栈开发:初章
Spring Boot 全栈开发:开发环境搭建
Spring Boot 全栈开发:应用部署使用
Spring Boot 全栈开发:漂亮的邮件注册
Spring Boot 全栈开发:解析器实现
Spring Boot 全栈开发:视频解析之优酷
Spring Boot 全栈开发:视频解析之乐视
Spring Boot 全栈开发:用户安全
Spring Boot 全栈开发:并发爬虫优化
未完待续

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Spring Boot 全栈开发:解析器实现

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址