基于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
4.0.0
com.java.crawler4j
myCrawler4j
0.0.1-SNAPSHOT
alimaven
aliyun maven
http://maven.aliyun.com/nexus/content/groups/public/
log4j
log4j
1.2.17
org.slf4j
slf4j-log4j12
1.7.10
edu.uci.ics
crawler4j
4.4.0
com.sleepycat
je
5.0.73
org.jsoup
jsoup
1.8.2
org.apache.commons
commons-csv
1.4
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 csv
private final String FILE_NAME = "res\\result.csv";
//csv filepath
private static final String NEW_LINE_SEPARATOR = "\n";
//CSV deliminator
private static final Object [] FILE_HEADER = {
"地区","60岁及以上人口:合计","男","女","健康:小计","男","女",
"基本健康:小计","男","女","不健康,但生活能自理:小计","男","女",
"生活不能自理:小计","男","女"};
//CSV header
private OutputStreamWriter fileWriter = null;
private CSVPrinter csvFilePrinter = null;
private CSVFormat format = CSVFormat.DEFAULT.withRecordSeparator(NEW_LINE_SEPARATOR);
private int pass=0;
private File csv;
//constructor
public 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);
}
//crawler4j
private final static Pattern FILTERS = Pattern.compile(".*(\\.(css|js|gif|jpg" + "|png|mp3|mp3|zip|gz))$");
@Override
public boolean shouldVisit(Page referringPage, WebURL url) {
String href = https://www.it610.com/article/url.getURL().toLowerCase();
return !FILTERS.matcher(href).matches() // 正则匹配,过滤掉我们不需要的后缀文件
&& href.startsWith("http://www.stats.gov.cn/tjsj/pcsj/rkpc/6rp/html/");
} @Override
public void visit(Page page) {
// 获取url
String url = page.getWebURL().getURL();
Document doc = null;
//if (page.getParseData() instanceof HtmlParseData) {
//HtmlParseData htmlParseData = https://www.it610.com/article/(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 file
try {
for (Element tr : trs) {
if(pass>=5) {
List> records = new ArrayList>();
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爬虫实践】运行结果
文章图片
推荐阅读
- 爬虫|若想拿下爬虫大单,怎能不会逆向爬虫,价值过万的逆向爬虫教程限时分享
- python|尚硅谷python爬虫(二)-解析方法
- web挖洞|HACK学习黑帽子Python--漏洞检测脚本快速编写
- Pyecharts|Pyecharts 猎聘招聘数据可视化
- Python爬虫笔记|Python爬虫学习笔记_DAY_17_Python爬虫之使用cookie绕过登录的介绍【Python爬虫】
- Python爬虫笔记|Python爬虫学习笔记_DAY_19_Python爬虫之代理ip与代理池的使用介绍【Python爬虫】
- Python爬虫笔记|Python爬虫学习笔记_DAY_18_Python爬虫之handler处理器的使用【Python爬虫】
- python|用 Python 写一副春联&福字,把最好的祝福,送给重要的人
- 爬虫|淘宝商品数据爬取
- 爬虫学习历程小记