webmagic学习-使用注解编写爬虫
写在前面:
官方文档:http://webmagic.io/docs/zh/posts/ch5-annotation/README.html
WebMagic支持使用独有的注解风格编写一个爬虫,引入webmagic-extension包即可使用此功能。
在注解模式下,使用一个简单的Model对象加上注解,可以用极少的代码量就完成一个爬虫的编写。
注解模式的开发方式是这样的:
<!--[if !supportLists]-->1. <!--[endif]-->首先定义你需要抽取的数据,并编写Model类。
<!--[if !supportLists]-->2. <!--[endif]-->在类上写明@TargetUrl注解,定义对哪些URL进行下载和抽取。
<!--[if !supportLists]-->3. <!--[endif]-->在类的字段上加上@ExtractBy注解,定义这个字段使用什么方式进行抽取。
<!--[if !supportLists]-->4. <!--[endif]-->定义结果的存储方式。实现PageModelPipeline即可。
下面是我用webmagic的注解方式对芝麻代理(http://http.zhimaruanjian.com/)网站写的简单爬虫;
1、创建maven项目,引入需要的包;这里是我的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>
<parent>
<artifactId>webmagic-parent</artifactId>
<groupId>us.codecraft</groupId>
<version>0.5.3</version>
</parent>
<groupId>webmagic</groupId>
<artifactId>webmagic-test</artifactId>
<!-- 这个提示让我remove掉 -->
<version>0.5.3</version>
<packaging>jar</packaging>
<name>webmagic-test</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<webmagic.version>0.5.3</webmagic.version>
</properties>
<dependencies>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-core</artifactId>
<version>${webmagic.version}</version>
</dependency>
<!-- 根据上文所说的:引入webmagic-extension包即可使用此功能 -->
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-extension</artifactId>
<version>${webmagic.version}</version>
</dependency>
</dependencies>
</project>
2、上面说了,使用注解方式写webmagic爬虫,需要写一个Model类。这个Model类里面有需要pipeline持久化的字段,字段上通过@ExtractBy注解来指定这个字段抓取的规则;在类名上使用@TargetUrl注解,标识哪些url需要解析(相当于原来的us.codecraft.webmagic.processor.PageProcessor.process(Page)方法);最后写个main方法,并用OOSpider类创建爬虫程序。(别忘了写getter/setter方法)
package com.lacerta.ipproxy.OOpageprocess;
import java.util.List;import us.codecraft.webmagic.Site;import us.codecraft.webmagic.model.OOSpider;import us.codecraft.webmagic.model.annotation.ExtractBy;import us.codecraft.webmagic.model.annotation.TargetUrl;import us.codecraft.webmagic.scheduler.RedisScheduler;
@TargetUrl(value = "(http://http.zhimaruanjian.com/proxylist/(\\d)/)|(http://http.zhimaruanjian.com/inha/(\\d)+/)")
public class IpProxyModel {
@ExtractBy("//td[@data-title='IP']/text()")
List<String> IP;
@ExtractBy("//td[@data-title='PORT']/text()")
List<String> PORT;
@ExtractBy("//td[@data-title='匿名度']/text()")
List<String> 匿名度;
@ExtractBy("//td[@data-title='类型']/text()")
List<String> 类型;
@ExtractBy("//td[@data-title='get/post支持']/text()")
List<String> get_post支持;
@ExtractBy("//td[@data-title='位置']/text()")
List<String> 位置;
@ExtractBy("//td[@data-title='响应速度']/text()")
List<String> 响应速度;
@ExtractBy("//td[@data-title='最后验证时间']/text()")
List<String> 最后验证时间;
public static void main(String[] args) {
OOSpider.create(Site.me().setDomain("OOwww.kuaidaili.com"),
new new ConsolePageModelPipeline()//这里使用的Pipeline是打印到控制台。
, IpProxyModel.class)
.setScheduler(new RedisScheduler("10.2.1.203"))//使用redis做为我的scheduler,参数是redis的ip地址
.addUrl("http://www.kuaidaili.com/proxylist/1/")//
.addUrl("http://http.zhimaruanjian.com/")//
.thread(3)//
.run();
}
//这里省略了所有字段的getter/setter方法。
}
如果不会使用RedisScheduler的童鞋可以使用默认的QueueScheduler(也就是不写.setScheduler(new RedisScheduler("10.2.1.203"))这一行就行了)到这里这个基于注解的webmagic爬虫就写好了。点击F11,让爬虫飞一会。。。。可以在控制台看到打印的结果。如果相应字段打印结果不正确,就要修改@ExtractBy注解的提取规则了。
3、是不是觉得控制台打印的结果太乱了?是不是觉得垂直爬虫爬取的结构化数据应该保存到文件或者数据库中呢?好办,只要实us.codecraft.webmagic.pipeline.PageModelPipeline<T>这个借口就行了。这里我参考官方自带的us.codecraft.webmagic.pipeline.FilePageModelPipeline自己写了一个com.lacerta.ipproxy.OOpageprocess.IpProxyFilePageModelPipeline,这个PageModelPipeline会以我自定义的方式,把爬取的结构化数据保存到文件中。那么,上代码:
package com.lacerta.ipproxy.OOpageprocess;
import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;import java.util.List;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import us.codecraft.webmagic.Task;import us.codecraft.webmagic.model.HasKey;import us.codecraft.webmagic.pipeline.PageModelPipeline;import us.codecraft.webmagic.utils.FilePersistentBase;
public class IpProxyFilePageModelPipeline extends FilePersistentBase implements PageModelPipeline<IpProxyModel> {
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* new JsonFilePageModelPipeline with default path "/data/webmagic/"
*/
public IpProxyFilePageModelPipeline() {
setPath("/data/webmagic/");
}
public IpProxyFilePageModelPipeline(String path) {
setPath(path);
}
private boolean flag = true; // 标志位,如果true就writer.
@Override
public void process(IpProxyModel ipProxyModel, Task task) {
String path = this.path + PATH_SEPERATOR + task.getUUID() + PATH_SEPERATOR;
BufferedWriter writer = null;
try {
String filename;
if (ipProxyModel instanceof HasKey) {
filename = path + ((HasKey) ipProxyModel).key() + ".txt";
} else {
filename = path + "IpProxyFileResult.txt";
}
writer = new BufferedWriter(new FileWriter(getFile(filename), true));
if (flag) {
writer.write("IP\tPORT\t匿名度\t类型\tGet/post支持\t位置\t响应速度\t最后验证时间\r\n");
flag = false;
}
List<String> ip = ipProxyModel.getIP();
List<String> port = ipProxyModel.getPORT();
List<String> 匿名度 = ipProxyModel.get匿名度();
List<String> 类型 = ipProxyModel.get类型();
List<String> get_post支持 = ipProxyModel.getGet_post支持();
List<String> 位置 = ipProxyModel.get位置();
List<String> 响应速度 = ipProxyModel.get响应速度();
List<String> 最后验证时间 = ipProxyModel.get最后验证时间();
if (get_post支持.size() == 0) {
for (int i = 0; i < ip.size(); i++) {
writer.write(ip.get(i) + "\t" + port.get(i) + "\t" + 匿名度.get(i) + "\t" + 类型.get(i) + "\tnull\t"
+ 位置.get(i) + "\t" + 响应速度.get(i) + "\t" + 最后验证时间.get(i) + "\r\n");
}
} else {
for (int i = 0; i < ip.size(); i++) {
writer.write(ip.get(i) + "\t" + port.get(i) + "\t" + 匿名度.get(i) + "\t" + 类型.get(i) + "\t"
+ get_post支持.get(i) + "\t" + 位置.get(i) + "\t" + 响应速度.get(i) + "\t" + 最后验证时间.get(i)
+ "\r\n");
}
}
} catch (IOException e) {
logger.warn("write file error", e);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
其实也没啥,官方提供了us.codecraft.webmagic.pipeline.FilePageModelPipeline,照着抄一个就行了。
最后,看数据吧:(路径:F:\spider\IpProxyModel\OOwww.kuaidaili.com\IpProxyFileResult.txt)这里只复制了前40条记录。
IPPORT匿名度类型Get/post支持位置响应速度最后验证时间218.20.236.2498118高匿名HTTP, HTTPSGET, POST中国 广东省 广州市 电信2秒2分钟前114.227.62.1508088高匿名HTTP, HTTPSGET, POST中国 江苏省 常州市 电信1秒2分钟前183.153.3.96808高匿名HTTP, HTTPSGET, POST中国 浙江省 台州市 电信1秒2分钟前117.86.12.191808高匿名HTTPGET, POST中国 江苏省 南通市 电信3秒2分钟前116.17.136.1869797透明HTTP, HTTPSGET, POST中国 广东省 惠州市 电信1秒1分钟前59.78.17.1981080高匿名HTTP, HTTPSGET, POST中国 上海市 上海市 教育网2秒4分钟前121.35.130.1179797透明HTTP, HTTPSGET, POST中国 广东省 深圳市 电信2秒7分钟前183.141.107.543128高匿名HTTP, HTTPSGET, POST中国 浙江省 嘉兴市 电信3秒10分钟前115.29.37.868088高匿名HTTPGET, POST中国 山东省 青岛市 阿里云2秒13分钟前59.66.166.518123高匿名HTTP, HTTPSGET, POST中国 北京市 北京市 教育网1秒16分钟前27.46.50.228888透明HTTP, HTTPSGET, POST中国 广东省 深圳市 联通3秒19分钟前60.191.164.833128透明HTTPGET, POST中国 浙江省 台州市 电信0.4秒23分钟前110.73.40.2468123高匿名HTTP, HTTPSGET, POST广西壮族自治区南宁市 联通3秒26分钟前119.86.48.308998高匿名HTTP, HTTPSGET, POST中国 重庆市 重庆市 电信1秒28分钟前101.6.52.1998123高匿名HTTPGET, POST中国 北京市 北京市 教育网2秒31分钟前112.92.218.2219797透明HTTP, HTTPSGET, POST中国 广东省 中山市 联通3秒34分钟前119.57.112.1308080透明HTTP, HTTPSGET, POST中国 北京市 北京市 3秒38分钟前114.250.48.1119000透明HTTP, HTTPSGET, POST中国 北京市 北京市 联通2秒40分钟前119.122.212.369000透明HTTP, HTTPSGET, POST中国 广东省 深圳市 电信2秒44分钟前113.245.57.2018118高匿名HTTP, HTTPSGET, POST中国 湖南省 株洲市 电信1秒46分钟前115.200.164.88998高匿名HTTP, HTTPSGET, POST中国 浙江省 杭州市 电信1秒49分钟前14.112.208.1559999透明HTTP, HTTPSGET, POST中国 广东省 惠州市 电信2秒53分钟前113.110.208.1249000透明HTTP, HTTPSGET, POST中国 广东省 深圳市 电信1秒55分钟前182.37.126.246808高匿名HTTP, HTTPSGET, POST中国 山东省 日照市 电信0.4秒59分钟前123.127.8.24880高匿名HTTP, HTTPSGET, POST中国 北京市 北京市 联通2秒1小时前122.96.59.10682高匿名HTTPGET, POST江苏省南京市 联通1秒1小时前111.13.7.4282高匿名HTTPGET, POST中国 北京市 北京市 移动2秒1小时前219.216.122.2508998高匿名HTTP, HTTPSGET, POST中国 辽宁省 沈阳市 教育网2秒1小时前117.23.248.2348118高匿名HTTPGET, POST中国 陕西省 宝鸡市 电信2秒1小时前171.38.78.278123高匿名HTTP, HTTPSGET, POST广西壮族自治区玉林市 联通1秒1小时前171.110.218.2109000透明HTTP, HTTPSGET, POST中国 广西壮族自治区 来宾市 电信2秒1小时前183.141.154.1253128高匿名HTTP, HTTPSGET, POST中国 浙江省 嘉兴市 电信2秒1小时前171.11.186.1768118高匿名HTTPGET, POST中国 河南省 商丘市 电信2秒1小时前124.133.154.838090匿名HTTPGET, POST中国 山东省 济南市 联通2秒1小时前118.81.251.609797透明HTTP, HTTPSGET, POST中国 山西省 太原市 联通0.8秒1小时前115.229.99.21808高匿名HTTP, HTTPSGET, POST中国 浙江省 嘉兴市 电信2秒1小时前124.193.7.2473128透明HTTPGET, POST北京市 鹏博士宽带2秒1小时前125.33.253.879797透明HTTP, HTTPSGET, POST中国 北京市 北京市 联通0.7秒1小时前221.227.131.1478000高匿名HTTPGET, POST中国 江苏省 南通市 电信3秒1小时前
4、源码解读:
参考:http://m.blog.csdn.net/article/details?id=51971708
OOSpider这个类继承Spider,但是对于四大组件中的PageProcesser做了更改
Pipeline需要继承PageModelPipeline,OOSpider成员变量有个ModelPipeline,ModelPipeline首先执行,然后调用用户自己实现的PageModelPipeline。
<!--[if !supportLists]-->· <!--[endif]-->初始化一个OOSpider:
public OOSpider(Site site, PageModelPipeline pageModelPipeline, Class... pageModels) {
this(ModelPageProcessor.create(site, pageModels));
this.modelPipeline = new ModelPipeline();
super.addPipeline(modelPipeline);
for (Class pageModel : pageModels) {
if (pageModelPipeline != null) {
this.modelPipeline.put(pageModel, pageModelPipeline);
}
pageModelClasses.add(pageModel);
}
}
<!--[if !supportLists]-->· <!--[endif]-->ModelPageProcessor,这个类继承PageProcessor,所以在主流程中将会执行对Page的解析工作(如果对主流程不熟悉那就先看看我的第一篇博客), 具体的解析工作是由PageModelExtractor执行,每个包含注解的class都会对应一个PageModelExtractor。
写在后面:
今天其实想做爬虫的ip代理,但是昨天晚上回家路上没事时把官方文档的这一章看完了,正好练习一下。
再说爬虫iP代理:
先说us.codecraft.webmagic.Site.setCycleRetryTimes(int)方法:这个方法在当前url download失败后,会添加到scheduler最后,int参数,就是这样重复的次数。
us.codecraft.webmagic.Site.setHttpProxyPool(List<String[]>)方法用户设置代理连接池;但是设置后从来就没有成功过:
不知道咋回事啊。要上网找一些资料参考一下。
相关推荐
webmagic的核心非常简单,但是覆盖爬虫的整个流程,也是很好的学习爬虫开发的材料。 本项目的主要特色: 完全模块化的设计,强大的可扩展性。 核心简单但是涵盖爬虫的全部流程,灵活而强大,也是学习爬虫入门的好...
Java开发案例-springboot-23-自定义注解实现post请求接收单个参数值-源代码+文档.rar Java开发案例-springboot-23-自定义注解实现post请求接收单个参数值-源代码+文档.rar Java开发案例-springboot-23-自定义注解...
通过阅读《黑马程序员---注解归纳》这篇博客,你将能够深入理解注解的工作原理,学习如何利用注解提升代码质量,并掌握在不同场景下使用注解的最佳实践。同时,配合提供的`annotation.txt`文件,你可能能获取到更多...
Spring Boot 整合爬虫框架WebMagic并存储数据到数据库是一项常见的数据抓取与处理任务。WebMagic是一个轻量级的Java爬虫框架,而Spring Boot则是流行的微服务开发框架,两者结合能方便地构建高效稳定的爬虫服务。...
---注解---.xmind Java常用各种注解
JAX-RS 注解及使用方法 JAX-RS(Java API for RESTful Web Services)是一种基于 Java 语言的 RESTful Web 服务框架,它提供了一种简单、灵活的方式来开发 RESTful Web 服务。JAX-RS 使用注解来定义资源的行为和...
Java设计模式、程序设计、反射、注解和泛型是Java开发中的核心概念,它们各自在不同的场景下发挥着重要作用,构建出高效、可维护的软件系统。 首先,Java设计模式是面向对象编程中的一种最佳实践,是解决常见问题的...
Spring系列--注解.md
例如,我们可以使用Spring Boot的DataSourceAutoConfiguration和DataSourceTransactionManager,结合@Configuration和@Bean注解来配置多个数据源,并通过AOP切面来管理事务,确保数据的一致性。 总结来说,这个...
[[springBoot系列]--springBoot注解大全]
8. **MyBatis配置**: 虽然本示例强调注解配置,但还需要在MyBatis的配置文件中启用注解处理器,告诉MyBatis使用注解来解析Mapper接口。 9. **SqlSession和ResultMap**: 在执行动态SQL时,我们需要使用SqlSession...
spring3-mvc注解教程
### 知识点一:WebMagic概述 #### 设计思想 - **专注单一领域**:WebMagic专注于Web爬虫这一特定领域,旨在提供简洁、高效且易于...通过上述知识点的学习,你将能够更好地理解和使用WebMagic进行高效的网络爬虫开发。
Java基础知识学习教程-12注解和反射 本章节主要讲述Java中的注解和反射机制,涵盖了注解的基本概念、内置注解、元注解和自定义注解等知识点,并引入反射机制,详细介绍了反射的概念、Class类、通过反射获取注解、...
【JavaSE进阶-09-注解1】章节主要介绍了Java中的注解(Annotation)概念及其使用,包括内置注释、自定义注释以及如何为注解添加变量和默认值。 1. **注解的作用**: - **编写文档**:通过元数据生成文档,如...
通过使用注解,开发者可以轻松地在代码中定义安全策略,而无需编写大量的XML配置。这极大地提高了开发效率,同时也使得代码更加可读和可维护。 1. **@EnableWebSecurity**:这是开启Spring Security的基础注解,它...
3. **创建Mapper接口**:在Java代码中定义Mapper接口,用`@Mapper`注解标记,然后在接口方法上使用`@Select`, `@Insert`, `@Update`, `@Delete`等注解来编写SQL语句。 4. **配置SqlSessionFactory**:SpringBoot会...
spring-aop注解用到的jar包,解压后直接导入即可使用。