用 OkHttp 库来下载网页或者其他内容。

爬虫的基础

爬虫的基础工作就是利用 http 协议从网络上读取内容。内容一般是 html 网页,当然也可能会是图片、pdf 、视频 、json 字符串等。网络浏览器 chrome 、firefox 等也是通过 http 协议读取网络上的资源并且在界面上进行渲染,然后呈现给用户。所以做好爬虫的第一个步就是如何在程序里面利用 http 协议和网络上的资源进行交互。

Java Http 库的选择

Http协议的细节比较复杂,显然我们不应该完全重头开始从底层去实现一个。在 Java 里有很多类库已经帮你完成了这部分基础的工作。例如 JDK 自带的 HttpURLConnection 标准库、Apache HttpComponents HttpClient 库、 OkHttp 等。

  1. HttpURLConnection 是 JDK 原生的库,不需要引入其他的依赖。但是使用起来非常繁琐,也不支持一些高级的功能。
  2. Apache HttpComponents HttpClient 支持的特性非常多,可以满足用户的各种需求。有一个比较大的缺点是目前还不支持 Http2 协议。不过对于一般的爬虫来说。这个也不是什么大的问题。
  3. OkHttp 是一个更高层次封装的 Http Client 库,支持 Http2 最新协议。接口的设计上也更加友好,使用起来上手非常容易。

综合来说,OkHttp库是一个接口友好,功能丰富的 Http Client 库。首选他作为我们爬虫的 Http Client

相关类库的引入

如果我们的 Java 项目是 Maven 来进行管理的,那么在 pom.xml 文件中加入如下的依赖就可以引入 OkHttp 库

        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>3.11.0</version>
        </dependency>

目前最新版本是 3.11.0 。为了对 Http 响应的二进制流进行处理,我们还引入了 Apacke Commons IO 库。

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>

下载一个 HTML 页面

一个可以在浏览器上访问的 HTML 页面一般都是采用 Http Get 方法访问的。大概的步骤如下:

  1. 首先建立一个 OkHttpClient 对象;
  2. 然后构建一个 Request 对象;
  3. 之后通过 OkHttpClient 和 Request 对象创建一个新的 Call 对象
  4. 调用 Call execute 方法获得一个 Response 对象。
  5. 分析这个 Response 获得需要的结果

具体的代码如下所示

        OkHttpClient httpClient = new OkHttpClient.Builder().build();
        String url = "https://www.jianshu.com/p/675ea919230e";
        Request request = new Request.Builder()
            .url(url)
            .build();
        try {
            Response response = httpClient.newCall(request).execute();
            if (response.isSuccessful() && response.body() != null) {
                System.out.println(response.body().string());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

执行这段代码后,就会将简书的一篇文章《是什么支撑了淘宝双十一,没错就是它java编程语言。》 的 html 代码在控制台打印出 来。

<!DOCTYPE html>
<!--[if IE 6]><html class="ie lt-ie8"><![endif]-->
<!--[if IE 7]><html class="ie lt-ie8"><![endif]-->
<!--[if IE 8]><html class="ie ie8"><![endif]-->
<!--[if IE 9]><html class="ie ie9"><![endif]-->
<!--[if !IE]><!--> <html> <!--<![endif]-->

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">

  <!-- Start of Baidu Transcode -->
  <meta http-equiv="Cache-Control" content="no-siteapp" />
  <meta http-equiv="Cache-Control" content="no-transform" />
  <meta name="applicable-device" content="pc,mobile">
  <meta name="MobileOptimized" content="width"/>
  <meta name="HandheldFriendly" content="true"/>
  <meta name="mobile-agent" content="format=html5;url=https://www.jianshu.com/p/675ea919230e">
  <!-- End of Baidu Transcode -->

    <meta name="description"  content="先来看看淘宝双十一数据 总交易额:1207亿, 覆盖国家和地区:235个, 物流订单:6.75亿, 支付总笔数:10.5亿, 支付峰值:12W笔/秒, 保险总保单量:6亿笔, 保险总金额:224亿元, 历史成交额:第一年的5000W,去年912亿,今年单日千亿,流 0.9秒付款成功,6分51秒商品完成打包从仓库发出,13分19秒签收成功。淘宝再次刷新世界支付记录。世界上规模最大,复杂性最高电...">
...
</html>

通过 POST 方法获取 JSON 数据

现在动态网页,很多时候需要用用 AJAX 的方法动态的获取一些内容。这些内容可以是一些 html 代码片段,也可以是 JSON 数据。。
例如我们访问下面的网站,

网站目录页面

在这一页里面我们可以分析每个文章的条目得到这一页里面所有的目标文章的链接。但是,如果我们想看更多的的时候,点击图片中红圈部分的 “Next” 按钮,通过再浏览器的开发选项里面观察网络情况,我们发现这里是通过 ajax 做了一次 post 请求,提交的数据是一个 json 字符串,返回的数据也是一个 json 字符串,而新的一页的文章列表的 url 就在返回的 json 字符串的内容中。在 chrome 浏览器中,我们用 F12 快捷键打开浏览器的开发者选项,然后点击 “Next” 按钮,得到如下图所示的结果。

翻页 ajax 请求

这里是浏览器通过 post 方法想地址 https://api.swiftype.com/api/v1/public/engines/search.json 发起了一个 ajax 请求,请求的数据是一个 json 字符串

{
    "engine_key": "Eqsrs2GTE_JFL6QA-25N",
    "page": 2,
    "per_page": 10,
    "sort_direction": {},
    "filters": {
        "posts": {
            "tags": ["!Private", "!999", "!private"],
            "issue": {
                "type": "and",
                "values": ["Economy", "Economy"]
            }
        }
    },
    "facets": {
        "posts": ["issue", "project", "person", "tags"]
    }
}

其中 page 属性值代表页码,per_page 代表每页返回的数据条数。这个请求返回的额数据也是一个 json 字符串,如下图

ajax 请求结果

那么,如果我们要用 OkHttp 来模拟这个过程,则需要用下面的代码来实现

 String json="{\n" +
            "\t\"engine_key\": \"Eqsrs2GTE_JFL6QA-25N\",\n" +
            "\t\"page\": 1,\n" +
            "\t\"per_page\": 10,\n" +
            "\t\"sort_direction\": {\n" +
            "\t\t\"posts\": \"desc\"\n" +
            "\t},\n" +
            "\t\"filters\": {\n" +
            "\t\t\"posts\": {\n" +
            "\t\t\t\"tags\": [\"!Private\", \"!999\", \"!private\"],\n" +
            "\t\t\t\"issue\": {\n" +
            "\t\t\t\t\"type\": \"and\",\n" +
            "\t\t\t\t\"values\": [\"Economy\"]\n" +
            "\t\t\t}\n" +
            "\t\t}\n" +
            "\t},\n" +
            "\t\"facets\": {\n" +
            "\t\t\"posts\": [\"issue\", \"project\", \"person\", \"tags\"]\n" +
            "\t},\n" +
            "\t\"sort_field\": {\n" +
            "\t\t\"posts\": \"published_at\"\n" +
            "\t}\n" +
            "}";
        String url="https://api.swiftype.com/api/v1/public/engines/search.json";
        OkHttpClient httpClient=new OkHttpClient.Builder()
            .connectTimeout(30,TimeUnit.SECONDS)
            .readTimeout(30,TimeUnit.SECONDS)
            .build();

        RequestBody requestBody=FormBody.create(MediaType.parse("application/json; charset=utf-8"),json);
        Request request=new Request.Builder().url(url).post(requestBody).build();
        try {
            Response response = httpClient.newCall(request).execute();
            if(response.isSuccessful() && response.body()!=null){
                System.out.println(new String(IOUtils.toByteArray(response.body().byteStream())));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

执行这一段代码,会在控制台打印出 “ajax 请求结果” 中的 json 字符串。

这样,我们就实现了利用 OkHttp 库来用 get 的 http 的方式获取一个网页以及通过 post 方式提交一个 json 数据的 http 请求的过程。这两个步骤基本上就解决了爬虫系统中最基本的问题。至于得到的 html 内容和 json 内容怎么分析,后面再将

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • 《少的力量》这本书的内容如书名,所见即所得,只是将该理论演绎了一百遍,是一本典型的欧美畅销书。 这个道理说来简单,...
    snipersteve阅读 648评论 1 3
  • 又是一明月夜,月亮真的很圆、很亮。银光洒在大地上,令一切都很安静、和谐。偶尔有风吹过,把草丛和树叶都弄得“沙...
    飛葉無名阅读 488评论 0 1
  • 有意义学习也是最高效的学习,符合杰斯以人为本的教育观所提倡的非指导性学习特征。 几年前有个研究生导师致力于非指导性...
    静姐_学习成长营阅读 930评论 0 1