上一篇写了一个简单的新浪新闻爬虫作为上手主要是用jsoup包来对url页面进行抓取到本地,并在本地进行数据的解析提取。这里就不重复叙述jsoup的用法了,百度一下基本一大片。看了网上大神们都有对知乎进行爬取,今天我也拿它来试试手。写这篇文章的目的主要是想将自己在爬取中遇到的一些坑,以及怎么解决的做一下记录。也算是一次加深理解的过程。

爬取的目标页面

2017-12-31_172919.png

目标是爬取问题推荐页面的所有问题。但是随后我就发现一个问题,第一次我是通过抓取这个https://www.zhihu.com/explore/recommendations链接来获取问题列表,但是当代码敲完测试的时候发现数据只有20条。。。这显然不是我所期望的,看了一遍代码 发现代码是没有毛病,那么问题出在哪里?排查了一片以及debug模式。最终发现是页面的问题。因为我忽略了一个重要的地方。页面是动态加载的,而且每次只加载20条。

页面加载.png

问题就出在这个地方,这里其实还包含了一个地址(https://www.zhihu.com/node/ExploreRecommendListV2)。通过抓包可以发现(google的F12真的好用,推荐多去看看)

ajax请求头.png

请求参数.png

返回json结果.png

知道问题出在哪里其实就已经完成了一半了。说一下接下来我的思路:

因为用请求的参数可以看出其实这就是一个类似于一个分页信息一样。那么我只要在java代码中每次模仿页面的请求给知乎发送ajax请求,然后解析返回的json结果是不是就可以获取其中的问题信息了。

上面其实就已经有两个需求需要解决。

在java代码中模仿ajax发送请求。采用的是Httpclient。

解析返回的json,Gson jar包可以完美解决。

封装了httpclient post请求

public class HttpClientUtil {

/**

*

* @Title: doPost

* @Description: 模仿提交post请求

* @param @param url

* @param @param map 请求的参数 采用map集合封装参数

* @param @param charset 编码格式

* @param @return 参数

* @return String 返回类型

* @author liangchu

* @date 2017-12-31 下午7:09:14

* @throws

*/

public static String doPost(String url,Map map,String charset){

HttpClient httpClient = null;

HttpPost httpPost = null;

String result = null;

try{

httpClient = new SSLClient();

httpPost = new HttpPost(url);

//设置参数

List list = new ArrayList();

Iterator iterator = map.entrySet().iterator();

while(iterator.hasNext()){

Entry elem = (Entry) iterator.next();

list.add(new BasicNameValuePair(elem.getKey(),(String) elem.getValue()));

}

if(list.size() > 0){

UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list,charset);

httpPost.setEntity(entity);

}

HttpResponse response = httpClient.execute(httpPost);

if(response != null){

HttpEntity resEntity = response.getEntity();

if(resEntity != null){

result = EntityUtils.toString(resEntity,charset);

}

}

}catch(Exception ex){

ex.printStackTrace();

}

return result;

}

}

根据url链接地址获取对应的信息列表

/**

*

* @Title: spiderZH2

* @Description: 这里是采用httpclient包发送请求 获取需要加载的列表

* @param @param url 参数url地址 offset 根据offset显示问题信息列表

* @return void 返回类型

* @author liangchu

* @date 2017-12-31 下午2:11:23

* @throws

*/

public static void spiderZH2(String url,int offset){

try {

//String curl ="https://www.zhihu.com/node/ExploreRecommendListV2";

Map createMap = new HashMap();

String charset = "utf-8";

// method 提交的参数

createMap.put("method", "next");

Map map = new HashMap();

// 分页显示的数据

map.put("limit", 20);

map.put("offset", offset);

createMap.put("method", "next");

Gson gson = new Gson();

String mapStr = gson.toJson(map);

// 请求的参数

createMap.put("params", mapStr);

// 根据httpclient模仿post请求

String httpOrgCreateTestRtn = HttpClientUtil.doPost(url,createMap,charset);

Map maps = gson.fromJson(httpOrgCreateTestRtn, Map.class);

String html = maps.get("msg").toString();

Document doc = Jsoup.parse(html);

Elements elements =

doc.select("div[class=zm-item]").select("h2").

select("a[class=question_link]");

File file = new File("F:/replite/zhifuwenda.txt");

// 遍历每个问题节点

for (Element question : elements) {

// 获取连接地址

String qUrl = question.attr("href");

// 这里需要判断urlhttp格式

if(!qUrl.contains("https://")){

qUrl = "https://www.zhihu.com"+qUrl;

}

Document document2=Jsoup.connect(qUrl)

.userAgent("Mozilla/5.0 "

+ "(iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) "

+ "AppleWebKit/533.17.9"

+ " (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5")

.get();

// 问题标题

Elements title = document2.select("#root").select("div").select("main").

select("div").select("div:nth-child(10)").select("div.QuestionHeader").

select("div.QuestionHeader-content").select("div.QuestionHeader-main").

select("h1");

// 回答问题的内容

Elements content = document2.select("#root").select("div").select("main").

select("div").select("div.Question-main").select("div.Question-mainColumn").

select("div.Card.AnswerCard").select("div").select("div").

select("div.RichContent.RichContent--unescapable").

select("div.RichContent-inner");

if (!file.getParentFile().exists()) {//判断路径是否存在,如果不存在,则创建上一级目录文件夹

file.getParentFile().mkdirs();

}

FileWriter fileWriter=new FileWriter(file, true);

fileWriter.write("=============链接:"+qUrl+"\r\n");

fileWriter.write("=============标题:"+title.get(0).text()+"\r\n");

fileWriter.write("=============回答:"+content.get(0).text()+"\r\n");

fileWriter.close();

}

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

调用

public static void main(String [] args){

// 这里采用循环的方式去除列表

String url = "https://www.zhihu.com/node/ExploreRecommendListV2";

for(int i=1;i<1000;i++){

spiderZH2(url,59+i*20);

}

}

数据采集截图

2017-12-31_191857.png

改进的地方还有很多,比如说可以采用多线程采集,应该效率会比较高,在实际的应用应该是采集的数据可以存入redis中,然后在由redis insert进数据库。要改进的地方还有很多,时间的问题也就没有去考虑的。这也算是上一个版本一个小小的提升吧。O(∩_∩)O

java爬虫知乎_java爬虫进阶篇(半小时知乎两万推荐问题)相关推荐

  1. java resume过时方法_面试官没想到,一个 Java 线程生命周期,我可以扯半小时

    面试官:你不是精通 Java 并发吗?从基础的 Java 线程生命周期开始讲讲吧. 好的,面试官.吧啦啦啦... 如果要说 Java 线程的生命周期的话,那我觉得就要先说说操作系统的线程生命周期 因为 ...

  2. python爬虫与java爬虫的区别_java爬虫(一)主流爬虫框架的基本介绍

    (1).Scrapy: Scrapy,Python开发的一个快速.高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据.Scrapy用途广泛,可以用于数据挖掘.监测和自动化测 ...

  3. java计算最小公差数_进阶篇:5.1.1)确认公差分析的目标尺寸和判断标准

    本章目的:找到一个产品所有的公差分析目标,并定下判断基准. 1.前言 有需求才有公差分析,我的需求就是:整个产品的公差分析一个都不能少--作者. 这一章就是给出一个产品所有公差分析的目标值的方法. 2 ...

  4. java调用百度搜索_Java爬虫怎么调用百度搜索引擎,对关键字的网页爬取?

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 package com.wjd.baidukey.crawler; import java.io.ByteArrayInputStream; import ...

  5. java爬虫框架动态_java爬虫框架webmagic

    最近需要爬去网站的一些商品,就开始在网上找方法,本来是想着用Python做的,因为以前用Python写过一个小脚本,爬取一个文献网站上的免费文献. 步骤大概是这样的:1,先获取给定URL的html文件 ...

  6. java数据爬取_java爬虫,爬取当当网数据

    背景:女票快毕业了(没错!我是有女票的!!!),写论文,主题是儿童性教育,查看儿童性教育绘本数据死活找不到,没办法,就去当当网查询下数据,但是数据怎么弄下来呢,首先想到用Python,但是不会!!百度 ...

  7. java无极树形结构_Java爬虫框架:SeimiCrawler——结构化解析与数据存储

    本文将介绍如何使用SeimiCrawler将页面中信息提取为结构化数据并存储到数据库中,这也是大家非常常见的使用场景.数据抓取将以抓取博客园的博客为例. 建立基本数据结构 为了演示,简单起见只建立一个 ...

  8. java爬虫编写步骤_JAVA爬虫--编写第一个网络爬虫程序

    JAVA爬虫–编写第一个网络爬虫程序 前言上一章节介绍了XPATH基础语法,本章节将手把手带大家编写第一个爬虫程序,同时也希望能通过这个爬虫程序,帮助大家熟悉上一章节学习的XPATH基础语法并运用到实 ...

  9. java 爬虫身份设定_Java爬虫中HttpClient请求头的设置

    在做爬虫的时候发现如果不设置请求头的话,每次httpclient发起的请求都是响应移动端板式的,无法抓取响应的内容,后面查了一下才知道,需要重新设置请求头,让服务端误以为是某个真实浏览器发起的请求: ...

最新文章

  1. Tensorflow实现神经网络及实现多层神经网络进行时装分类
  2. 修复handsontable自动完成不支持中文的bug
  3. MPLS 企业组网有哪些特性?——Vecloud
  4. Linux开机自启动配置
  5. idea设置放大缩小_手机里竟然自带quot;放大镜quot;,很远也感觉近在眼前,真的涨知识了...
  6. 用AzureFunction开发最简单的Teams Bot
  7. 39.数组中数值和下标相等的元素
  8. Bootstrap3 排版之水平对齐
  9. 60-400-045-使用-binlog-Maxwell读取MySQL binlog日志到Kafka
  10. Java基础学习总结(90)——Java单元测试技巧
  11. [转]学习object-c,补习一下指针
  12. MAC电脑Command键怎么调换为Control键
  13. kvm : virsh create *** 报错处理
  14. 推荐x61使用nhc软件控制风扇
  15. 算法产品化---人脸识别采集终端的摄像头品质要求
  16. 工程师笔记 | 嵌入式工程师常用软件
  17. 电阻触摸屏 linux 校准软件,android 电阻单点触摸屏校准
  18. 什么是宽带薪酬?宽带薪酬系统如何实施?
  19. [VB.NET]雪花飘的屏保
  20. H3C路由器多出口NQA+TRACK实现冗余

热门文章

  1. 研究第一台电子计算机的过程,世界上第一台计算机诞生的过程
  2. 1.Unity3D商业游戏源码研究-变身吧主公-ResourcesMgr
  3. VisionPro通过SN码连接相机
  4. CTF练习 TU-ctf-2016 pwn woO-50
  5. GEA无法运行Python 程序
  6. BeeCloud支付接入视频教程-黄君贤-专题视频课程
  7. 关系抽取(二)远程监督方法总结
  8. 人工智能基础——为什么逻辑学中“假推真”、“假推假”永远是真命题?
  9. 用python一键保存几千张表情包斗图,分分钟征服朋友圈所有好友
  10. 迅雷下载iso镜像失败(文件重命名失败)