2021年Java爬虫技术教程(一小时实现)

Java爬虫开发

操作要点

正则表达式
Java网络通信:URL
IO流
Map—HashMap
字符串操作
异常处理

项目已上传本人码云(gitee)传送门

如果这篇博客对你有一点点小帮助,希望您能给我来波一键三连;

前言

python优点:

1.各种爬虫框架,方便高效的下载网页;
2.多线程、进程模型成熟稳定,爬虫是一个典型的多任务处理场景,请求页面时会有较长的延迟,总体来说更多的是等待。多线程或进程会更优化程序效率,提升整个系统下载和分析能力。
3.gae 的支持,当初写爬虫的时候刚刚有 gae,而且只支持 python ,利用 gae 创建的爬虫几乎免费,最多的时候我有近千个应用实例在工作。

java 和 c++ :
相对脚本语言比较麻烦,所以放弃。总之,如果开发一个小规模的爬虫脚本语言是个各方面比较有优势的语言。如果要开发一个复杂的爬虫系统可能 java 是个增加选项, c++ 我感觉写个模块之类的更加适合。对于一个爬虫系统来说,下载和内文解析只是基本的两个功能。真正好的系统还包括完善的任务调度、监控、存储、页面数据保存和更新逻辑、排重等等。爬虫是一个耗费带宽的应用,好的设计会节约大量的带宽和服务器资源,并且好坏差距很大。

注意(爬虫爬取数据,必须是合法的数据,)

爬虫的类型

通用型的爬虫: 宽度遍历

		针对网页进行无差别抓取,例如Google搜索引擎和百度搜索引擎等等;(他们不生产网页内容,其内容都是类似的爬虫爬取来的)
		难点:页面下载和链接管理上,如果你要高效的抓取更多界面,就必须进行更快的下载;同时随着链接数量的增多,需要考虑如果对大规模的链接进行去重和调度,就成了一个很大的问题
 			通用型爬虫框架:
 			Nutch,     Heritrix

垂直型的爬虫

		关注内容与准确还有效率,仅仅抓取到有效有用的数据,并且在爬虫抓取之前,就能够对数据进行简单的处理:如:提取标题,内容,时间等;
		例如:股票财经,其涨跌幅度;

	难点:如何高效的定制一个爬虫,可以精确的抽取网页内容,并保存成结构化的数据。
		框架 :webmagic

本次代码实践所用技术

	模拟浏览器:HttpClient 
	html解析:jsoup

1.在Module建立一个maven工程

(因为我提前建立了一个大的maven工程项目,本次为了节省时间,就不重新创建一个maven工程,直接利用现有的)
建立一个简单的maven,不选用现成的骨架
点击module在这里插入图片描述
选择好你需要的jdk版本,点击next
在这里插入图片描述
设置好工程名称,和域名倒写。点击finish
在这里插入图片描述
点击file,点击Project structure,再点击module
在这里插入图片描述
将 java设为Source 将resources 设为Resource
在这里插入图片描述
引入你需要的maven依赖

org.jsoup jsoup 1.10.3 org.apache.httpcomponents httpcore 4.4.10 org.apache.httpcomponents httpclient 4.5.6 commons-io commons-io 2.6
</dependencies>

建立好包
在这里插入图片描述
本次爬取网站:昵图网传送门 以一个图片网站作为本次爬取对象
在这里插入图片描述
在网站中审查元素:确定图片的html代码结构
crtl+(a标签里面的http://www.nipic.com/topic/show_27400_1.html)
分析html代码,观察里面的结点结构特点。建立一个URL的值,把里面所有的html的保存起来。
然后来处理里面的每一个html,再来根据里面的每一个html,来取这个界面中间的图片。
需要分开处理,img图片和上面的a标签,来爬取上面的图片,将图片保存起来。
在这里插入图片描述
创建一个UrlPool类,用来存放html。
代码全在我的gitee:传送门
对你有用的话,可以点个收藏关注;给我的gitee点一个star;谢谢;

package com;


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created with IntelliJ IDEA.
 *
 * @Auther: 孙伟俊
 * @Date: 2021/03/14/22:37
 * @Description:
 */
//用来存放html
public class UrlPool {
    public static void main(String[] args) {
        getURL("http://www.nipic.com/");
    }

    private static void getURL(String baseUrl) {
//        创建一个map集合,传入要爬取的页面的url,并定义一个Boole型值,用于判断当前传入的url是否被遍历过;
        Map<String,Boolean> oldMap=new LinkedHashMap<String,Boolean>();
//        如果采集下来的路径是相对路径的话,要将相对路径进行
        String oldLinkHost="";
//        使用正则表达式,对路径进行占位符替换
        Pattern p=Pattern.compile("(http?://)?[^/\\s]*");
        Matcher m=p.matcher(baseUrl);
        if(m.find()){
            oldLinkHost=m.group();
//            取到正则之后的值
            //因为baseUrl,也是需要去爬取的,所以要将baseUrl的值,放入到这个集合中,因为未采集,所以定值为false
            oldMap.put(baseUrl,false);

            oldMap=crawlLinks(oldLinkHost,oldMap);//遍历这个url,告诉他传入的值经过正则处理过,如果取到一个相对路径则进行拼接
            //返回的也是一个oldMap;(是个引用类型)
            for (Map.Entry<String,Boolean> mapping:oldMap.entrySet()){
                System.out.println("链接"+ mapping.getKey());
            }
        }
    }
    /**
    * @Description: 实现递归    对传入的url进行处理
    * @Param: [oldLinkList, oldMap]
    * @return: void
    * @Author: 孙伟俊
    * @Date: 2021/3/14
    */


    private static Map<String,Boolean> crawlLinks(String oldLinkHost, Map<String, Boolean> oldMap) {
        Map<String,Boolean> newMap=new LinkedHashMap<String,Boolean>();//创建一个新的容器
//        如果url被遍历过,就不做遍历,
        String oldLink="";
        for (Map.Entry<String,Boolean> mapping: oldMap.entrySet()){
            System.out.println("链接"+ mapping.getKey()+"----check"+mapping.getValue());
            if(!mapping.getValue()){}
            oldLink=mapping.getKey();
            try{
                URL url=new URL(oldLink);
                HttpURLConnection connection=(HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");

                //如果拿到的响应值为responseCode=200
                if(connection.getResponseCode()==200){
                    //读取所有的a标签   使用BufferedReader 缓冲区来接收,这样读取速度快一点,
                    BufferedReader reader=new BufferedReader(
                            new InputStreamReader(connection.getInputStream()));
                    //定义 a标签的正则表达式

                    Pattern p = Pattern.compile("a.*?href=[\\\"']?((https?://)?/?[^\"']+)[\\\"']?.*?>(.+)</a>");
                    Matcher matcher=null;
                    String line="";
                    //开始流操作
                    while ((line=reader.readLine())!=null){
                        matcher=p.matcher(line);

                        if(matcher.find()){
                            String newLink=matcher.group(1).trim();
                            //判断newLink是否为合法的,如果newLink不以http开头,此时的newLink就是一个相对路径
                            if(!newLink.startsWith("http")){
                                if (newLink.startsWith("/")){
                                    newLink=oldLinkHost+newLink;
                                }else {
                                    newLink=oldLinkHost+"/"+newLink;
                                }
                            }
                            if(newLink.endsWith("/")){
                                newLink=newLink.substring(0,newLink.length()-1);
                            }
                            //判断url有没有重复
                            if(!oldMap.containsKey(newLink)
                                    &&!newMap.containsKey(newLink)
                                    &&!newLink.startsWith(oldLinkHost)){
                                newMap.put(newLink,false);
                            }
                        }
                    }
                }
            }catch (Exception e){

            }finally {

            }
            oldMap.replace(oldLink,false,true);
        }
        if(!newMap.isEmpty()){
            //将新的url集合和oldMap进行合并
            oldMap.putAll(newMap);
            oldMap.putAll(crawlLinks( oldLinkHost, oldMap));
        }
        return oldMap;
    }

}

运行上面的UrlPool类,得到下面的控制台输出:
为了拿到被爬取的内容图片,对内容解析并持久化,创建ImageCrawl类
这一部分:因为考虑到待会教程太长了,放到下一篇博客中说明;

对内容解析并持久化:放在下一篇博客教程中;

后续我会对本次爬虫中涉及的技术的内容,整理出相关博客:

正则表达式
Java网络通信:URL
IO流
Map—HashMap
字符串操作
异常处理

本人技术有限,如中间出现什么错误,欢迎大家在评论区指出,希望大家多多支持;

点赞+加一键三连

  • 25
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值