Java 爬虫遇到需要登录的网站,该怎么办?

2023-11-02

这是 Java 网络爬虫系列博文的第二篇,在上一篇 Java 网络爬虫,就是这么的简单 中,我们简单的学习了一下如何利用 Java 进行网络爬虫。在这一篇中我们将简单的聊一聊在网络爬虫时,遇到需要登录的网站,我们该怎么办?

在做爬虫时,遇到需要登陆的问题也比较常见,比如写脚本抢票之类的,但凡需要个人信息的都需要登陆,对于这类问题主要有两种解决方式:一种方式是手动设置 cookie ,就是先在网站上面登录,复制登陆后的 cookies ,在爬虫程序中手动设置 HTTP 请求中的 Cookie 属性,这种方式适用于采集频次不高、采集周期短,因为 cookie 会失效,如果长期采集的话就需要频繁设置 cookie,这不是一种可行的办法,第二种方式就是使用程序模拟登陆,通过模拟登陆获取到 cookies,这种方式适用于长期采集该网站,因为每次采集都会先登陆,这样就不需要担心 cookie 过期的问题。

为了能让大家更好的理解这两种方式的运用,我以获取豆瓣个人主页昵称为例,分别用这两种方式来获取需要登陆后才能看到的信息。获取信息如下图所示:


获取图片中的缺心眼那叫单纯,这个信息显然是需要登陆后才能看到的,这就符合我们的主题啦。接下来分别用上面两种办法来解决这个问题。

手动设置 cookie

手动设置 cookie 的方式,这种方式比较简单,我们只需要在豆瓣网上登陆,登陆成功后就可以获取到带有用户信息的cookie,豆瓣网登录链接:https://accounts.douban.com/passport/login。如下图所示:

图中的这个 cookie 就携带了用户信息,我们只需要在请求时携带这个 cookie 就可以查看到需要登陆后才能查看到的信息。我们用 Jsoup 来模拟一下手动设置 cookie 方式,具体代码如下:

/**
 * 手动设置 cookies
 * 先从网站上登录,然后查看 request headers 里面的 cookies
 * @param url
 * @throws IOException
 */
public void setCookies(String url) throws IOException {

    Document document = Jsoup.connect(url)
            // 手动设置cookies
            .header("Cookie", "your cookies")
            .get();
    //
    if (document != null) {
        // 获取豆瓣昵称节点
        Element element = document.select(".info h1").first();
        if (element == null) {
            System.out.println("没有找到 .info h1 标签");
            return;
        }
        // 取出豆瓣节点昵称
        String userName = element.ownText();
        System.out.println("豆瓣我的网名为:" + userName);
    } else {
        System.out.println("出错啦!!!!!");
    }
}

从代码中可以看出跟不需要登陆的网站没什么区别,只是多了一个.header("Cookie", "your cookies"),我们把浏览器中的 cookie 复制到这里即可,编写 main 方法

public static void main(String[] args) throws Exception {
    // 个人中心url
    String user_info_url = "https://www.douban.com/people/150968577/";
    new CrawleLogin().setCookies(user_info_url);

运行 main 得到结果如下:

可以看出我们成功获取到了缺心眼那叫单纯,这说明我们设置的 cookie 是有效的,成功的拿到了需要登陆的数据。这种方式是真的比较简单,唯一的不足就是需要频繁的更换 cookie,因为 cookie 会失效,这让你使用起来就不是很爽啦。

模拟登陆方式

模拟登陆的方式可以解决手动设置 cookie 方式的不足之处,但同时也引入了比较复杂的问题,现在的验证码形形色色、五花八门,很多都富有挑战性,比如在一堆图片中操作某类图片,这个还是非常有难度,不是随便就能够编写出来。所以对于使用哪种方式这个就需要开发者自己去衡量利弊啦。今天我们用到的豆瓣网,在登陆的时候就没有验证码,对于这种没有验证码的还是比较简单的,关于模拟登陆方式最重要的就是找到真正的登陆请求、登陆需要的参数。 这个我们就只能取巧了,我们先在登陆界面输入错误的账号密码,这样页面将不会跳转,所以我们就能够轻而易举的找到登陆请求。我来演示一下豆瓣网登陆查找登陆链接,我们在登陆界面输入错误的用户名和密码,点击登陆后,在 network 查看发起的请求链接,如下图所示:

从 network 中我们可以查看到豆瓣网的登陆链接为https://accounts.douban.com/j/mobile/login/basic,需要的参数有五个,具体参数查看图中的 Form Data,有了这些之后,我们就能够构造请求模拟登陆啦。登陆后进行后续操作,接下来我们就用 Jsoup 来模拟登陆到获取豆瓣主页昵称,具体代码如下:

/**
 * Jsoup 模拟登录豆瓣 访问个人中心
 * 在豆瓣登录时先输入一个错误的账号密码,查看到登录所需要的参数
 * 先构造登录请求参数,成功后获取到cookies
 * 设置request cookies,再次请求
 * @param loginUrl 登录url
 * @param userInfoUrl 个人中心url
 * @throws IOException
 */
public void jsoupLogin(String loginUrl,String userInfoUrl)  throws IOException {

    // 构造登陆参数
    Map<String,String> data = new HashMap<>();
    data.put("name","your_account");
    data.put("password","your_password");
    data.put("remember","false");
    data.put("ticket","");
    data.put("ck","");
    Connection.Response login = Jsoup.connect(loginUrl)
            .ignoreContentType(true) // 忽略类型验证
            .followRedirects(false) // 禁止重定向
            .postDataCharset("utf-8")
            .header("Upgrade-Insecure-Requests","1")
            .header("Accept","application/json")
            .header("Content-Type","application/x-www-form-urlencoded")
            .header("X-Requested-With","XMLHttpRequest")
            .header("User-Agent","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36")
            .data(data)
            .method(Connection.Method.POST)
            .execute();
    login.charset("UTF-8");
    // login 中已经获取到登录成功之后的cookies
    // 构造访问个人中心的请求
    Document document = Jsoup.connect(userInfoUrl)
            // 取出login对象里面的cookies
            .cookies(login.cookies())
            .get();
    if (document != null) {
        Element element = document.select(".info h1").first();
        if (element == null) {
            System.out.println("没有找到 .info h1 标签");
            return;
        }
        String userName = element.ownText();
        System.out.println("豆瓣我的网名为:" + userName);
    } else {
        System.out.println("出错啦!!!!!");
    }
}

这段代码分两段,前一段是模拟登陆,后一段是解析豆瓣主页,在这段代码中发起了两次请求,第一次请求是模拟登陆获取到 cookie,第二次请求时携带第一次模拟登陆后获取的cookie,这样也可以访问需要登陆的页面,修改 main 方法

public static void main(String[] args) throws Exception {
    // 个人中心url
    String user_info_url = "https://www.douban.com/people/150968577/";

    // 登陆接口
    String login_url = "https://accounts.douban.com/j/mobile/login/basic";

    // new CrawleLogin().setCookies(user_info_url);
    new CrawleLogin().jsoupLogin(login_url,user_info_url);
}

运行 main 方法,得到如下结果:

模拟登陆的方式也成功的获取到了网名缺心眼那叫单纯,虽然这已经是最简单的模拟登陆啦,从代码量上就可以看出它比设置 cookie 要复杂很多,对于其他有验证码的登陆,我就不在这里介绍了,第一是我在这方面也没什么经验,第二是这个实现起来比较复杂,会涉及到一些算法和一些辅助工具的使用,有兴趣的朋友可以参考崔庆才老师的博客研究研究。模拟登陆写起来虽然比较复杂,但是只要你编写好之后,你就能够一劳永逸,如果你需要长期采集需要登陆的信息,这个还是值得你的做的。

除了使用 jsoup 模拟登陆外,我们还可以使用 httpclient 模拟登陆,httpclient 模拟登陆没有 Jsoup 那么复杂,因为 httpclient 能够像浏览器一样保存 session 会话,这样登陆之后就保存下了 cookie ,在同一个 httpclient 内请求就会带上 cookie 啦。httpclient 模拟登陆代码如下:

/**
 * httpclient 的方式模拟登录豆瓣
 * httpclient 跟jsoup差不多,不同的地方在于 httpclient 有session的概念
 * 在同一个httpclient 内不需要设置cookies ,会默认缓存下来
 * @param loginUrl
 * @param userInfoUrl
 */
public void httpClientLogin(String loginUrl,String userInfoUrl) throws Exception{

    CloseableHttpClient httpclient = HttpClients.createDefault();
    HttpUriRequest login = RequestBuilder.post()
            .setUri(new URI(loginUrl))// 登陆url
            .setHeader("Upgrade-Insecure-Requests","1")
            .setHeader("Accept","application/json")
            .setHeader("Content-Type","application/x-www-form-urlencoded")
            .setHeader("X-Requested-With","XMLHttpRequest")
            .setHeader("User-Agent","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36")
            // 设置账号信息
            .addParameter("name","your_account")
            .addParameter("password","your_password")
            .addParameter("remember","false")
            .addParameter("ticket","")
            .addParameter("ck","")
            .build();
    // 模拟登陆
    CloseableHttpResponse response = httpclient.execute(login);
    if (response.getStatusLine().getStatusCode() == 200){
        // 构造访问个人中心请求
        HttpGet httpGet = new HttpGet(userInfoUrl);
        CloseableHttpResponse user_response = httpclient.execute(httpGet);
        HttpEntity entity = user_response.getEntity();
        //
        String body = EntityUtils.toString(entity, "utf-8");

        // 偷个懒,直接判断 缺心眼那叫单纯 是否存在字符串中
        System.out.println("缺心眼那叫单纯是否查找到?"+(body.contains("缺心眼那叫单纯")));
    }else {
        System.out.println("httpclient 模拟登录豆瓣失败了!!!!");
    }
}

运行这段代码,返回的结果也是 true。

有关 Java 爬虫遇到登陆问题就聊得差不多啦,来总结一下:对于爬虫遇到登陆问题有两种解决办法,一种是手动设置cookie,这种方式适用于短暂性采集或者一次性采集,成本较低。另一种方式是模拟登陆的方式,这种方式适用于长期采集的网站,因为模拟登陆的代价还是蛮高的,特别是一些变态的验证码,好处就是能够让你一劳永逸

以上就是 Java 爬虫时遇到登陆问题相关知识分享,希望对你有所帮助,下一篇是关于爬虫是遇到数据异步加载的问题。如果你对爬虫感兴趣,不妨关注一波,相互学习,相互进步

源代码:源代码

文章不足之处,望大家多多指点,共同学习,共同进步

最后

打个小广告,欢迎扫码关注微信公众号:「平头哥的技术博文」,一起进步吧。
平头哥的技术博文

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 爬虫遇到需要登录的网站,该怎么办? 的相关文章

  • npm install 编译时报“Cannot read properties of null (reading ‘pickAlgorithm‘)“

    先看报错 先说下网上大多数的解决方案 方案一 重新安装node解决 方案二 删了node models重新下 或者直接下载CNPM 淘宝镜像 进行安装 CNPM安装办法 npm install g cnpm registry https r
  • 解决STM32驱动0.96OLED不亮的问题

    问题描述 使用STM32无法驱动OLED 解决方案 1 检查硬件连接是否有误 OLED STM32 VCC 5V或3 3V SDA SDA SCL SCL GND GND 备注 最好接STM32最小系统版的3 3V 当连接STM32最小系统
  • Javaio流

    io流 关于Java的io流一般按照数据操作类型可以分为字节流与字符流 首先来说一下字节流 字节流 字节流的方法都是以stream结尾的 字节流的用途 转换图片为二进制 转换音频 视屏为二进制 字符串等也可以转为二进制 字节流常用于图片 音
  • 签到题【牛客算法周周练6E】【暴力枚举+线段树】

    题目链接 题目保证数据随机 数据随机真的是太强了 直接可以跑最坏时候是的复杂度 直接暴力建线段树 然后更新的时候更新到底 查询的时候也是查询到底 因为数据随机 所以其实被处理的次数是很少的 因为要刚好是set里有的 或者是set里没有的 这
  • Unity3D-----三维数学(向量)

    Unity3d gt 三维数学之向量 一 向量 1 什么是向量 2 向量的形式 3 向量的大小 4 向量的方向 二 向量运算 1 向量相减 2 向量相加 3 向量与标量的乘除法 4 点乘 5 叉乘 三 三角函数 1 角的度量单位 2 三角函
  • Labelme 目标检测和语义分割的数据标注

    1 安装labelme 打开conda prompt 输入以下代码创建虚拟环境 打开虚拟环境 安装lelme conda create n labelme python 3 6 创建虚拟环境 conda activate labelme 打
  • 解决idea出现报错:Error running,Command line is too long. Shorten command line

    报错的原因 因为项目需要打印的环境变量太长 超过了限制 需要缩短命令行来解决问题 解决办法 方法一 Edit Configurations 将默认的Shorten command line的值user local default 改为 JA
  • 格式工厂多个图片合并成一个PDF的报错

    使用图片合并PDF功能时 当图片数量超过50会报错 找到imgconv py文件 将50改为500 保存 现在可以支持100张图合并成一个PDF文件了 但是超过150张程序会直接闪退 正在解决中 补充说明 1 如何设置PDF压缩比 打开 g
  • 有奖调研

    简介 感谢您一直以来对阿里云通信短信服务的支持 为了提升用户体验 为您在数字化转型的通信之路提供助力 云通信短信服务将发起一次满意度调研 有关短信服务 无论使用情况 抑或功能需求 还是文档 产品介绍页 计算与账单 控制台 API SDK 售
  • TypeError Cannot read properties of undefined (reading ‘matched‘)vue项目创建之后写路由报错

    vue项目创建之后写路由报错 原代码 修改之后代码 在 import 路由文件后 命名为Router 就会出现报错 原因 router 才是Vue实例化的配置字段名称 不识别其他的
  • Linux下访问数据库

    Linux下访问数据库 声明 本文只简单描述Linux系统下访问mysql数据库的步骤 关于连接上数据库之后的简单的对于数据库的增删改查等操作只是稍微提及 关于增删改查的语句书写 本文不再讲述 一般来说 访问数据库有如下几个步骤 1 初始化
  • C#控制台程序中使用log4.net来输出日志

    Apache log4net 库是一个帮助程序员将日志语句输出到各种输出目标的工具 log4net 是优秀的 Apache log4j 框架到 Microsoft NE T 运行时的端口 我喜欢他可以自定义输出 区分等级等特点 导入库 我们
  • Android自定义控件(三)---实战篇(详解onMeasure)

    接着Android自定义控件 二 实战篇的讲解 这篇我们来详细讲一下测量 onMeasure 和绘制 onDraw 这两个方法 首先 我们来看测量 onMeasure 方法 在这个方法里 我们主要是设置控件的宽高 widthMeasureS
  • jqgrid 翻页记录选中行

    简单的jqgrid列表 list jqGrid url contextPath getList postData data datatype json colNames 用户名 密码 colModel name name index nam
  • 递归算法

    一 一半又一只 一个人赶着鸭子去每个村庄卖 每经过一个村子卖去所赶鸭子的一半又一只 这样他经过了七个村子后还剩两只鸭子 问他出发时共赶多少只鸭子 经过每个村子卖出多少只鸭子 1 题目分析 设经过第n个村子时有fun n 只鸭子 卖去fun
  • java 根据数据库表生成实体类工具

    public class CodeGenerator 修改生成配置 public static String dbUrl 数据库连接串 public static String dbName 账号 public static String

随机推荐

  • 【js】Object.entries的用法

    Object entries是返回一个键值对数组 const obj one 1 two 2 three 3 const result Object entries obj console log result one 1 two 2 th
  • 【Go】Go 的项目目录

    文章目录 一 Go 的项目目录 1 适合个人开发者 2 目前流行的项目结构 3 适合企业开发者 二 Go 项目构建及编译 第一个 Go 程序 参考链接 一 Go 的项目目录 进行Go语言开发的时候 我们的代码总是会保存在 GOPATH sr
  • 阿里云物联网——MQTT协议---CONNECT

    什么是MQTT 1 1简介 MQTT的中文含义 消息队列遥测传输 MQTT的英文 Message Queuing Telemetry Transport 它是基于TCP IP协议 为硬件性能低下的远程设备和网络情况糟糕的情况下设计发布的发布
  • 邻接表的存储

    include
  • 计算机网络——TCP三次握手详解为什么两次不行

    文章目录 1 TCP报文段结构 2 三次握手 3 SYN洪泛攻击 4 为什么是 三次 TCP是面向连接的 connection oriented 即收发双方在发送数据之前 必须首先建立一个连接 这样在连接断开之前 就一直使用这个连接传输数据
  • js-数组遍历方法forEach和map的原理解析和实际应用

    数组遍历方法forEach和map的原理解析和实际应用 目录 数组遍历方法forEach和map的原理解析和实际应用 一 前言 二 代码 1 相同点 2 forEach 3 map 三 结语 一 前言 forEach和map是数组的两个方法
  • 人们热议的Web3究竟是什么?

    Web3已经是一个热词 几乎每个行业 甚至很多的人都可以从中讲到机会 那么这个机会究竟是什么呢 又该作哪些准备呢 作为一个新兴领域 加密圈盛产各种新概念 哪怕是随便关注下 就知道它总能产生源源不断的行业术语 诸如NFT DApp DeFi和
  • 测试sqlite数据库可承载数据量

    环境 vmvare10 1 ubuntu14 04 sqlite3 一 创建数据库 在当前文件夹下 执行以下命令 如已有数据库则打开 若没有则创建 二 创建所需表 Creat table mysqlitetest id TEXT name
  • 同学,同事,KTV聚会的小游戏

    1 吸心大全 搞个扑克用嘴吸住 传给旁边的人 他在吸过去 依次传下去 谁掉了就喝酒 2 两个人一队 一定要男女搭配哦 一个人口里含一口水或者饮料都可以 然后说裁判指定的话 由另一人来猜 规定时间里猜对最多的就算赢 3 弄个超大的骰子 这个估
  • 最小二乘法,最大似然估计

    最小二乘法 最大似然估计 一 最小二乘法 1 基本思想 2 作用 3 如何求解最小二乘法 二 最大似然估计 1 概念 2 似然估计的思想是 3 如何求解最大似然估计 三 最小二乘法和最大似然估计的联系和区别 四总结 一 最小二乘法 最小二乘
  • gamma分布的推导与理解

    1 概述 gamma分布与指数分布 泊松分布甚至其它一些混合分布有较为紧密的联系 本文通过对比与之相关的概率分布 建立某种联系并推导其概率密度函数 以便加深理解与认知 2 Gamma分布的必要性 在设置 Gamma 分布的两个参数 并将它们
  • Spring Cloud 学习笔记十五:搭建微服务工程之Knife4j 介绍及使用

    目录 Knife4j 介绍及使用 Knife4j 介绍及使用 Knife4j的前身是swagger bootstrap ui 前身swagger bootstrap ui是一个纯swagger ui的ui皮肤项目 具体介绍见官方文档 htt
  • 商业数据分析概论

    我正在和鲸社区参加 商业数据分析训练营活动 https www heywhale com home competition 6487de6649463ee38dbaf58b 以下是我的学习笔记 学习主题 波士顿房价数据快速查看 日期 202
  • Java进阶--编译时注解处理器(APT)详解

    本文同步发布在掘金 未经本人允许不得转载 上篇文章 Java进阶 Java注解及其实例应用 我们使用注解 反射实现了一个仿ButterKnife功能的示例 考虑到反射是在运行时完成的 多少会影响程序性能 因此 ButterKnife本身并非
  • JDBC连接数据库常用的一些配置项

    最近在服务器中部署服务遇到了一个连接超时的报错CommunicationsException 查找解决方法后发现可以通过配置JDBC重连来解决 添加 autoReconnect true failOverReadOnly false 配置在
  • pg_dump 命令

    pg数据库安装目录 bin 下面 有 pg dump exe cmd切换到 安装目录 bin 下 使用pg dump 命令 pg dump help 查看命令详情 导出sql语句 如下 将 10 20 25 224 主机的 数据库fdb11
  • [深度学习]更好地理解正则化:可视化模型权重分布

    在机器学习中 经常需要对模型进行正则化 以降低模型对数据的过拟合程度 那么究竟如何理解正则化的影响 本文尝试从可视化的角度来解释其影响 首先 正则化通常分为三种 都是在loss函数的基础上外加一项 L0 即不等于0的元素个数 L1 即所有元
  • 剪映电脑版_剪映如何剪视频?详细图文教程+更多进阶高级玩法,新手必看!...

    短视频的火爆 平台上出现了各式各样酷炫的视频 因此 许多人也想做出高逼格的视频 但相信大部分的人都会遇到这么一个难题 那就是从未接触过剪辑 不知道视频要怎么优化处理 今天这篇文章 就带着小伙伴们了解一款非常适合新手的手机剪辑软件一一剪映AP
  • Qt5教程: (4) 带参数信号与槽

    在subwidget h中声明一个signal 和之前的信号函数重名但是有参数 void backSignal QString 之后在subwidget cpp的槽函数sendSignal 中也发送该信号 emit backSignal 子
  • Java 爬虫遇到需要登录的网站,该怎么办?

    这是 Java 网络爬虫系列博文的第二篇 在上一篇 Java 网络爬虫 就是这么的简单 中 我们简单的学习了一下如何利用 Java 进行网络爬虫 在这一篇中我们将简单的聊一聊在网络爬虫时 遇到需要登录的网站 我们该怎么办 在做爬虫时 遇到需