java爬虫抓取网页数据(Java开发的爬虫框架很容易上手,输出结果:如果你和我一样)
优采云 发布时间: 2022-03-10 18:11java爬虫抓取网页数据(Java开发的爬虫框架很容易上手,输出结果:如果你和我一样)
爬虫初学者,WebMagic作为Java开发的爬虫框架很容易上手,下面看一个简单的例子。
WebMagic 框架简介
WebMagic 框架由四个组件组成,PageProcessor、Scheduler、Downloader 和 Pipeline。
这四个组件分别对应了爬虫生命周期中的处理、管理、下载和持久化的功能。
这四个组件是Spider中的属性,爬虫框架是通过Spider来启动和管理的。
WebMagic的整体架构图如下:
四个组件
PageProcessor 负责解析页面、提取有用信息和发现新链接。你需要定义自己。
Scheduler 负责管理要爬取的 URL,以及一些去重工作。一般不需要自己自定义Scheduler。
Pipeline 负责提取结果的处理,包括计算、持久化到文件、数据库等。
下载器负责从 Internet 下载页面以进行后续处理。通常你不需要自己实现它。
数据流对象
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());
}
}<br />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());
}
}<br />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,组)
这里@attr和group是可选的,默认是group0
不支持
使用起来非常方便。