【Java】爬虫,能不能再详细讲讲?万字长文送给你!

【Java】爬虫,数据持久化到MongoDB 前言 先上几盘菜尝尝: MongoDB是什么?【博客园】惨绿少年《MongoDB 入门篇》 MongoDB怎么安装?【菜鸟教程】《Windows 平台安装 MongoDB》 MongoDB快速上手?【优快云】Xuych_《java连接mongoDB 并进行增删改查操作》 MongoDB全部用法?【菜鸟教程】《MongoDB 教程》 再送你一个MongoDB可视化操作工具: 【... 阅读详情

前言

本文仅用于学习知识探讨,绝无其它恶意。

前两篇基础文章链接:

《【Java】爬虫,看完还爬不下来打我电话 》

《【Java】爬虫,数据持久化到MongoDB》

本文打算再详细的讲讲一些流程细节,另外,最后有写到如何分析爬取下来的内容。

在开始正文之前,还要说清一件事:我是小白,能不能学会爬虫?

答:学不会,别学了,放弃吧。赶紧拿起手机,打游戏吧。这么热的天,哪凉快哪去,千万别遭这个罪。

正文

静态与动态网页

​ 我所理解的静态网页就是,浏览器中右键查看源代码,源码内容与用户看到的内容一致;动态网页就是,源码中找不到用户所看到的内容(部分)。

​ 这就有意思了,源码中都没有的内容,那是怎么呈现出来的?答案就是通过二次加载甚或多次加载得到。

​ 存在即合理,简单想想就能想通,倘若我点进去一个网页,加载半天一片空白,很大概率我是会不耐烦的。所以势必要一部分一部分的加载进去,有些东西还需要我点击“加载更多“之后才会加载。

爬静态网页的流程

  1. 第一步就是学习框架,Java首推Jsoup框架。
  2. 省省吧,静态网页没有第二步。
  3. 为了整体格式,这里要凑够三行。

爬动态网页的流程

  1. 第一步依然是学习框架,Java首推cdp4j框架。
  2. 学会“抓包”。
  3. 可以了,爬虫就这么点东西,都凑不够三步。
第一步 学习cdp4j框架

​ 因为是全英文网站,可能有些人会产生抵触的心理。但是,类名总能看懂吧:Code Samples地址

cdp4j样例代码这上面的代码我挨个运行过一遍,最后用到我这个项目里的只需要上面红框4个即可。

第二步 学会“抓包“

​ 有些人吃包子还需要用筷子夹,我向来都是用手抓 :)

​ “抓包”这个动词看起来很神秘,高深莫测。其实,就是看网页。东北话:瞅!瞪大眼睛瞅就可以成为抓包了,只不过需要瞅对地方。这个对的地方就是浏览器开发者工具,谷歌浏览器是右键->检查;火狐浏览器是右键->查看元素;搜狗、360浏览器是右键->审查元素;或者,统统按F12。推荐使用Chrome浏览器,因为好用,另外cdp4j框架使用前提就是安装Chrome浏览器。这里有个坑,请认准Chrome官网下载地址和官方图标:除此图标之外,任何图标都是假的Chrome。配色不一样、中间不是蓝点等等,都是假的Chrome。

​ Chrome浏览器安装好并不能使用,需要点右上角的三个点,然后选设置,或者直接在地址栏输入chrome://settings/

设置

​ 将搜索引擎设置为国内的搜索引擎,谷歌浏览器不能用谷歌搜索引擎,说起来也是令人欷歔(不知道国外的百度浏览器能否使用百度搜索引擎 : )

百度搜索引擎

进入开发者工具后,刷新一下页面,然后先点击Network再点击Type按响应类型排序,如下图:

抓包
​ 现在这个过程就叫“抓包”,至于能不能抓到,那看你有没有那个眼力劲了。

​ 当我们点击Type之后,Network响应的数据就会进行按类别进行排序。因为动态网页和静态网页的区别就在于数据不是一口气加载进来的,而是先加载浏览器地址栏URL,响应后再加载对应的脚本去后台获取JSON数据,解析JSON数据填充到页面中进行渲染。既然是脚本,当然需要关注script类型的响应了,如下图:

Script
​ 如果不能一眼看出来这些script类型响应了什么内容,可以逐个点击,之后会弹出一个展示框,选中Preview。最终,我发现了新闻列表是通过下图中红框的链接得到的:

新闻列表
​ 至此,网易新闻·国内新闻列表这个“包”,已经被我们“抓”到了。单次抓包结束!

​ 不过,爬虫程序逻辑还没完。

​ 如果往下浏览网页,当翻到距离底部不远的时候,网易新闻(国内)会再次加载新闻列表。这时候Network下对应就出现了新的响应内容。
加载更多
​ 直到出现 :-)已经到最后啦~, 就代表我们只能获取这么多。每次加载70篇新闻,总共可以加载3次。也就是说,我们只能获得网易新闻(国内)最近的3*70=210篇新闻,时间是近7天。对于“新闻”来说,210篇、近7天,差不多就够了,再多就不新了(我曾想挣扎一下拿到更久远的数据,能力有限,没整出来 :)
加载全部
​ 我们可以对每个响应逐个右键,Copy,Copy link address
copy
我已经给整出来了,瞪大眼睛瞅瞅有啥规律?

https://temp.163.com/special/00804KVA/cm_guonei.js?callback=data_callback   (第一次加载)
https://temp.163.com/special/00804KVA/cm_guonei_02.js?callback=data_callback(第二次加载)
https://temp.163.com/special/00804KVA/cm_guonei_03.js?callback=data_callback(第三次加载)

​ 规律就是都包含这个正则表达式

"cm_guonei[_0-9]*\\.js"

​ 但是,等等,我们是不是忽略了一个重要的事情,就是,怎么才能获取到响应的url?

​ 两种方式:一、手动“抓包”,然后写死在程序中。二、手动“抓包”,然后使用cdp4j进行获取Network响应URL。

​ 为了锻炼锻炼我的正则表达式 能力,我选择了后者。

​ 还记得我在一开始用红色框标记的4个官方样例吗?NetworkResponse.java

​ 主要代码如下:
NetworkResponse

​ 通过这个Demo我们就能拿到后台响应的url链接了,再用正则"cm_guonei[_0-9]*\.js"进行匹配就能筛选出我们想要的URL链接。

​ 一旦正则匹配成功,我们就可以自己手动构造3个url链接。下面代码纯属我写着玩,大家完全可以分析出来后手动写死,没必要费这么大劲。

// 获取Network响应的新闻列表url
public static List<String> getNetworkResponseNewsListUrl(String url){
   
   
    Launcher launcher = new Launcher();
    List<String> newsListUrlList = new ArrayList<>();
    try (SessionFactory factory = launcher.launch(asList("--disable-gpu", "--headless"))) {
   
   
        String context = factory.createBrowserContext();
        try (Session session = factory.create(context)) {
   
   
            // 连通网络
            session.getCommand().getNetwork().enable();
            // 事件监听器
            session.addEventListener(new EventListener() {
   
   
                @Override
                public void onEvent(Events event, Object value) {
   
   
                    if (NetworkResponseReceived.equals(event)) {
   
   
                        ResponseReceived rr = (ResponseReceived) value;
                        Response response = rr.getResponse();
                        // 从response对象中获得url
                        String newsListUrl = response.getUrl();
                        // 正则匹配,检测网站 https://regex101.com 匹配3条约用时2ms
                        Pattern pattern = Pattern.compile("cm_guonei[_0-9]*\\.js");
                        Matcher matcher = pattern.matcher(newsListUrl);
                        if (matcher.find()) {
   
   
                            newsListUrlList.add(newsListUrl);
                            newsListUrl = newsListUrl.replaceFirst("cm_guonei[_0-9]*\\.js","cm_guonei_02.js");
                            newsListUrlList.add(newsListUrl);
                            newsListUrl = newsListUrl.replaceFirst("cm_guonei[_0-9]*\\.js","cm_guonei_03.js");
                            newsListUrlList.add(newsListUrl);
                        }
                    }
                }
            });
            // 监听器写在导航之前
            // 一定要有连接超时设置,且不小于2s(多次测试得出结论,具体时间和网速有关系),否则无法获取
            session.navigate(url).wait(5 * 1000).waitDocumentReady(5 * 1000);
        }
        // 处理浏览器上下文,源码:contexts.remove(browserContextId)
        factory.disposeBrowserContext(context);
    }
    // 关闭后台进程,由于历史原因,关闭进程习惯使用kill
    launcher.getProcessManager().kill();
    return newsListUrlList;
}

​ 拿到获取新闻列表的响应链接后,我们就可以使用静态网页工具Jsoup进行获取网页了。这里或许会有疑问,为啥又是cdp4j,又是Jsoup来回混用呢?答案很简单,哪个工具擅长什么就使用哪个呗。

​ Jsoup显然是爬取静态网页中的哥哥!

获取Network响应的新闻列表JSON串
public static String getNewsListJsonStr(String url) throws IOException {
   
   
    // 使用parse,请求连接时指明编码GBK(试出来的),否则获取的内容会乱码
    // 参考:https://www.sojson.com/blog/225.html
    org.jsoup.nodes.Document doc = Jsoup.parse(new URL(url).openStream(), "GBK", url);
    String body = doc.text();

    // 零宽断言,从body上截取路径data_callback( )圆括号内数据
    Pattern pattern = Pattern.compile("(?<=data_callback\\()(.*)(?=\\))");
    Matcher matcher = pattern.matcher(body);
    while(matcher.find()){
   
   
        return matcher.group();
    }
    return "";
}

解析JSON

​ 通过上面代码就可以拿到Network返回的JSON数据了,之后,我们可以先去一个在线网站解析一下,复制一下JSON内容区这个网站:在线解析JSON

​ 可以发现,最外层是1个JSONArray,里面嵌套70个JSONObject

嵌套


JSON总体可以分为对象、集合(数组)两大类,二者可以任意嵌套。

常用的工具就是Google的Gson,两大功能:序列化、反序列化,官方给出教程如下

序列化,即对象转为Json字符串

反序列化,即Json字符串转为对象

Object序列化与反序列化

// 序列化
UserSimple userObject = new UserSimple(  
    "Norman", 
    "norman@futurestud.io", 
    26, 
    true
);

Gson gson = new Gson();  
String userJson = gson.toJson(userObject);  
/*
结果 ==>
"{
  "age": 26,
  "email": "norman@futurestud.io",
  "isDeveloper": true,
  "name": "Norman"
}"
*/

// 反序列化
String userJson = "{'age':26,'email':'norman@futurestud.io','isDeveloper':true,'name':'Norman'}";  

Gson gson = new Gson();  
UserSimple userObject = gson.fromJson(userJson, UserSimple.class);  
// 结果 ==> 就是上面那个userObject

Array序列化与反序列化

int[] ints = {
   
   1, 2, 3, 4, 5};
String[] strings = {
   
   "abc", "def", "ghi"};

Gson gson = new Gson();
// 序列化
gson.toJson(ints);     // ==> [1,2,3,4,5]
gson.toJson(strings);  
Java实现爬虫 关于美国历来每次飞机失事的数据,包含时间地点、驾驶员、死亡人数、总人数、事件描述,一共有12列,第一列是标题,下面一共有5268条数据。多线程中如果想设置等待状态,有一个方法可以实现wait(),如果想从等待状态唤醒,则可以使用notify()。通过Pattern和Matcher的配合,我们可以把一段内容中匹配我们要求的文字提取出来,方便我们来处理。对爬取的HTML页面来说,如果想提取连接地址,就必须找到所有超连接的标签和对应的属性。需要先自定义一个线程的操作类,在这个操作类中判断不同的状态,并且根。... 阅读详情

相关推荐

Java实现网络爬虫-Java入门|Java基础课程

目标 网络爬虫的是做什么的? 手动写一个简单的网络爬虫; 1. 网络爬虫 1.1. 名称 网络爬虫(又被称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚 本。 另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。 1.2. 简述 网络爬虫是通过网页的链接地址来寻找网页,从网站某一个页面(通常是首页)开始,读取网页的内容,找到 在网页中的其它...

万和IT教育 5031

Java网络爬虫全面教程

Java网络爬虫 这是本文目录 这里写目录标题Java网络爬虫1. HttpClient1.1 Get请求1.2 POST请求1.3 连接池1.4 参数设置2. Jsoup 本文将循序渐进介绍3大爬虫必备技术 HttpClietn(负责请求页面并获得页面) Jsout(负责解析页面,提取元素) WebMagic(Java的一个爬虫框架,利用WebMagic可以整合1、2中的繁琐操作) WebMagic框架我们留到下一期讲解。 1. HttpClient 使用网络爬虫其实就是要用Java程序去访问Ht

weixin_44293582的博客 3118

网络爬虫课程介绍及网络爬虫是什么

1.1.1知识概述 介绍网络爬虫的课时安排,以及简单介绍当前课程在大数据课程中的重要性。 1.1.2视频详情 1.1.3总结与补充 无 1.1.4课堂提问与练习 无 1.1.5习题答案 无 1.1网络爬虫是什么1.2.1知识概述 以上数据来源于百度百科 爬虫又叫网络爬虫,网络蜘蛛,一种运行在互联网上用来获取数据的...

qq_40208605的博客 1778

Java网络爬虫入门

Java网络爬虫是一个强大的工具,可以用于收集、分析各种数据,并用于数据挖掘、搜索引擎等场景。发送HTTP请求:使用Java发送HTTP请求,获取Web页面的内容。本文旨在介绍Java网络爬虫的入门知识,包括如何使用Java编写网络爬虫程序、如何发送HTTP请求、如何解析网页和如何保存爬取结果等。如:要爬取的是新闻网站,要收集的是新闻标题、发布时间、正文等。解析HTML页面:使用Java解析HTML页面,提取有用的信息。解析HTML页面:使用Java解析HTML页面,提取有用的信息。

吃不胖. 387

Java网络爬虫的设计与实现

网络爬虫(Web Crawler),也被称为网络蜘蛛(Web Spider)或网络机器人(Web Robot),是一种自动获取网页内容的程序或脚本。它按照一定的规则,自动地在互联网上浏览、检索并抓取信息。网络爬虫是搜索引擎、数据挖掘和知识管理等领域的关键技术之一。Java语言自1995年问世以来,因其“编写一次,到处运行”的理念而广受欢迎。它的特点包括面向对象、平台无关性、安全性、多线程和网络编程能力等。

weixin_33773084的博客 1254

Python头歌实验题目(2024版)

武汉理工大学头歌平台实验题目

2401_84152595的博客 2万+

从零开始用Plaxis 2D设计深基坑支护结构:含地锚与桩墙实战教程

本文提供了一份基于Plaxis 2D的深基坑支护结构设计实战教程。教程以钻孔灌注桩排桩结合预应力锚索的典型支护体系为例,详细阐述了从地质模型建立、材料参数定义(重点介绍硬化土模型)、施工阶段模拟(含开挖、锚索施加预应力和地下水渗流固结耦合分析)到结果解读与设计优化的全流程。旨在帮助岩土工程师掌握数值模拟核心,实现从经验设计到量化分析的跨越。

kotlin6android的博客 505

vue引入使用腾讯地图

// 引入鹅厂地图 initMap(lat = 0.0000000, lng = 0.0000000) { // 定义地图中心点坐标- var center = new TMap.LatLng(lat, lng) // 定义map变量,调用 TMap.Map() 构造函数创建地图 map = new TMap.Map(document.getElementById('txMapBox'), { center: center, // 设.

LiangRZ 4536

嵌入式开发实战:如何用cJSON库在STM32上实现轻量级JSON通信(附完整代码)

本文详细介绍了如何在STM32嵌入式系统中使用cJSON库实现高效的JSON通信方案。针对嵌入式环境的内存限制,提供了内存优化策略、cJSON库的深度定制方法以及完整的通信流程实现代码,帮助开发者解决JSON解析效率低下和跨平台兼容性等核心挑战。

star5的专栏 473

手把手教你用AppsFlyer SDK实现延迟深度链接(附Android/iOS代码示例)

本文详细介绍了如何使用AppsFlyer SDK实现延迟深度链接,提供Android和iOS双平台代码示例,帮助开发者解决跨平台精准跳转与用户归因问题。通过实战案例和高级场景分析,提升应用的用户转化率和广告投放效果。

sre5engineer的博客 701

Unreal Engine鸿蒙移植实战:环境配置、构建流程与性能优化指南

游戏引擎移植是跨平台开发中的关键技术环节,其核心原理在于通过适配目标操作系统的底层接口和工具链,实现同一套代码在不同硬件和软件环境下的高效运行。这项技术的价值在于最大化代码复用率,降低多平台维护成本,并能让应用快速触达新兴生态系统的用户。在移动游戏和XR应用领域,随着鸿蒙HarmonyOS生态的快速发展,将成熟的商业引擎如Unreal Engine迁移至此平台,成为开发者探索新市场机会的重要路径。本文聚焦于Unreal Engine项目向鸿蒙系统的移植实践,详细解析了从环境搭建、源码适配到构建打包的全链路流

weixin_29011395的博客 411

【GPFS专题5】---IBM Spectrum Scale (GPFS) 日常运维命令大全

掌握这些命令是有效管理 GPFS 集群的基础。实际生产环境中,建议结合自动化脚本和监控系统(如 IBM Storage Insights)实现高效运维。定期备份配置、监控性能指标,并进行灾备演练,是保障数据安全和系统稳定的关键。

jundao1997的专栏 841

Spark Catalog详解

旁边的实习生说:我想要用spark代码中对hive库中的内部表和外部表进行删除(包括数据),咋感觉网上搜了一圈都找不到解决方案啊,spark这么鸡肋吗?我:你应该静下心来好好把spark基础知识进行全面学习。实习生:难道spark有这功能,而我没有学习过?咋弄啊?我:学习一下Spark Catalog。实习生:啥是Catalog啊?Spark Catalog是Spark SQL中的一个元数据管理组件,它提供了一个集中化的存储和查询表、视图和函数的位置。

SunnyRivers 1814

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

上一篇: 【数据库】B+树与索引之间的恩怨情仇
下一篇: 搜集一些骨骼清奇的文章
midnight_time
博客等级 码龄10年 1714粉丝 97原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值