webmagic初次学习 爬取知乎数据
爬虫知多少,小公司刚起步的公司做成的软件需要大量的数据来维持,这就需要专业的爬虫工程师来搞点数据了,个人是干大数据的,会java和scala,当然也了解过pychon,说是爬虫都是拿pychon来搞,当然这是对强大的java的一种蔑视,java可以说是程序界上的元老的,啥都可以搞。今天就来介绍一个简单又实用的爬虫架构,webmagic!!!,爬虫个人觉得只要研究透网站的规则,什么语言都是可以来搞这个网站的数据,今天以爬取知乎网页内容为例 来搞他
简单介绍
webmagic整体个人觉得可以分为两层,一层是process,一层是pipline,process层用来真正获取html并解析,解析完成后可以立即返回得到结果,也可以传到pipline,pipline是一个整理数据的通道,接收process的数据整理并返回。启动类用来创建process,将url地址传到process来进程爬虫。整体使用maven来做项目管理。
下面这个网址是用字符串拼接的知乎搜索文章的一个后台连接地址,我们可以通过网址抓包得到这个地址,发现是个json,整体就简单多了。
https://www.zhihu.com/api/v4/search_v3?t=general&q=%E9%BB%91%E5%A4%B4&correction=1&offset=0&limit=20&lc_idx=0&show_all_topics=0第一步 pom添加webmagic依赖
<!-- webmagic依赖 -->
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-core</artifactId>
<version>${webmagic.version}</version>
</dependency>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-extension</artifactId>
<version>${webmagic.version}</version>
</dependency>
第二步 编写process类
@Component("processorZh")
public class ZHProcess implements PageProcessor {
private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);
@Override
public void process(Page page) {
//先获取文本
page.putField("result", page.getHtml().xpath("//body/text()").toString());
//内容
String data = page.getHtml().xpath("//body/text()").get();
//拿出这个页面的下一个网址
JSONObject jsonObject = JSON.parseObject(data);
JSONObject obj = jsonObject.getJSONObject("paging");
if (obj.get("is_end").toString().equals("false")) {
//获取下一页
page.addTargetRequest(obj.get("next").toString());
}
}
@Override
public Site getSite() {
return site;
}
爬虫process类先继承PageProcessor实现两个方法,getsite()方法是爬虫的配置,设置休眠时长,每页间隔时长和编码,编码是自适应的。page可以获取html页面,然后page有很多方法,获取url,html等,html就可以解析,使用xpath,css和$等,还可以使用正则解析,得到get和all之后将数据传入pipline。
第三部 编写pipline类
/**
* 知乎pipleline 整理数据并入库
*/
public class ZhiHuPipleline implements Pipeline {
private PcContentMapper mapper;
private PcContentDTO pcd;
public ZhiHuPipleline(PcContentMapper mapper, PcContentDTO pcd) {
this.mapper = mapper;
this.pcd = pcd;
}
@Override
public void process(ResultItems resultItems, Task task) {
List<PcContent> pclist=new ArrayList<PcContent>();
String result = resultItems.get("result");
String title = "";
String answer = "";
String auther = "";
Long comment = 0L;
Long voteupCount = 0L;
String type = "";
Long createtime = 0L;
Long updatetime = 0L;
JSONObject jsonObject = JSON.parseObject(result);
JSONArray arrays = jsonObject.getJSONArray("data");
for (int i = 0; i < arrays.size(); i++) {
JSONObject obj = (JSONObject) arrays.get(i);
JSONObject objHigh = obj.getJSONObject("highlight");
title = objHigh.getString("title");
JSONObject objObject = obj.getJSONObject("object");
//获取作者
if (objObject.getJSONObject("author") != null) {
auther = MyStringUtil.filterEmoji(objObject.getJSONObject("author").getString("name"));
}
//评分
if (objObject.getString("voteup_count") != null) {
voteupCount = Long.parseLong(objObject.getString("voteup_count"));
}
//内容
//评论个数
if (objObject.getString("comment_count") != null) {
comment = Long.parseLong(objObject.getString("comment_count"));
}
if (objObject.getString("type") != null) {
//类型(article:文章 answer:问答式)
type = objObject.getString("type");
}
if (objObject.getLong("created_time") != null) {
createtime = objObject.getLong("created_time");
}
if (objObject.getLong("updated_time") != null) {
updatetime = objObject.getLong("updated_time");
}
PcContent pc = new PcContent();
pc.setDetailUrl(returnUrl(objObject));
pc.setCommentNum(comment);
pc.setKeyword(pcd.getKeyword());
pc.setTitle(MyStringUtil.filterEmoji(title));
pc.setArticleType(type);
pc.setServiceType(AllCommon.ZHIHU);
pc.setPageview(0L);
pc.setLikeCount(voteupCount);
pc.setMatter(answer);
pc.setInsertDatetime(new Date());
pc.setUpdateDatetime(MyStringUtil.timeToDate(updatetime * 1000));
pc.setCrawlType(AllCommon.TUWEN);
//收藏数没有
pc.setCollectNum(0);
pc.setAuthor(auther);
try {
if (pc.getLikeCount() >= pcd.getLikeCount() &&//判断前段传来的条件
pc.getCommentNum() >= pcd.getCommentCount()
&& MyStringUtil.isEffectiveDate(createtime, pcd.getStartTime(), pcd.getEndTime())
) {
//mapper.insert(Page2OOS.downloadpage(pc));
pc.setReleaseTime(MyStringUtil.timeToDate(createtime * 1000));
//mapper.insert(pc);
pclist.add(pc);
}
} catch (Exception e) {
new PaChongException(ResponseEnum.SYSTEM_ERROR);
}
}
try {//判断集合中数据是否异常
if(pclist.size()!=0) {
mapper.insertList(pclist);
}
}catch (Exception e){
System.err.println("数据异常");
}
}
/**
* 知乎的拼接网址 规则 获取
*
* @param jsobj
* @return
*/
public static String returnUrl(JSONObject jsobj) {
StringBuffer str = new StringBuffer("https://www.zhihu.com/question/");
StringBuffer str1 = new StringBuffer("https://zhuanlan.zhihu.com/p/");
JSONObject jsb = jsobj.getJSONObject("question");
if (jsb != null) {
String url = jsb.getString("url");
return str.append(url.substring(32, url.length())).toString();
} else {
return str1.append(jsobj.getString("id")).toString();
}
}
}
pipline主要整理数据,我们也可以在process类整理,完全可以不需要pipline类。
第三部 编写启动方法
/**
* 知乎爬虫运行方法
*/
public static void zhTextRun(PcContentDTO pcd, PcContentMapper mapper) {
String url = "https://www.zhihu.com/api/v4/search_v3?t=general&q=" + pcd.getKeyword() + "&correction=3&offset=20&limit=20&lc_idx=25&show_all_topics=0&search_hash_id=32f69fe3edb72c74ab16573708957c46&vertical_info=0%2C1%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C1";
Spider spi = new Spider(new ZHProcess());
Map<String,Object> map=new HashMap<>();
map.put("service_type",pcd.getServiceType());
map.put("keyword",pcd.getKeyword());
map.put("crawl_type",pcd.getCrawlType());
//先删除数据库中已存在的
mapper.rmContext(map);
spi.addPipeline(new ZhiHuPipleline(mapper, pcd)).addUrl(url).thread(10).run();
}
spider new出process,将连接传入,然后增加pipline,设置线程并启动,成功