1. WebCollector与传统网络爬虫的区别
传统的网络爬虫倾向于整站下载,目的是将网站内容原样下载到本地,数据的最小单元是单个网页或文件。而WebCollector可以通过设置爬取策略进行定向采集,并可以抽取网页中的结构化信息。
2. WebCollector与HttpClient、Jsoup的区别
WebCollector是爬虫框架,HttpClient是Http请求组件,Jsoup是网页解析器(内置了Http请求功能)。
一些程序员在单线程中通过迭代或递归的方法调用HttpClient和Jsoup进行数据采集,这样虽然也可以完成任务,但存在两个较大的问题:
(1)单线程速度慢,多线程爬虫的速度远超单线程爬虫。
(2)需要自己编写任务维护机制。这套机制里面包括了URL去重、断点爬取(即异常中断处理)等功能。
WebCollector框架自带了多线程和URL维护,用户在编写爬虫时无需考虑线程池、URL去重和断点爬取的问题。
3. WebCollector能够处理的量级
WebCollector目前有单机版和Hadoop版(WebCollector-Hadoop),单机版能够处理千万级别的URL,对于大部分的精数据采集任务,这已经足够了。WebCollector-Hadoop能够处理的量级高于单机版,具体数量取决于集群的规模。
4. WebCollector的遍历
WebCollector采用一种粗略的广度遍历,但这里的遍历与网站的拓扑树结构没有任何关系,用户不需要在意遍历的方式。
网络爬虫会在访问页面时,从页面中探索新的URL,继续爬取。WebCollector为探索新URL提供了两种机制,自动解析和手动解析。
更多了解官网:https://github.com/CrawlScript/WebCollector
看了下相关的教程,感觉这个工具配置还挺简单的,上手也很轻松,看了相关的案例就写了这段爬取彼岸壁纸网站几乎所有壁纸的爬虫代码。
首先导入架包:
<dependency> <groupId>cn.edu.hfut.dmic.webcollector</groupId> <artifactId>WebCollector</artifactId> <version>2.73-alpha</version> <!--定义不导入日志打印包(避免包冲突)--> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency>
代码:
import cn.edu.hfut.dmic.webcollector.model.CrawlDatums; import cn.edu.hfut.dmic.webcollector.model.Page; import cn.edu.hfut.dmic.webcollector.plugin.rocks.BreadthCrawler; import org.jsoup.Connection; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.*; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; public class BaCollect extends BreadthCrawler { public BaCollect(String crawlPath, boolean autoParse) { super(crawlPath, autoParse); this.addSeed("http://pic.netbian.com");//种子页面,起始页面 for (int pageIndex = 2; pageIndex <= 1159; pageIndex++) { String seedUrl = String.format("http://pic.netbian.com/index_%d.html", pageIndex); this.addSeed(seedUrl); //循环添加了种子 } /*正规则,待爬取网页至少符合一条正规则,才可以爬取*/ // this.addRegex("+^http://pic.netbian.com.*"); /*负规则,只要符合一条负规则,跳过,不爬取*/ // this.addRegex("-^http://pic.netbian.com.*"); /** addRegex 参数为一个 url 正则表达式, 可以用于过滤不必抓取的链接,如 .js .jpg .css ... 等 * 也可以指定抓取某些规则的链接,如下 addRegex 中会抓取 此类地址: * http://pic.netbian.com/2018-07-13-graphql-for-octokit/ * */ // this.addRegex("http://pic.netbian.com/[0-9]{4}-[0-9]{2}-[0-9]{2}-[^/]+/"); //不要爬取包含jpg|png|gif的图片 this.addRegex("-.*\\.(jpg|png|gif).*"); //不要爬取包含 #的URL this.addRegex("-.*#.*"); /*设置User-Agent*/ // this.conf.setDefaultUserAgent("Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:26.0) Gecko/20100101 Firefox/26.0"); /*设置cookie*/ // this.conf.setDefaultCookie("mxm=123456"); /*线程数*/ // this.setThreads(30); // this.conf.setTopN(100);//设置每次迭代中爬取数量的上限 /** *设置是否为断点爬取,如果设置为false,任务启动前会清空历史数据。 *如果设置为true,会在已有crawlPath(构造函数的第一个参数)的基础上继 *续爬取。对于耗时较长的任务,很可能需要中途中断爬虫,也有可能遇到 *死机、断电等异常情况,使用断点爬取模式,可以保证爬虫不受这些因素 *的影响,爬虫可以在人为中断、死机、断电等情况出现后,继续以前的任务 *进行爬取。断点爬取默认为false * */ // this.setResumable(false); } /* visit函数定制访问每个页面时所需进行的操作 */ @Override public void visit(Page page, CrawlDatums crawlDatums) { // System.out.println("URL:"+page.url()); for (Element element : page.select("li a")) { if(element.attr("href").matches("/tupian/.*.html")){ System.out.println("图片:"+element.attr("href")); CollectImgs("http://pic.netbian.com"+element.attr("href")); } } } //获取图片 public static void CollectImgs(String url) { //链接到目标地址 Connection connect = Jsoup.connect(url); Document document = null; try { //设置useragent,设置超时时间,并以get请求方式请求服务器 document = connect.userAgent("Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)") .timeout(6000) .ignoreContentType(true).get(); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //获取所有图片链接 Elements imgtag = document.getElementById("img").getElementsByTag("img"); for (int i = 0; i < imgtag.size(); i++) { if (imgtag.get(i).attr("src").matches("/uploads/allimg/.*")) { System.out.println("图片:http://pic.netbian.com" + imgtag.get(i).attr("src")); downImages("/ba_imgs","http://pic.netbian.com" + imgtag.get(i).attr("src")); } } } /** * 下载图片到指定目录 * @param filePath 文件路径 * @param imgUrl 图片URL */ public static void downImages(String filePath, String imgUrl) { // 若指定文件夹没有,则先创建 File dir = new File(filePath); if (!dir.exists()) { dir.mkdirs(); } // 截取图片文件名 String fileName = imgUrl.substring(imgUrl.lastIndexOf('/') + 1, imgUrl.length()); try { // 文件名里面可能有中文或者空格,所以这里要进行处理。但空格又会被URLEncoder转义为加号 String urlTail = URLEncoder.encode(fileName, "UTF-8"); // 因此要将加号转化为UTF-8格式的%20 imgUrl = imgUrl.substring(0, imgUrl.lastIndexOf('/') + 1) + urlTail.replaceAll("\\+", "\\%20"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } // 写出的路径 File file = new File(filePath + File.separator + fileName); try { // 获取图片URL URL url = new URL(imgUrl); // 获得连接 URLConnection connection = url.openConnection(); // 设置10秒的相应时间 connection.setConnectTimeout(10 * 1000); // 获得输入流 InputStream in = connection.getInputStream(); // 获得输出流 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file)); // 构建缓冲区 byte[] buf = new byte[1024]; int size; // 写入到文件 while (-1 != (size = in.read(buf))) { out.write(buf, 0, size); } out.close(); in.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
启动:
@Test public void PaCollect() throws Exception { //crawlPath是URL信息存放路径 BaCollect crawler = new BaCollect("crawl", true); //网页爬取深度为4 crawler.start(4);//启动 System.out.println("===============================================\n=== ==="); System.out.println("=== 爬取的图片已为您下载到:"+new File("/ba_imgs").getAbsolutePath()); System.out.println("=== ===\n==============================================="); }
爬取结果:
发表评论