webmagic框架是java开源的爬虫框架,封装了读取网页内容和操作html相关标签的方法,使用起来简单,上手很快。
2.1、pom文件配置
<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>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-selenium</artifactId>
<version>0.7.3</version>
</dependency>
2、代码实现,webmagic提供了很丰富的api,异步获取网页,处理网页,将处理结果持久化,整个流程很清晰。我这边贴上我实践的相关代码。将异步爬取改成了同步爬取,因为只需要爬取单个url,且需同步及时返回结果。包括相关对html做查询、删除、修改、增加操作。
/**
* 开启爬虫
* @param url
* @return
*/
public static Page startSpider(String url) {
Request request = new Request(url);
String chromePath = System.getProperty("chrome.chromedriver");;
LOG.info("chromePath:" + chromePath);
SeleniumDownloader downloader = new SeleniumDownloader(chromePath);
downloader.setSleepTime(2000);
SpiderProcessor spiderProcessor = new SpiderProcessor(spiderTaskId);
Task task = new Task() {
@Override
public String getUUID() {
return UrlUtils.getDomain(request.getUrl());
}
@Override
public Site getSite() {
return spiderProcessor.getSite();
}
};
Page page = null;
try {
page = downloader.download(request, task);
LOG.info("开始执行:");
if (page == null || page.isDownloadSuccess()) {
spiderProcessor.process(page);
}
} catch (Exception e) {
LOG.error("spiderProcessor process fail:{}", e);
} finally {
try {
downloader.close();
} catch (IOException e) {
LOG.error("downloader close fail:{}", e);
}
}
return page;
}
查询相关操作:
Elements video_iframe = page.getHtml().getDocument().getElementsByClass("video_iframe");
Elements linkElements = page.getHtml().getDocument().getElementsByTag("link");
String name = page.getHtml().$("#activity-name", "text").toString();
String digest = page.getHtml().$("meta[property=og:description]", "content").toString();
修改操作:
for (Element element : linkElements) {
String href = element.attr("href");
if (StringUtils.isNotEmpty(href) &&
!href.startsWith("https") &&
!href.contains("http")) {
element.attr("href", "https" + href);
}
}
删除操作:
Element activity_name = page.getHtml().getDocument().getElementById("activity-name");
if (activity_name != null) {
activity_name.remove();
}
新增操作:
for (Element element : video_iframe) {
Element parent = element.parent();
Elements videos = element.getElementsByTag("video");
if (videos == null || videos.size() == 0) {
continue;
}
Element videoElement = videos.get(0);
String videoSrc = videoElement.attr("src");
String videoPoster = videoElement.attr("poster");
parent.append("<video src=\"" + newVideoUrl + "\"style=\"width: 677px; height: 310px;\" class=\"\"poster=\"" + newVideoPoster + "\" data-cover=\"" + newVideoPoster + "\"></video>");
element.remove();
}
3.1、chromedriver文件位置读取问题,因为本地读取方式和linux上读取方式不一致,导致本地在resource目录下可以正常获取,linux上打成的jar不能正常获取。原因是linux上不能直接读取没有解压的包,jar包里的文件只能通过IO读成Instream形式,再转换成key-value这种。解决办法是指定linux下的目录。
3.2、selenuim_config的配置,设置config.ini文件的路径,遇到跟3.1一样的问题,读取文件报错,然后遇到webmagic框架中的一个bug,LinkedBlockingDeque队列在队列为空时,调用take方法会阻塞线程,导致当前线程进入假死状态。基于这个问题,将WebDriverPool方法重写,将读取config.ini文件里的配置,改成写死走chrome浏览器,然后处理异常解决不当的问题。
3.3、linux服务器上调用chromedriver报错,原因有二:一、chrome浏览器跟chromedriver版本不匹配,二、chrome的参数设置不对
ChromeOptions chromeOptions = new ChromeOptions();
// 禁用沙箱
chromeOptions.addArguments("--no-sandbox");
chromeOptions.addArguments("--disable-dev-shm-usage");
chromeOptions.addArguments("--headless");
mDriver = new ChromeDriver(chromeOptions);