文档章节

从零实现一个高性能网络爬虫(一)网络请求分析及代码实现

卧颜沉默
 卧颜沉默
发布于 2017/05/23 09:32
字数 1690
阅读 13
收藏 0
点赞 0
评论 0

摘要

从零实现一个高性能网络爬虫系列教程第一篇,后续会有关于url去重、如何反爬虫、如何提高抓取效率、分布式爬虫系列文章。
以我写的一个知乎爬虫为Demo讲解,github地址 (https://github.com/wycm/zhihu-crawler) ,有兴趣的朋友可以star下。
网络请求的分析是写网络爬虫非常关键且重要的一个步骤。这篇文章以知乎网站为例,从网络请求分析到代码(java)实现。

目的

获取某个知乎用户的所有关注用户的个人资料

请求分析

  • 就目前的大部分网页来说,网页上能看到的数据大多都是直接在网站后台生成好数据(有的网页是在网站前端通过js代码处理后显示,如数据混淆、加密等)直接在前台显示。
  • 虽然很多网站采用了ajax异步加载,但是归根结底它还是一个http请求。只要能够分析出对应数据的请求来源,那么就很容易的拿到你想要的数据了。以下步骤讲解如何分析http请求。
  1. 以我的知乎账户为例,获取我的所有关注用户资料。首先打开我的关注列表,可以看到主面板就是我的关注用户列表,
    我一共关注233个用户,现在目的是就是要获取这233个用户的个人资料信息。打开F12->NetWork,勾选上Preserve log和Disable cache(如下图)。
  2. 下拉滚动条,点击下一页获取对应请求(在翻页的过程会有很多无关的请求),待页面加载完成后,在请求列表中右键->Save as HAR with content,这个文件是把当前请求(request)列表保存为
    json格式文本,保存后使用chrome打开这个文件,搜索(Ctrl+F)页面出现的关键字,要注意这里中文采用了unicode编码,我这里直接搜索5032(李博杰的关注者数,见下图)。这一步骤的目的是获取我们想要数据(关注用户的个人资料)的请求来源。
  3. 由步骤2搜索得出,关注用户的资料数据来自以下请求(如下图),url解码后为https://www.zhihu.com/api/v4/members/wo-yan-chen-mo/followees?include=data[*].answer_count,articles_count,gender,follower_count,is_followed,is_following,badge[?(type=best_answerer)].topics&offset=20&limit=20(url1),从这里可以看出关注列表的数据并不是从(url2)同步加载而来的,而是直接通过ajax异步请求url1来获得关注用户数据,然后通过js代码填充数据。这里要注意用红色矩形圈住的authorization request header,在代码实现的时候必须加上这个header。这个数据并不是动态改变的,通过步骤2的方式可以发现它是来自一个js文件。该步骤注意的是,我写该文章的时候是2017-04-27,随着时间推移,知乎可能会更新相关api接口的url,也就是说通过步骤2得出的url有可能并不是我上面的url1,但是具体分析的方法还是通用的。
  4. 多测试几次可以得出以上url1的参数含义如下
    参数名 类型 必填 说明
      include   String   是   data[*]answer_count,articles_count   需要返回的字段(这个值可以改根据需要增加一些字段)
      offset   int   是   0   偏移量(通过调整这个值可以获取到一个用户的所有关注用户资料)
      limit   int   是   20   返回用户数(最大20,超过20无效)
  5. 关于如何测试请求,我常用的以下三种方式
    • 原生chrome浏览器。可以做一些简单的GET请求测试,这种方式有很大的局限性,不能编辑http header。如果直接(未登录知乎)通过浏览器访问url1,会得到401的response code。因为它没有带上authorization request header。所以这种方式能测试一些简单且没有特殊request header的GET请求。
    • chrome插件Postman。一个很强大的http请求测试工具,可以直接编辑request header(包括cookies)。如果可以FQ的话,强烈推荐。GET、POST、PUT等都是支持的,几乎可以发送任意类型的http请求,测试的url1如下图。通过修改它参数的值,来看服务器响应数据的变化来确定参数含义

       

    • intellij idea ultimate版自带的工具。打开方式 Tools->Test RESTful Web Service。也是可以直接编辑http header(包括cookies)请求发送,GET、POST、PUT等请求方式也都是支持的。
  6. response是一段json格式的数据,中文是采用的unicode编码,解码后数据内容如下图

 

 

代码实现

  • 代码采用的Java HttpClient4.x,关于HttpClient4.x的使用我这里不过多讲解,要注意的是HttpClient4.x和3.x API有很大的差异。
    package com.cnblogs.wycm;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    
    import java.io.IOException;
    
    /**
     * 获取wo-yan-chen-mo关注的所有知乎用户信息
     * 只是把用户资料打印出来,没有具体解析(关于解析出详细数据可以采用正则表达式、json库、jsonpath等方式)
     */
    public class Demo {
        public static void main(String[] args) throws IOException {
            //创建http客户端
            CloseableHttpClient httpClient = HttpClients.createDefault();
    
            String url = "https://www.zhihu.com/api/v4/members/wo-yan-chen-mo/followees?include=data%5B*%5D.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset=0&limit=20";
    
            //创建http request(GET)
            HttpGet request = new HttpGet(url);
    
            //设置http request header
            request.setHeader("authorization", "oauth c3cef7c66a1843f8b3a9e6a1e3160e20");
            //执行http请求
            CloseableHttpResponse response = httpClient.execute(request);
            //打印response
            String responseStr = EntityUtils.toString(response.getEntity());
            System.out.println(responseStr);
    
            String nextPageUrl = getNextPageUrl(responseStr);
            boolean isEnd = getIsEnd(responseStr);
    
            while (!isEnd && nextPageUrl != null){
                //创建http request(GET)
                request = new HttpGet(nextPageUrl);
    
                //设置http request header
                request.setHeader("authorization", "oauth c3cef7c66a1843f8b3a9e6a1e3160e20");
                response = httpClient.execute(request);
                //打印response
                responseStr = EntityUtils.toString(response.getEntity());
                System.out.println(responseStr);
                nextPageUrl = getNextPageUrl(responseStr);
                isEnd = getIsEnd(responseStr);
            }
        }
    
        /**
         * 获取next url
         * @param responseStr
         * @return
         */
        private static String getNextPageUrl(String responseStr){
            JSONObject jsonObject = (JSONObject) JSON.parse(responseStr);
            jsonObject = (JSONObject) jsonObject.get("paging");
            return jsonObject.get("next").toString();
        }
    
        /**
         * 获取is_end
         * @param responseStr
         * @return
         */
        private static boolean getIsEnd(String responseStr){
            JSONObject jsonObject = (JSONObject) JSON.parse(responseStr);
            jsonObject = (JSONObject) jsonObject.get("paging");
            return (boolean) jsonObject.get("is_end");
        }
    }

     

  • maven依赖

    <dependency>
          <groupId>org.apache.httpcomponents</groupId>
          <artifactId>httpclient</artifactId>
          <version>4.5</version>
        </dependency>
    
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>1.2.31</version>
        </dependency>

     

© 著作权归作者所有

共有 人打赏支持
卧颜沉默
粉丝 2
博文 4
码字总数 6776
作品 0
成都
精通Python网络爬虫-书籍介绍

 内容简介 本书从技术、工具与实战3个维度讲解了Python网络爬虫: 技术维度:详细讲解了Python网络爬虫实现的核心技术,包括网络爬虫的工作原理、如何用urllib库编写网络爬虫、爬虫的异常...

weiwei_pig
2017/04/09
0
0
用Nodejs做一个简单的小爬虫

Nodejs将JavaScript语言带到了服务器端,作为js主力用户的前端们,因此获得了服务器端的开发能力,但除了用express搭建一个博客外,还有什么好玩的项目可以做呢?不如就做一个网络爬虫吧。据...

tower1229
2017/06/23
0
0
月薪20K的Python程序员2018年Python学习进阶书籍推荐

用了python,与太阳肩并肩,本文与大家分享一些Python编程语言的入门书籍,其中不乏经典。以下书籍已经经中心多位编辑老师进行详细阅读后才整理出来供大家学习!推荐下大数据技术学习群:8050...

加米谷
07/09
0
0
Netty高性能之道

背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用。相比于传统基于J...

HenrySun
2016/04/19
119
0
Java 与 Netty 实现高性能高并发

1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用。相比于传统基于...

ljianbing
2017/04/01
0
0
SuperSpider——打造功能强大的爬虫利器

1.爬虫的介绍 图1-1 爬虫(spider) 网络爬虫(web spider)是一个自动的通过网络抓取互联网上的网页的程序,在当今互联网中得到越来越广泛的使用。这种技术一般用来爬取网页中链接,资源等,当...

云栖希望。
2017/12/04
0
0
NodeJS网络爬虫

  原文地址:NodeJS网络爬虫   网上有很多其他语言平台版本的网络爬虫,比如Python,Java。那怎么能少得了我们无所不能的javascript呢😂?这个和之前给产品狗开发的批量图片下载配置工...

Jeff.Zhong
2017/12/05
0
0
Netty系列之Netty高性能之道

背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用。相比于传统基于J...

宇智波带土
2014/06/17
0
1
python来袭~爬虫0020:urllib2的使用

urllib2的使用 ——编辑:大牧莫邪 目录清单 入门程序了解爬虫采集数据步骤 底层操作Request对象 请求头设置之UserAgent用户代理 请求头设置 用户代理——UserAgent 自定义请求头消息 请求方式...

大牧莫邪
01/13
0
0
33款可用来抓数据的开源爬虫软件工具

要玩大数据,没有数据怎么玩?这里推荐一些33款开源爬虫软件给大家。 爬虫,即网络爬虫,是一种自动获取网页内容的程序。是搜索引擎的重要组成部分,因此搜索引擎优化很大程度上就是针对爬虫...

Airship
2015/11/09
0
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

about git flow

  昨天元芳做了git分支管理规范的分享,为了拓展大家关于git分支的认知,这里我特意再分享这两个关于git flow的链接,大家可以看一下。 Git 工作流程 Git分支管理策略   git flow本质上是...

qwfys
今天
1
0
Linux系统日志文件

/var/log/messages linux系统总日志 /etc/logrotate.conf 日志切割配置文件 参考https://my.oschina.net/u/2000675/blog/908189 dmesg命令 dmesg’命令显示linux内核的环形缓冲区信息,我们可...

chencheng-linux
今天
1
0
MacOS下给树莓派安装Raspbian系统

下载镜像 前往 树莓派官网 下载镜像。 点击 最新版Raspbian 下载最新版镜像。 下载后请,通过 访达 双击解压,或通过 unzip 命令解压。 检查下载的文件 ls -lh -rw-r--r-- 1 dingdayu s...

dingdayu
今天
0
0
spring boot使用通用mapper(tk.mapper) ,id自增和回显等问题

最近项目使用到tk.mapper设置id自增,数据库是mysql。在使用通用mapper主键生成过程中有一些问题,在总结一下。 1、UUID生成方式-字符串主键 在主键上增加注解 @Id @GeneratedValue...

北岩
今天
2
0
告警系统邮件引擎、运行告警系统

告警系统邮件引擎 cd mail vim mail.py #!/usr/bin/env python#-*- coding: UTF-8 -*-import os,sysreload(sys)sys.setdefaultencoding('utf8')import getoptimport smtplibfr......

Zhouliang6
今天
0
0
Java工具类—随机数

Java中常用的生成随机数有Math.random()方法及java.util.Random类.但他们生成的随机数都是伪随机的. Math.radom()方法 在jdk1.8的Math类中可以看到,Math.random()方法实际上就是调用Random类...

PrivateO2
今天
2
0
关于java内存模型、并发编程的好文

Java并发编程:volatile关键字解析    volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在...

DannyCoder
昨天
0
0
dubbo @Reference retries 重试次数 一个坑

在代码一中设置 成retries=0,也就是调用超时不用重试,结果DEBUG的时候总是重试,不是0吗,0就不用重试啊。为什么还是调用了多次呢? 结果在网上看到 这篇文章才明白 https://www.cnblogs....

奋斗的小牛
昨天
2
0
数据结构与算法3

要抓紧喽~~~~~~~放羊的孩纸回来喽 LowArray类和LowArrayApp类 程序将一个普通的Java数组封装在LowArray类中。类中的数组隐藏了起来,它是私有的,所以只有类自己的方法才能访问他。 LowArray...

沉迷于编程的小菜菜
昨天
0
0
spring boot应用测试框架介绍

一、spring boot应用测试存在的问题 官方提供的测试框架spring-boot-test-starter,虽然提供了很多功能(junit、spring test、assertj、hamcrest、mockito、jsonassert、jsonpath),但是在数...

yangjianzhou
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部