爬取动态页面(WebMagic、HtmlUnit)
- 一、HtmlUnit的基本使用
- 引入依赖
- 一般使用步骤
- WebClient 的一些配置(上述一般步骤中的第二步)
- 二、案例(爬取CSDN首页)测试(WebMagic+HtmlUnit)
- 三、总结
上次提出了用 Selenium+浏览器驱动
去模拟浏览器的行为,然后去爬取动态页面(爬取动态页面(WebMagic、Selenium、ChromeDriver))。但是真的是太慢太慢了,而且 WebMagic 很多特性都用不了了,比如:多线程去处理请求、使用Pipeline去对结果集进行处理、请求去重…WebMagic最后被用成了HttpClient、Jsoup,失去了框架的意义。(也有可能是小编没合理地去模块化,但慢是真慢)
所以这里提出一个简单易用的工具——HtmlUnit
,它可以模拟浏览器的行为,支持JavaScript解析和执行,可以用于解析动态页面。但它解析JavaScript的时候也是比较慢的,但后续用 WebMagic 去处理静态页面就快起来了。就比如说处理某网站的主页(动态页面)是需要解析JavaScript的,但主页里面的超链接对应的网页是静态网页,这时就可以直接用WebMagic去处理就可以了,速度就有了。
这里得说明一下 HtmlUnit 的缺点,方便后面讲解其使用:
- 不支持所有的动态页面:虽然 HTMLUnit 可以处理 JavaScript 和 AJAX,但是它并不支持所有的动态页面。一些高度复杂的动态页面可能会导致 HTMLUnit 无法正确解析页面。(比如:51job)
- 缺乏可视化界面:HTMLUnit 是一个 GUI-less浏览器,因此它缺乏可视化界面,这使得它不太适合用于测试和调试 Web 应用程序。(但咱这用的是去爬虫,所以问题应该不大)
- 对JavaScript的支持并不完美:HTMLUnit 的 JavaScript 引擎不如一些主流浏览器的 JavaScript 引擎强大,所以当用 HtmlUnit 去解析的时候,可能会出现一些JavaScript的问题。(这个根据调试结果,自己应该做相应的调整选择)
一、HtmlUnit的基本使用
引入依赖
需要 htmlunit 依赖和 commons-io 这个工具依赖。
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version></dependency><dependency><groupId>net.sourceforge.htmlunit</groupId><artifactId>htmlunit</artifactId><version>2.70.0</version></dependency>
一般使用步骤
// 1. 创建 WebClient 对象,模拟浏览器行为
WebClient client = new WebClient();
// 2. 对 client 进行一些配置
// 比如设置不需要解析css时
client.getOptions().setCssEnabled(false);
// 3. 打开网页(通过getPage(url)方法),该过程进行了解析
HtmlPage htmlPage = client.getPage(url);
// 4. 因为小编一般用它就是解析动态页面的,所以一般都是会解析JavaScript的
// 所以这里最好设一个解析script时间,让它充分得以解析
client.waitForBackgroundJavaScript(10*1000);// 10s
// 5. 获取解析后的页面html源代码字符串
String htmlStr = htmlPage.asXml();
// 6. 再利用webmagic中的Html类去构造Html对象去处理数据
Html html = new Html(htmlStr);
// 7. 关闭WebClient
client.close();
WebClient 的一些配置(上述一般步骤中的第二步)
- 开启JavaScript解析(默认是开启的)
client.getOptions().setJavaScriptEnabled(true);
- 关闭CSS解析(默认是开启的)
client.getOptions().setCssEnabled(false);
- 禁止抛出JavaScript错误,防止程序终止(默认是开启的)
client.getOptions().setThrowExceptionOnScriptError(false);
- 等待JavaScript执行完成(这个设在getPage方法后,对面上面的第四步)
client.waitForBackgroundJavaScript(10*1000);// 10s
- 设置浏览器的 User-Agent,反反爬虫策略之一。让浏览器觉得你不是爬虫用户访问的。
client.addRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3");
二、案例(爬取CSDN首页)测试(WebMagic+HtmlUnit)
爬取CSDN首页,案例代码
@Component
public class TestProcessor implements PageProcessor {@SneakyThrows@Overridepublic void process(Page page) {if(page.getUrl().toString().equals(url)) {// 创建WebClient对象WebClient client = new WebClient();// 开启自动解析JavaScriptclient.getOptions().setJavaScriptEnabled(true);client.getOptions().setCssEnabled(false);client.getOptions().setThrowExceptionOnScriptError(false);// 打开网页,获取HtmlPage对象HtmlPage htmlPage = client.getPage(page.getUrl().toString());client.waitForBackgroundJavaScript(30000);// 页面源代码String s = htmlPage.asXml();Html html = new Html(s);// 获取当页职位urlList<String> allUrl = html.css("html body div#app div div.main div.page-container.page-component div div.home_wrap div#floor-blog-index_747 div.floor-blog-index div.blog-content div.Community div.active-blog div.Community-item-active.blog div.Community-item.blog div.content a.blog","href").all();// 去获取数据、处理数据、保存数据for (String jurl : allUrl) {page.addTargetRequest(jurl);// 静态页面交给webmagic处理}client.close();}else{addSave(page);}}private void addSave(Page page) {// 获取对应的html对象Html jobHtml = page.getHtml();// 获取数据并保存数据// 存入数据库}private Site site = Site.me().setRetryTimes(3).setSleepTime(1000).setTimeOut(3000).setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3");@Overridepublic Site getSite() {return this.site;}// initialDelay 当任务启动后,等待多久执行方法// fixedDelay 每隔多久执行这个方法@Scheduled(initialDelay = 1000,fixedDelay = 100000)public void process(){Spider.create(new TestProcessor()).addUrl(url).thread(5).run();}private String url = "https://blog.csdn.net/?spm=1001.2101.3001.4477";
}
测试效果
首页JavaScript被解析后的 CSDN HTML 代码
首页博客超链接对应的博客网页(它是静态网页),其 HTML 代码解析如下图所示
三、总结
使用 HtmlUnit
去解析动态页面然后去爬虫是比较方便的,这是由于 HtmlUnit 工具易用的原因。但由于它存在 JavaScript 支持并不完美,外加有些动态页面它也是解析不了的缺陷,使用 Selenium+浏览器驱动 这种方式也不能说就比 HtmlUnit 解析要差。
爬虫使用’工具’总结就是:
- 静态页面直接用 Webmagic;
- 动态页面如果可以用 HtmlUnit 就用 HtmlUnit;
- HtmlUnit 完成不了的再用 Selenium+浏览器驱动。
还有就是小编发现很多网站首页是动态页面的,但动态网页里超链接对应的页面一般是静态网页的。(小编没说绝对哈,一般是这样的)