java爬虫抓取网页数据(Java开发的爬虫框架很容易上手,输出结果:如果你和我一样)
优采云 发布时间: 2021-11-25 01:16java爬虫抓取网页数据(Java开发的爬虫框架很容易上手,输出结果:如果你和我一样)
对于初学者来说,WebMagic 作为 Java 开发的爬虫框架很容易使用。我们通过一个简单的例子来了解一下。
WebMagic 框架介绍
WebMagic 框架收录四个组件,PageProcessor、Scheduler、Downloader 和 Pipeline。
这四个组件分别对应爬虫生命周期中的处理、管理、下载、持久化功能。
这四个组件是Spider中的属性,爬虫框架由Spider启动和管理。
WebMagic 的整体结构如下:
四大组件
PageProcessor 负责解析页面、提取有用信息和发现新链接。您需要自己定义它。
Scheduler 负责管理要爬取的 URL 和一些重复数据删除工作。一般不需要自己自定义Scheduler。
Pipeline 负责提取结果的处理,包括计算、持久化到文件、数据库等。
Downloader 负责从网上下载页面进行后续处理。通常,您不需要自己实现它。
用于数据流的对象
Request是对URL地址的一层封装,一个Request对应一个URL地址。
Page 代表从 Downloader 下载的页面——可以是 HTML、JSON 或其他文本格式的内容。
ResultItems相当于一个Map,保存PageProcessor处理的结果,供Pipeline使用。
环境配置
使用Maven添加依赖的jar包。
us.codecraft
webmagic-core
0.7.3
us.codecraft
webmagic-extension
0.7.3
org.slf4j
slf4j-log4j12
或者直接点我下载。
添加jar包之后,所有的准备工作就完成了,是不是很简单?
下面我们来测试一下。
package edu.heu.spider;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.pipeline.ConsolePipeline;
import us.codecraft.webmagic.processor.PageProcessor;
/**
* @ClassName: MyCnblogsSpider
* @author LJH
* @date 2017年11月26日 下午4:41:40
*/
public class MyCnblogsSpider implements PageProcessor {
private Site site = Site.me().setRetryTimes(3).setSleepTime(100);
public Site getSite() {
return site;
}
public void process(Page page) {
if (!page.getUrl().regex("http://www.cnblogs.com/[a-z 0-9 -]+/p/[0-9]{7}.html").match()) {
page.addTargetRequests(
page.getHtml().xpath("//*[@id=\"mainContent\"]/div/div/div[@class=\"postTitle\"]/a/@href").all());
} else {
page.putField(page.getHtml().xpath("//*[@id=\"cb_post_title_url\"]/text()").toString(),
page.getHtml().xpath("//*[@id=\"cb_post_title_url\"]/@href").toString());
}
}
public static void main(String[] args) {
Spider.create(new MyCnblogsSpider()).addUrl("http://www.cnblogs.com/justcooooode/")
.addPipeline(new ConsolePipeline()).run();
}
}
输出结果:
如果你和我一样,之前没有使用过 log4j,可能会出现以下警告:
这是因为缺少配置文件。在资源目录新建一个log4j.properties文件,粘贴下面的配置信息。
该目录可以定义为您自己的文件夹。
# 全局日志级别设定 ,file
log4j.rootLogger=INFO, stdout, file
# 自定义包路径LOG级别
log4j.logger.org.quartz=WARN, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{MM-dd HH:mm:ss}[%p]%m%n
# Output to the File
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=D:\\MyEclipse2017Workspaces\\webmagic\\webmagic.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%n%-d{MM-dd HH:mm:ss}-%C.%M()%n[%p]%m%n
立即尝试,没有警告。
爬取列表类 网站 示例
列表爬取的思路非常相似。首先判断是否是列表页。如果是,将 文章 url 添加到抓取队列中。如果不是,说明此时是一个文章页面,直接爬取你想要的。内容很好。
选择列表类型 文章 网站:
首先判断是文章还是列表。查看几页后,可以找到规则并使用正则表达式进行区分。
page.getUrl().regex("https://voice\\.hupu\\.com/nba/[0-9]{7}\\.html").match()
如果满足上述正则表达式,则该url对应一个文章页面。
接下来提取需要爬取的内容,我选择了xPath(浏览器自带,可以直接粘贴)。
WebMagic 框架支持多种提取方式,包括xPath、css 选择器、正则表达式,所有链接都可以通过links() 方法进行选择。
提取前记得通过getHtml()获取html对象,通过html对象使用提取方法。
ps:WebMagic 似乎不支持 xPath 中的 last() 方法。如果你使用它,你可以考虑其他方法。
然后使用 page.putFiled(String key, Object field) 方法将你想要的内容放入一个键值对中。
page.putField("Title", page.getHtml().xpath("/html/body/div[4]/div[1]/div[1]/h1/text()").toString());
page.putField("Content", page.getHtml().xpath("/html/body/div[4]/div[1]/div[2]/div/div[2]/p/text()").all().toString());
如果文章页面的规律性不满足,说明这是一个列表页面。这时候页面中文章的url必须通过xPath来定位。
page.getHtml().xpath("/html/body/div[3]/div[1]/div[2]/ul/li/div[1]/h4/a/@href").all();
这时候就已经得到了要爬取的url列表,可以通过addTargetRequests方法将它们加入到队列中。
最后实现翻页。同理,WebMagic 会自动加入爬取队列。
page.getHtml().xpath("/html/body/div[3]/div[1]/div[3]/a[@class='page-btn-prev']/@href").all()
以下是完整代码。我自己实现了一个 MysqlPipeline 类。使用Mybatis时,可以将抓取到的数据直接持久化到数据库中。
您还可以使用内置的 ConsolePipeline 或 FilePipeline 等。
package edu.heu.spider;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import edu.heu.domain.News;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;
import us.codecraft.webmagic.processor.PageProcessor;
/**
* @ClassName: HupuNewsSpider
* @author LJH
* @date 2017年11月27日 下午4:54:48
*/
public class HupuNewsSpider implements PageProcessor {
// 抓取网站的相关配置,包括编码、抓取间隔、重试次数等
private Site site = Site.me().setRetryTimes(3).setSleepTime(100);
public Site getSite() {
return site;
}
public void process(Page page) {
// 文章页,匹配 https://voice.hupu.com/nba/七位数字.html
if (page.getUrl().regex("https://voice\\.hupu\\.com/nba/[0-9]{7}\\.html").match()) {
page.putField("Title", page.getHtml().xpath("/html/body/div[4]/div[1]/div[1]/h1/text()").toString());
page.putField("Content",
page.getHtml().xpath("/html/body/div[4]/div[1]/div[2]/div/div[2]/p/text()").all().toString());
}
// 列表页
else {
// 文章url
page.addTargetRequests(
page.getHtml().xpath("/html/body/div[3]/div[1]/div[2]/ul/li/div[1]/h4/a/@href").all());
// 翻页url
page.addTargetRequests(
page.getHtml().xpath("/html/body/div[3]/div[1]/div[3]/a[@class='page-btn-prev']/@href").all());
}
}
public static void main(String[] args) {
Spider.create(new HupuNewsSpider()).addUrl("https://voice.hupu.com/nba/1").addPipeline(new MysqlPipeline())
.thread(3).run();
}
}
// 自定义实现Pipeline接口
class MysqlPipeline implements Pipeline {
public MysqlPipeline() {
}
public void process(ResultItems resultitems, Task task) {
Map mapResults = resultitems.getAll();
Iterator iter = mapResults.entrySet().iterator();
Map.Entry entry;
// 输出到控制台
while (iter.hasNext()) {
entry = iter.next();
System.out.println(entry.getKey() + ":" + entry.getValue());
}
// 持久化
News news = new News();
if (!mapResults.get("Title").equals("")) {
news.setTitle((String) mapResults.get("Title"));
news.setContent((String) mapResults.get("Content"));
}
try {
InputStream is = Resources.getResourceAsStream("conf.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sessionFactory.openSession();
session.insert("add", news);
session.commit();
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
查看数据库:
爬取的数据一直静静地躺在数据库中。
官方文档还介绍了通过注解实现各种功能,非常简单灵活。
使用xPath时要注意,框架作者自定义了几个功能:
表达式描述XPath1.0
文字(n)
第n个直接文本子节点,0表示全部
纯文本
所有文本()
所有直接和间接文本子节点
不支持
整洁的文本()
所有直接和间接文本子节点,并用换行符替换一些标签,使纯文本显示更整洁
不支持
html()
内部html,不包括标签的html本身
不支持
外层Html()
内部html,包括标签的html本身
不支持
正则表达式(@attr,expr,group)
这里@attr 和 group 都是可选的,默认是 group0
不支持
使用起来非常方便。