基于Crawler4j的Java爬虫实践

  • 1. Introduction
  • 2. 系统架构
    • 2.1 crawler4j
    • 2.2 jsoup
    • 2.3 Apache Commons CSV
    • 2.4 maven
  • 3. 关键
    • 3.1 编码encoding
      • 问题1
      • 问题2
    • 3.2 maven
      • 问题1
      • 问题2
  • 4. 代码、运行结果

1. Introduction

爬虫介绍:
在互联网时代,网络爬虫主要是为搜索引擎提供最全面和最新的数据
在大数据时代,网络爬虫更是从互联网上采集数据的有利工具。目前已经知道的各种网络爬虫工具已经有上百个,网络爬虫工具基本可以分为 3 类。
• 分布式网络爬虫工具,如 Nutch。
• Java 网络爬虫工具,如 Crawler4j、WebMagic、WebCollector。
• 非 Java 网络爬虫工具,如 Scrapy(基于 Python 语言开发)。

关于爬虫的原理、工作流程以及抓取策略等更多信息可以学习下面这篇文章,这里不多说明。
(通过网络爬虫采集大数据)

实践简介:
使用java语言编写爬虫,爬取国家统计局网站上的老年人口数据,爬到的数据存储为.csv格式。
爬取的目标网站

文章目的:
本文主要记录和总结这次java爬虫实践。

2. 系统架构

2.1 crawler4j

crawler4j框架简介:
一个 开源-基于Java语言-多线程的 网络爬虫框架,简单易用。
github传送门: crawler4j

crawler4j框架使用简述:
i. 继承实现WebCrawler爬虫类, 该类决定爬虫应该抓取哪些URL(对应shouldVisit方法)并处理下载的页面(对应visit方法)。
ii. 实现一个控制器类Controller,设置抓取的种子网址,设置抓取结果存储的文件夹以及并发爬虫线程的数量(main方法就在里面,在这里面使用爬虫类)。

2.2 jsoup

简介:
jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容(html string)。它提供了一套非常省力的API,可通过DOM,CSS,以及类似于jQuery的选择器语法来解析和操作数据(这个好像是它的亮点)。
官网:jsoup

2.3 Apache Commons CSV

简介:
java的工具库,提供了 用于读取和写入各种CSV类型文件 的简单API
官网:common csv
使用方法参考博文:使用Apache Common CSV读写CSV文件

2.4 maven

介绍:
参考博文:Maven介绍,包括作用、核心概念、用法、常用命令、扩展及配置

使用方法简述:
maven配置成功后,在eclipse中建立maven项目。对于源代码中需要引入的第三方包,只需要在pom.xml中声明相应的第三方库的依赖(dependency)即可,具体的dependency来源则是在远程仓库中搜索,有下面两个选择:
阿里云镜像:https://maven.aliyun.com/mvn/search
官方仓库:http://mvnrepository.com/

声明了依赖后,maven会自动从远程仓库下载依赖包到本地仓库,应用于源程序的构建,超方便有不有:)

3. 关键

3.1 编码encoding

问题1

由于目标网站的编码是gb2312, 直接使用jsoup解析crawler4j抓取到的html文本会有编码错误,可能是crawler4j不能在向目标网站请求的时候设置编码,导致返回的页面编码有偏差(不太确定~)。

//这样写会有编码错误!
String html = htmlParseData.getHtml();
Document doc = Jsoup.parse(html, "GBK");

参考:crawler4j抓取页面使用jsoup解析html时的解决方法

解决:
利用crawler4j抓取的目标网站url,和Jsoup支持在请求的时候,传入URL 对象,然后设置编码的功能,实现网页文本的正确编码解析。

//OK!
Document doc = Jsoup.parse(new URL(url).openStream(), "GBK", url);

参考:JSOUP教程,JSOUP 乱码处理,JSOUP生僻字乱码解决方案

问题2

写入csv后仍有汉字编码错误,开始以为是commons csv的问题,排查后发现commons csv是基于java写出流的,而java写出流默认编码不是UTF-8,这就导致最后生成的csv中文乱码

解决:
java写出流设置编码为utf-8就好了。

OutputStreamWriter fileWriter = new OutputStreamWriter (new FileOutputStream (FILE_NAME,true),"UTF-8");
CSVPrinter csvFilePrinter  = new CSVPrinter(fileWriter, format);

3.2 maven

问题1

初学maven, 对maven运作不了解导致迷茫

解决:
首先是了解maven的工程目录结构:
工程里有很多索引类文件、生成文件,都可以随意删除。留下的就是src/main里面的java源代码,还有pom.xml这个Maven的核心配置文件。
然后理解怎么使用maven:
maven配置好后,所有的操作都在pom.xml中。
这样就可以正确使用maven了:)
参考博文:Maven详解(三)------ Maven工程目录介绍

问题2

pom.xml有小红叉,但找不到详细的报错信息,找到之后又怎么解决?

maven错误信息在哪里?(eclipse-maven环境下):
打开window->show view->problems窗口,可以看到所有的出错信息。或者,去工程的properties->Java Build Path->Libraries->Maven Dependencies里面也可以看到一点。

假设maven配置ok,这种引入新包出错的一般解决方法如下:
a) 从 local maven repository 中删除以.lastUpdated 结尾的文件(用notepad++打开可以看到错误信息)
b) 然后对项目做maven更新(Maven->Update Project),并且记得在弹出的对话框中选择“Force Update Of Snapshots/Releases"

参考博文:
Could not transfer artifact xxx from/to xxx解决方案
Failed to read artifact descriptor for xxx:jar

4. 代码、运行结果

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><!-- 项目信息 --><modelVersion>4.0.0</modelVersion><groupId>com.java.crawler4j</groupId><artifactId>myCrawler4j</artifactId><version>0.0.1-SNAPSHOT</version><repositories><repository><id>alimaven</id><name>aliyun maven</name><url>http://maven.aliyun.com/nexus/content/groups/public/</url></repository></repositories><dependencies><!-- 加入log4j支持 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><!-- 加入slf4j log4j驱动类 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.10</version></dependency><dependency><groupId>edu.uci.ics</groupId><artifactId>crawler4j</artifactId><version>4.4.0</version></dependency><dependency><groupId>com.sleepycat</groupId><artifactId>je</artifactId><version>5.0.73</version></dependency><dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.8.2</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.commons/commons-csv --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-csv</artifactId><version>1.4</version></dependency></dependencies></project>

MyCrawler.java

package com.java.crawler;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;import edu.uci.ics.crawler4j.crawler.Page;
import edu.uci.ics.crawler4j.crawler.WebCrawler;
import edu.uci.ics.crawler4j.url.WebURL;public class MyCrawler extends WebCrawler {//common csvprivate final String FILE_NAME = "res\\result.csv"; //csv filepathprivate static final String NEW_LINE_SEPARATOR = "\n"; //CSV deliminatorprivate static final Object [] FILE_HEADER = {"地区","60岁及以上人口:合计","男","女","健康:小计","男","女","基本健康:小计","男","女","不健康,但生活能自理:小计","男","女","生活不能自理:小计","男","女"}; //CSV headerprivate OutputStreamWriter fileWriter = null;private CSVPrinter csvFilePrinter = null;private CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator(NEW_LINE_SEPARATOR);private int pass=0;private File csv;//constructorpublic MyCrawler() throws IOException {csv = new File(FILE_NAME);if (csv.isFile()) {csv.delete();}fileWriter = new OutputStreamWriter (new FileOutputStream (FILE_NAME,true),"UTF-8");csvFilePrinter  = new CSVPrinter(fileWriter, format);csvFilePrinter.printRecord(FILE_HEADER);}//crawler4jprivate final static Pattern FILTERS = Pattern.compile(".*(\\.(css|js|gif|jpg" + "|png|mp3|mp3|zip|gz))$");@Overridepublic boolean shouldVisit(Page referringPage, WebURL url) {String href = url.getURL().toLowerCase(); return !FILTERS.matcher(href).matches() // 正则匹配,过滤掉我们不需要的后缀文件&& href.startsWith("http://www.stats.gov.cn/tjsj/pcsj/rkpc/6rp/html/"); }@Overridepublic void visit(Page page) {// 获取urlString url = page.getWebURL().getURL();Document doc = null;//       if (page.getParseData() instanceof HtmlParseData) {//            HtmlParseData htmlParseData = (HtmlParseData) page.getParseData();
//            String text = htmlParseData.getText();
//            String html = htmlParseData.getHtml();
//            doc = Jsoup.parse(html,"GBK");
//      }try {doc = Jsoup.parse(new URL(url).openStream(), "GBK", url);} catch (MalformedURLException e1) {e1.printStackTrace();} catch (IOException e1) {e1.printStackTrace();}Elements trs = doc.body().select("div").select("table").select("tr");System.out.println("extraction succeed");//to csv filetry {for (Element tr : trs) {if(pass>=5) {List<String> records = new ArrayList<String>();Elements tds = tr.select("td");if(tds.size()==16 && !tds.get(0).text().equals("")) {for (Element td : tds) {String s = td.text();System.out.print(s+",");   //console 显示正常
//                          s = new String(s.getBytes("GBK"), "UTF-8");
//                          System.out.print(s+";"); //UTF-8 records.add(s);}System.out.println("");csvFilePrinter.printRecord(records);}} else {pass++; //extract data from trs[5] }}System.out.println("CSV file created successfully ~~~");} catch (IOException e) {e.printStackTrace();} finally {try {fileWriter.flush();fileWriter.close();csvFilePrinter.close();} catch (IOException e) {e.printStackTrace();}}}}

Controller.java

package com.java.crawler;import edu.uci.ics.crawler4j.crawler.CrawlConfig;
import edu.uci.ics.crawler4j.crawler.CrawlController;
import edu.uci.ics.crawler4j.fetcher.PageFetcher;
import edu.uci.ics.crawler4j.robotstxt.RobotstxtConfig;
import edu.uci.ics.crawler4j.robotstxt.RobotstxtServer;public class Controller {public static void main(String[] args) throws Exception {String crawlStorageFolder = "E:\\eclipse_jee_2019-06\\work_place\\Crawler4j01\\res"; // 定义爬虫数据存储位置int numberOfCrawlers = 1; // 定义爬虫数量,用于多线程爬虫CrawlConfig config = new CrawlConfig(); // 定义爬虫配置config.setCrawlStorageFolder(crawlStorageFolder); // 设置爬虫文件存储位置PageFetcher pageFetcher = new PageFetcher(config); // 实例化爬虫机器人配置RobotstxtConfig robotstxtConfig = new RobotstxtConfig();        RobotstxtServer robotstxtServer = new RobotstxtServer(robotstxtConfig, pageFetcher); // 实例化爬虫控制器CrawlController controller = new CrawlController(config, pageFetcher, robotstxtServer);controller.addSeed("http://www.stats.gov.cn/tjsj/pcsj/rkpc/6rp/html/B0801a.htm");controller.start(MyCrawler.class, numberOfCrawlers);controller.waitUntilFinish();System.out.println("crawler finished");}
}

运行结果

基于Crawler4j的Java爬虫实践相关推荐

  1. 基于Crawler4j的WEB爬虫

    基于Crawler4j的WEB爬虫 一.WEB爬虫介绍 爬虫,Crawler,最早被用于搜索引擎收录页面,例如百度蜘蛛等等.说简单点,原理就是根据一些规则,获取url和页面,再从获取到的页面中继续提取 ...

  2. 基于SpringBoot的Java爬虫-京东商品页

    基于SpringBoot的Java爬虫项目-京东商品页 一. 爬取(部分)效果图 二.遇到的各种BUG 三. 项目目录结构 四. 具体代码详解 4.1 配置文件添加依赖 4.2 application ...

  3. 基于Jsoup的Java爬虫-爬取必应壁纸网站的壁纸(Java静态壁纸爬虫实例)

    准备阶段 1.必应壁纸网站:https://bing.ioliu.cn(爬取对象网站) 2.Jsoup包下载地址:https://jsoup.org/download(以下代码需要用到该包,记得导入包 ...

  4. Java爬虫实践之获取历史上的今天

    概述 我们可以在一些网站上看到一些文字,显示了历史上的今天发生了什么事情.例如CSDN的登录页面: 而我们今天的目标是百度搜索上显示的历史上的今天,如下: (注:图片无法显示) 通过历史上的今天访问查 ...

  5. JAVA爬虫实践(实践二:博客园)

    分析博客园网站的请求可以发现,博客园的分页请求为POST方式,和知乎的滚动加载类似. 不同的是请求响应返回的是HTML而不是JSON. 这样可以套用上一篇爬知乎的代码,需要修改的部分就是POST方法传 ...

  6. Java爬虫实践:Jsoup+HttpUnit爬取今日头条、网易、搜狐、凤凰新闻

    0x0 背景 最近学习爬虫,分析了几种主流的爬虫框架,决定使用最原始的两大框架进行练手: Jsoup&HttpUnit 其中jsoup可以获取静态页面,并解析页面标签,最主要的是,可以采用类似 ...

  7. 基于jsoup的java爬虫-爬取豆瓣小组租房信息

    主要框架为springboot+mybatis+jsoup jsoup官方文档:https://www.open-open.com/jsoup/ 爬取的豆瓣网址为:https://www.douban ...

  8. 手把手Java爬虫教学 - 2. 爬虫项目创建 需求说明

    上一篇博客我们简单的了解了一波爬虫,知道了什么是爬虫,爬虫的作用,下面我们就开始着手自己来创建一个爬虫.(项目源码估计你们得看最后的几个博客,因为我这个是一边写代码一边写博客的,所以说没有办法那么快提 ...

  9. 基于Java爬虫的课堂考勤管理系统(毕业设计论文)

    开发环境和选用的架构: 本系统中采用的开发环境是Windows10+JDK8+Tomcat8+MySQL5.6 使用IDEA作为开发工具,GIT用作版本控制,Maven管理依赖 采用SSM+Sprin ...

最新文章

  1. Google 出品的 Java 编码规范,权威又科学,强烈推荐
  2. python官网下载步骤linux-linux下安装python
  3. 转载-如何做好项目的需求与业务调研
  4. linux操作系统之线程同步及互斥量
  5. Android代码导出数据库,导入/导出到android sqlite数据库
  6. mysql 攻击密码_MySQL用户Root密码为弱口令的攻击
  7. Impala-shell 启动异常 - Python版本为3.x 启动脚本为2.x
  8. oracle-01940,ORA-01940: 无法删除当前已连接的用户的错误,该如何解决呢?
  9. 【★】路由环路大总结!
  10. 学习c++一点一滴----读取注册表
  11. Hive窗口函数经典案例(保姆级案例)
  12. 爬虫或日常使用过程中解决ip被封锁IP限制的几种方法
  13. vue项目整合aliplayer阿里云视频
  14. 基于stc8a的ad9833模块的例程的使用
  15. 修正的判定条件覆盖例题_语句覆盖、判断覆盖、条件覆盖、条件判定组合覆盖、多条件覆盖、修正条件覆盖...
  16. 阿里云云计算助理工程师认证(ACA)详细解读
  17. C#时间显示格式(12小时制VS24小时制)
  18. seo优化什么意思?
  19. java开发用allman风格_缩进风格
  20. python爬取百度新闻采集教程

热门文章

  1. IR2103使用实例
  2. Windows安装Python-docx三方库(保姆级教程)
  3. Serv-U15.1.5安装配置和外网访问使用
  4. 服务器测试常用指令-分测试内容
  5. sql语句计算出每个月的天数
  6. 区块链去中心化等特点
  7. 【有利可图网】PS实战系列:制作开阔大气的海洋生态立体字
  8. 数据库优化之百万级数据方案
  9. ros基础之古月居(发布者创建)
  10. DNS基础的相关学习