Java爬虫小试牛刀

爬虫?相信很多人对这个词都不陌生,简单来说,就是利用工具爬取网页上的数据并加以整理分析。照例向小白科普一下对爬虫的误区、原理以及实现。

爬虫常见的误区:python=爬虫?

很多小白会把python与爬虫划等号,实际上,python是一种计算机程序设计语言,它不仅仅可以做爬虫,也可以构建web应用,最近大火的人工智能,也是可以使用python语言来实现的。
而爬虫,其本质是抓取服务器向浏览器响应的数据(下文原理会详述),不同的计算机程序设计语言如Java,C#都可以实现爬虫。

小结:python≠爬虫,python的功能远比我们想象中的要强大,爬虫也并非只有python可以实现。

爬虫原理

让我们回忆一下我们访问百度时的过程:

1.在地址栏中输入一个URL:https://www.baidu.com/
有人肯定会说,我从来没这么干过,我都是用浏览器一打开的导航进百度的。
其实这么进入百度,只是浏览器替你输入了访问百度的链接。
2.浏览器刷新了一下,百度的搜索框出现在我们眼前。
当然了,网速卡顿刷新不出来的情况不考虑。

这期间,浏览器与服务器之间发生了什么?

1.浏览器向服务器发送URL,即请求地址。
2.服务器接到浏览器发来的网络请求,开始向浏览器响应数据。
3.浏览器接到服务器发来的数据,进行解析,并展示出来。
有兴趣的可以清除一下浏览器缓存,使用Fn+F12组合键打开浏览器控制台,选择NetWork菜单,页面刷新时可以看到具体的响应过程

爬虫的实现机制

1.既然浏览器可以向服务器发送请求地址,我们也可以用程序向服务器发起请求。
2.既然浏览器可以接到服务器发来的数据,我们就可以模仿浏览器解析的过程,通过筛选,拿到我们想要的数据。
小结:通过我们自己编写的程序,无需重复动手整理我们想要的数据,这一切交给我们的爬虫程序来搞定。

Java爬虫的具体案例

目标:爬取山西农业大学新闻网首页中院部动态模块展示的最新新闻,并将新闻内容以文件的形式保存到本地。


爬取资源1

爬取资源2
(一)需求分析

1.解析新闻网主页,抓取到院部动态模块的内容
2.模拟跳转,进入每一条新闻页面,抓取新闻具体内容
3.将新闻具体内容保存在文件中

(二)代码实现

1.使用maven工具,在pom.xml中导入我们爬虫所依赖的jar包

  <dependencies>
        <!-- httpclient:用于向浏览器发送请求 -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
        </dependency>
        <!-- jsoup:用于解析浏览器发来的数据 -->
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.8.3</version>
        </dependency>
        <!-- log4j:用于生成日志 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <!-- junit:用于单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>

2.制作一个简易的用于发送请求的类

package com.sxau.example;

import java.io.IOException;

import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRouteParams;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.util.EntityUtils;

public class MyClient {
    public String getContent(String url) throws ClientProtocolException, IOException {
        // 创建httpclient对象
        HttpClient hClient = new DefaultHttpClient();
        // 设置连接超时时间,响应超时时间,以及代理服务器
        hClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5000)
                .setParameter(CoreConnectionPNames.SO_TIMEOUT, 5000)
                .setParameter(ConnRouteParams.DEFAULT_PROXY, new HttpHost("117.191.11.71", 8080));
        // 创建get请求对象
        HttpGet hGet = new HttpGet(url);
        // 模拟请求,获得服务器响应的源码
        HttpResponse response = hClient.execute(hGet);
        // 将源码转换为字符串
        String content = EntityUtils.toString(response.getEntity(), "UTF-8");
        // 返回转化后的字符串
        return content;
    }
}

3.制作一个用于解析服务器数据的类

package com.sxau.example;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

public class MyJsoup {
    public Elements getTarget(
            String htmlResource,String selectCondition) {
        //解析服务器发来的数据
        Document doc = Jsoup.parse(htmlResource);
        //对解析后的数据通过条件筛选
        Elements elements = doc.select(selectCondition);
        return elements;
    }
}

4.制作一个将文件存储至本地的类

package com.sxau.example;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class MyFileIO {
    public void makeFile(String title,String txtContent) throws IOException {
        //将标题左右多余的空格去掉
        title = title.trim();
        //拿到当前应用所在路径
        String property = System.getProperty("user.dir");
        //设置生成文件的路径与名称
        String filePath = property + "\\src\\main\\webapp\\spidertxt\\" + title + ".txt";
        //生成新文件
        File txt = new File(filePath);
        //将文件输入器定位到刚刚生成的新文件
        FileWriter writer = new FileWriter(txt);
        //将已经匹配的字符串写入文件中
        writer.write(txtContent);
        //刷新并关闭流
        writer.flush();
        writer.close();
    }
}

5.为了提高效率,制作一个线程用于并发处理

package com.sxau.example;

import java.io.IOException;

import org.apache.http.client.ClientProtocolException;
import org.jsoup.select.Elements;
/**
 * 实现Runable接口
 * @author Administrator
 *
 */
public class MyThread implements Runnable{
    
    private String mainUrl;
    private String singleUrl;
    //提供有参数的构造方法,确保进入页面时url不为空
    public MyThread(String mainUrl, String singleUrl) {
        this.mainUrl = mainUrl;
        this.singleUrl = singleUrl;
    }
    /**
     * 实现接口未实现的run()方法
     * 通过httpclient发送请求并接收数据
     * 观察html页面,使用jsoup中便捷的仿css/js选择器语法得到我们需要的内容
     * 对匹配好的字符串进行优化,并进行本地存储
     */
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        MyClient myClient = new MyClient();
        String url=mainUrl+singleUrl;
        String content;
        try {
            content = myClient.getContent(url);
            String selectCondition1=".arti_title";
            String selectCondition2=".wp_articlecontent";
            MyJsoup jsoup = new MyJsoup();
            Elements elements1 = jsoup.getTarget(content, selectCondition1);
            Elements elements2 = jsoup.getTarget(content, selectCondition2);
            String html1 = elements1.get(0).html();
            String title = html1.replaceAll("<div class=\"arti_title\"></div>", "");
            String html2 = elements2.get(0).html();
            html2 = html2.replaceAll("<p>", "");
            String word = html2.replaceAll("</p>", "");
            MyFileIO fileIO=new MyFileIO();
            fileIO.makeFile(title, word);
        } catch (ClientProtocolException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        
    }
    
}

6.制作主体程序

package com.sxau.example;

import java.io.IOException;

import org.apache.http.client.ClientProtocolException;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class MySpider {
    public static void main(String[] args) throws ClientProtocolException, IOException {
        MyClient myClient = new MyClient();
        String url="http://news.sxau.edu.cn/";
        String content = myClient.getContent(url);
        String selectCondition="a[href][title~=(|)]";
        MyJsoup jsoup = new MyJsoup();
        Elements elements = jsoup.getTarget(content, selectCondition);
        for (Element element : elements) {
            String attr = element.attr("href");
            new Thread(new MyThread(url, attr)).start();
        }
        System.out.println("文件爬虫成功!");
    }
}

6.运行mian方法,稍等片刻,新鲜出炉的文件已经安静地在文件夹里躺着。

log4j:WARN No appenders could be found for logger (org.apache.http.impl.conn.BasicClientConnectionManager).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
文件爬虫成功!
最终效果

至此,一个简单的爬虫功能就实现了。新手上路,有什么问题还请各位看官不吝赐教,互相探讨共同进步。

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

推荐阅读更多精彩内容

  • HTTP基本原理 URI、URL、URN(Uninform Resource) URI(Identifier):统...
    GHope阅读 2,059评论 2 26
  • 爬虫文章 in 简书程序员专题: like:128-Python 爬取落网音乐 like:127-【图文详解】py...
    喜欢吃栗子阅读 21,736评论 4 412
  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 31,894评论 2 89
  • 这是欢快的一天,街道上到处洋溢着小孩子的欢乐,感染着来来往往的行人,今天是国际儿童节,全世界为祖国的花朵们庆祝他们...
    往后只求己阅读 121评论 0 0
  • 过去的2017年体会最深的就是在某些方面花钱学到了很多宝贵的知识。节省了很多时间,把注意力用在了更多能给自己带来成...
    安静的小木屋阅读 186评论 0 0