1,学习gecco
源码地址:https://gitee.com/xtuhcy/gecco
2,运行源码。
导入到idea 里面。
运行第一个demo 在text 里面可以找到
@Gecco(pipelines="consolePipeline")
public class CommonCrawler implements HtmlBean {
private static final long serialVersionUID = -8870768223740844229L;
@Request
private HttpRequest request;
@Text(own=false)
@HtmlField(cssPath="body")
private String body;
public HttpRequest getRequest() {
return request;
}
public void setRequest(HttpRequest request) {
this.request = request;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public static void main(String[] args) {
GeccoEngine.create()
.classpath("com.geccocrawler.gecco.demo")
.start("https://www.baidu.com/")
.interval(2000)
.start();
}
}
代码说明
接口HtmlBean说明该爬虫是一个解析html页面的爬虫(gecco还支持json格式的解析)
注解@Gecco告知该爬虫匹配的url格式(matchUrl)和内容抽取后的bean处理类(pipelines处理类采用管道过滤器模式,可以定义多个处理类)。
注解@RequestParameter可以注入url中的请求参数,如@RequestParameter("user")表示匹配url中的{user}
注解@HtmlField表示抽取html中的元素,cssPath采用类似jquery的css selector选取元素
注解@Text表示获取@HtmlField抽取出来的元素的text内容
注解@Html表示获取@HtmlField抽取出来的元素的html内容(如果不指定默认为@Html)
GeccoEngine表示爬虫引擎,通过create()初始化,通过start()/run()运行。可以配置一些启动参数如:扫描@Gecco注解的包名classpath;开始抓取的url地址star;抓取线程数thread;抓取完一个页面后的间隔时间interval(ms)等
根据文档,可以进行自己demo 测试了。
也可以先看文档
reamde.MD其实够好了。
http://www.geccocrawler.com/author/gecco/
看着困了。还是写吧。
代码在 源码里面添加的和测试的
Snipaste_2021-05-08_17-25-59.png
主要是爬明星的基本信息。。是循环进行的。
主方法
package com.geccocrawler.gecco.demo.mingxing;
import com.geccocrawler.gecco.GeccoEngine;
import com.geccocrawler.gecco.annotation.*;
import com.geccocrawler.gecco.request.HttpGetRequest;
import com.geccocrawler.gecco.request.HttpRequest;
import com.geccocrawler.gecco.spider.HtmlBean;
import java.util.List;
//@Gecco(matchUrl = "http://ku.ent.sina.com.cn/star/search&page_no={page}", pipelines = {"consolePipeline", "starIndexPagePipeline"})
@Gecco(matchUrl = "http://ent.sina.com.cn/ku/star_search_index.d.html?page={page}", pipelines = {"consolePipeline", "starIndexPagePipeline"})
//matchUrl是爬取相匹配的url路径,然后将获取到的HtmlBean输出到相应的管道(pipelines)进行处理。这里的管道是可以自定义的。
public class StarIndexPage implements HtmlBean {
private static final long serialVersionUID = 1225018257932399804L;
@Request
private HttpRequest request;
//url中的page参数
@RequestParameter
private String page;
//首页中的明星板块的集合,li的集合
@HtmlField(cssPath = "#dataListInner > ul >li")
private List<StarDetail> lsStarDetail;
//@HtmlField(cssPath = "#dataListInner > ul >li")是用来抓取网页中的相应网页数据,csspath是jQuery的形式。
//cssPath获取小技巧:用Chrome浏览器打开需要抓取的网页,按F12进入发者模式。然后在浏览器右侧选中该元素,鼠标右键选择Copy–Copy selector,即可获得该元素的cssPath
//当前的页码,如果当前的是有很多页码的话,可以通过获取当前页码还有总页码,为继续抓取下一页做准备
//@Text是指抓取网页中的文本部分。@Html是指抓取Html代码。@Href是用来抓取元素的连接 @Ajax是指获取Ajax得到的内容。
@Text
@HtmlField(cssPath = "#dataListInner > div > ul > li.curr a")
private int currPageNum;
//相应的Getter和Setter方法...省略
@Text
@HtmlField(cssPath = "#dataListInner > div > ul > li")
private String pageNum;
public String getPageNum() {
return pageNum;
}
public void setPageNum(String pageNum) {
this.pageNum = pageNum;
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public HttpRequest getRequest() {
return request;
}
public void setRequest(HttpRequest request) {
this.request = request;
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
public List<StarDetail> getLsStarDetail() {
return lsStarDetail;
}
public void setLsStarDetail(List<StarDetail> lsStarDetail) {
this.lsStarDetail = lsStarDetail;
}
public int getCurrPageNum() {
return currPageNum;
}
public void setCurrPageNum(int currPageNum) {
this.currPageNum = currPageNum;
}
/*
* https://segmentfault.com/a/1190000010086659
* 案例。。可以用
* */
public static void main(String[] args) {
// String url = "http://ku.ent.sina.com.cn/star/search&page_no=1"; //想要爬取的网站的首页地址
String url = "http://ent.sina.com.cn/ku/star_search_index.d.html?page=1"; //想要爬取的网站的首页地址
HttpGetRequest start = new HttpGetRequest(url); //获取网站请求
start.setCharset("UTF-8");
GeccoEngine.create() //创建搜索引擎
.classpath("com.geccocrawler.gecco.demo.mingxing") //要搜索的包名,会自动搜索该包下,含@Gecco注解的文件。
.start(start)
.thread(5)//开启多少个线程抓取
.interval(2000) //隔多长时间抓取1次
.run();
}
}
@Gecco 来 找url 和 爬虫的参数
下面的放就是上面指定的方法
也是 数据存储的地方
package com.geccocrawler.gecco.demo.mingxing;
import com.geccocrawler.gecco.annotation.PipelineName;
import com.geccocrawler.gecco.pipeline.Pipeline;
import com.geccocrawler.gecco.request.HttpRequest;
import com.geccocrawler.gecco.scheduler.SchedulerContext;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
@PipelineName("starIndexPagePipeline")
//@pipelineName 标签指定了pipline的名字。并且pipeline这个类需要实现Pipleline<T>。
public class StarIndexPagePipeline implements Pipeline<StarIndexPage> {
@Override
public void process(StarIndexPage starIndexPage) {
List<StarDetail> lsStarDetail = starIndexPage.getLsStarDetail();
StringBuilder inputText = new StringBuilder();
for (StarDetail starDetail : lsStarDetail) {
String professionHtml = starDetail.getProfessionHtml();
String starNameHtml = starDetail.getStarNameHtml();
Document docName = Jsoup.parse(starNameHtml);
String starName = docName.getElementsByTag("a").attr("title").trim();
String starSex = starDetail.getStarSex().trim();
Document doc = Jsoup.parse(professionHtml);
String profession = "未知"; //有不含a标签的,不含a标签的都是未知的
if (professionHtml.indexOf("<a") != -1) {
profession = doc.getElementsByTag("a").text();
}
String nationality = starDetail.getNationality().trim();
String birthday = starDetail.getBirthday().trim();
String constellation = starDetail.getConstellation().trim();
String height = starDetail.getHeight().trim();
inputText.append(starName + "\t" +
starSex + "\t" +
profession + "\t" +
nationality + "\t" +
birthday + "\t" +
constellation + "\t" +
height + "\t" +
System.getProperty("line.separator"));
}
//写入文件
writeFile(inputText.toString());
//爬取下一页
HttpRequest currRequest = starIndexPage.getRequest();
// int currPageNum = starIndexPage.getCurrPageNum();
// String pageNum = starIndexPage.getPageNum();
Map<String, String> parameters = currRequest.getParameters();
String page = parameters.get("page");
int i = Integer.parseInt(page);
/*
System.out.println("----------已爬取第" + currPageNum + "页----------");
pageNum = pageNum.replace("第", "");
pageNum = pageNum.replace("页", "");
int i1 = Integer.parseInt(pageNum);
System.out.println("----------已爬取第" + pageNum + "页----------");
System.out.println("----------已爬取第" + i1 + "页----------");*/
System.out.println("----------已爬取第" + i + "页----------");
searchNext(i, currRequest);
}
//写入文档的方法
public void writeFile(String inputText) {
try {
File f1 = new File("D:\\明星数据.txt");
if (!f1.exists()) {
f1.createNewFile();
}
FileWriter fw1 = new FileWriter("D:\\明星数据.txt", true);
PrintWriter pw = new PrintWriter(fw1, true);
pw.println("姓名" + "\t" + "性别" + "\t" + "职业" + "\t" + "国籍" + "\t" + "生日" + "\t" + "星座" + "\t" + "身高");
pw.print(inputText);
pw.flush();
pw.close();
/*if (new File("D:\\明星数据.txt").exists()) {
FileWriter fw1 = new FileWriter("D:\\明星数据.txt", true);
PrintWriter pw = new PrintWriter(fw1);
pw.print(inputText);
pw.flush();
pw.close();
} else {
}*/
} catch (IOException e) {
e.printStackTrace();
}
}
public void searchNext(int currPageNum, HttpRequest currRequest) {
//总页数只有2178
if (currPageNum < 2179) {
// System.out.println("----------第" + currPageNum + "页----------");
int nextPageNum = currPageNum + 1;
// System.out.println("----------第" + nextPageNum + "页----------");
String currUrl = currRequest.getUrl();
String nextUrl = StringUtils.replaceOnce(currUrl, "page=" + currPageNum, "page=" + nextPageNum);
SchedulerContext.into(currRequest.subRequest(nextUrl));
} else {
System.out.println("---------------爬取完毕------------------");
}
}
}
主要是第几页没有能对。以及页面获取属性。@Text @HtmlField的理解使用
这就就搞定了。总页数是根据网站里面二判断的。
还有明星的实体
package com.geccocrawler.gecco.demo.mingxing;
import com.geccocrawler.gecco.annotation.Html;
import com.geccocrawler.gecco.annotation.HtmlField;
import com.geccocrawler.gecco.annotation.Text;
import com.geccocrawler.gecco.spider.HtmlBean;
public class StarDetail implements HtmlBean {
/*//明星的照片
@Image("src")
@HtmlField(cssPath = "a > img")
prie String PhotoString;*/
//明星的名字
@Html
@HtmlField(cssPath ="div > div > h4")
private String starNameHtml;
//明星的性别
@Text
@HtmlField(cssPath = "div > p:nth-child(2)")
private String starSex;
//明星的职业
@Html
@HtmlField(cssPath = "div > p:nth-child(3)")
private String professionHtml;
//明星的国籍
@Text
@HtmlField(cssPath = " div > p:nth-child(4)")
private String nationality;
//明星的出生日期
@Text
@HtmlField(cssPath = "div > p.special")
private String birthday;
//明星的星座
@Text
@HtmlField(cssPath = "div > p:nth-child(6)>a")
private String constellation;
//明星的身高
@Text
@HtmlField(cssPath = "div > p:nth-child(7)")
private String height;
public String getStarNameHtml() {
return starNameHtml;
}
public void setStarNameHtml(String starNameHtml) {
this.starNameHtml = starNameHtml;
}
public String getStarSex() {
return starSex;
}
public void setStarSex(String starSex) {
this.starSex = starSex;
}
public String getProfessionHtml() {
return professionHtml;
}
public void setProfessionHtml(String professionHtml) {
this.professionHtml = professionHtml;
}
public String getNationality() {
return nationality;
}
public void setNationality(String nationality) {
this.nationality = nationality;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public String getConstellation() {
return constellation;
}
public void setConstellation(String constellation) {
this.constellation = constellation;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
}
最后就保存在d盘明星数据.txt中,就循环进行的。
网友评论