Crawler实现英语单词的翻译

首先声明一点,这种方法仅限于低频次的交互来获取翻译信息,一旦一秒内大量的请求会被重定向,那就直接不能用了

如果希望可以批量查询英语单词翻译,可以查看我的下一篇博客。

接下来的任务就是要把这么一大堆的单词进行翻译,我们想要得到每个单词的音标,有什么词性以及对应的翻译。现在我们就来讲讲通过网络来实现单词的翻译。

Java的HttpURLConnection类可以帮助我们发送HTTP请求,并获取相应的HTTP响应。我们可以设置请求头、请求方法、请求参数等信息,来模拟浏览器行为。

<dependency><groupId>org.apache.httpcomponents.client5</groupId><artifactId>httpclient5</artifactId><version>5.1</version>
</dependency>
<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.15.3</version>
</dependency>

private static final String TRANSLATE_URL = "http://www.baidu.com/s?wd=";这个网页就是我们平时百度查词的地址

我就希望可以得到两种音标,还有对应的词性和翻译。具体用到的两个依赖,一个是对于网页的解析Jsoup,这个和python的BS4基本原理一致,还有一个就是用于网络请求的http依赖。

import org.jsoup.Jsoup;
import java.net.URLEncoder;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.net.HttpURLConnection;
import java.net.URL;

第一步我们首先要对查询的文字进行一个编码(这一步在项目里不需要有,因为前序操作已经确定这个是String类型了)

String encodedWord = URLEncoder.encode(word, StandardCharsets.UTF_8.toString());
// 编码查询词,防止特殊字符导致的URL解析错误

第二步是向url发起链接

// 构建完整的URL,包括查询参数
URL url = new URL(TRANSLATE_URL + encodedWord);
// 打开连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

这里我们将URL封装成了带有网络协议等信息的实例对象来方便我们调用Connection方法。

现在建立好连接之后,我们可以看一下连接里面的数据。

可以看到请求体里面没有任何的数据段,这样去进行多次读取页面的操作会让百度感觉很”陌生“,所以现在要去请求头里加一些数据,让这个访问看起来就是真实的。

// 创建一个可变的 Map 来存储请求头Map<String, String> headers = new HashMap<>();headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");headers.put("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");headers.put("Connection", "keep-alive");headers.put("Cookie", "BIDUPSID=2BCC6FC9896B4237256E7EC335CECF0A; PSTM=1726058803....");headers.put("Host", "www.baidu.com");headers.put("Upgrade-Insecure-Requests", "1");headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0");

这些内容都可以直接在自己的网页端查到。我们用一个map来进行存储,然后一次添加到

// 添加自定义请求头
for (Map.Entry<String, String> entry : headers.entrySet()) {connection.setRequestProperty(entry.getKey(), entry.getValue());
// 设置请求方法为GET
connection.setRequestMethod("GET");

到这一步我们的请求就算是发送完成了。接下来就是服务器的响应,200就是响应成功了

// 获取响应码
int responseCode = connection.getResponseCode();
StringBuilder response = new StringBuilder();
// 如果响应码为200,表示请求成功
if (responseCode == HttpURLConnection.HTTP_OK) {// 获取响应流BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));String line;// 读取响应内容while ((line = reader.readLine()) != null) {response.append(line);}reader.close();
}

在 Java 的网络编程中,当建立了一个网络连接(比如通过 Socket 连接或者 HttpURLConnection 等建立的连接,这里的 connection 就是代表这样一个已建立的连接对象),可以通过调用 getInputStream() 方法获取这个连接对应的输入流。这个输入流里包含了对方(服务器等)发送过来的数据,不过它是以字节流的形式存在的,原始状态下不太方便直接按文本内容进行读取操作。

  • InputStreamReader 是字节流和字符流之间的桥梁,它用于将字节流(也就是前面获取的 connection.getInputStream() 这个字节输入流)转换为字符流,因为很多时候我们期望处理的是文本字符形式的数据,而不是单纯的字节数组。同时,指定了编码格式为 StandardCharsets.UTF_8,这一点很关键,因为要确保正确地将字节解码成对应的字符。不同的字符编码格式下,相同的字节序列可能表示完全不同的字符,如果不指定正确的编码(服务器通常会按照某种编码格式来发送文本响应,UTF-8 是现在网络通信中很常用的一种编码格式),就可能出现乱码问题,导致后续无法正确解析和处理读取到的文本内容。

又有一个问题,为什么不直接使用 connection.getInputStream() 创建 BufferedReader

  1. 字节流与字符流的差异
    • connection.getInputStream()返回的是字节流(InputStream)。字节流是以字节为单位来处理数据的,它并不知道这些字节如何组合成字符。而在很多网络通信场景中,如读取网页内容、解析 JSON 或 XML 等文本格式的数据时,我们需要以字符为单位来处理数据。
    • 直接使用字节流来读取文本数据会比较麻烦。例如,一个汉字在 UTF - 8 编码下可能占用 3 个字节,如果只按字节读取,很难正确地将这些字节组合成完整的字符进行处理。
  2. 编码问题
    • 没有经过字符流转换直接使用字节流读取文本可能会导致编码问题。不同的字符编码方式(如 UTF - 8、GBK 等)对字符的字节表示是不同的。
    • 通过InputStreamReader可以指定编码方式(如StandardCharsets.UTF - 8),将字节流按照正确的编码转换为字符流。这样能确保从网络中读取的文本数据被正确地解码。例如,如果服务器以 UTF - 8 编码发送数据,而客户端没有正确地按照 UTF - 8 解码,就会出现乱码。
  3. 缓冲和高效读取
    • BufferedReader提供了缓冲功能。它内部有一个缓冲区,当读取数据时,会先从缓冲区获取数据,只有当缓冲区为空时才会从底层的输入流(这里是经过InputStreamReader转换后的字符输入流)读取数据并填充缓冲区。
    • 这种缓冲机制可以减少与底层数据源(如网络连接)的交互次数,提高读取效率。直接使用connection.getInputStream()没有这种缓冲机制,每次读取操作可能都会涉及到相对耗时的底层 I/O 操作。例如,在读取一个较大的文本文件或网络响应中的大量文本内容时,缓冲机制可以显著提高性能。
  4. 方便的文本读取方法
    • BufferedReader提供了方便的readLine()方法,可以逐行读取文本内容。在处理文本数据时,很多时候数据是以行分隔的,如网页的 HTML 代码、配置文件等。
    • 直接使用connection.getInputStream()作为字节流没有这种按行读取的便捷方法,需要自己编写复杂的代码来实现按行读取字节流并将其转换为字符的功能

总之,reader读到的信息就是获取的那个页面的源码。我们把他存到一个String对象里面。


接下来才是真正意义上的爬取操作。

Document doc = Jsoup.parse(response.toString());Elements posElements = doc.select("span.part-name_3R3ee");
Elements En_phoneticElements = doc.select("span.orginal-txt_3dDqw");
Elements US_phoneticElements = doc.select("sapn.orginal-txt_3dDqw");

能看到在html标签里面,英式的发音藏在一个span标签里面,相对应的翻译

我就不一一列举了,用doc.select方式找到对应的标签进行提取。我们可以定义一个DTO或者一个数据库按照类型把他们都存进来。

wordModel.setWord(word);
wordModel.setEnPronunciation(En_phoneticElements.first().text());
wordModel.setUsPronunciation(US_phoneticElements.first().text());

根据这种写法就得到了我们的音标。但是又有个问题,音标只有一个,但是单词的翻译可能会有很多个,所以单纯的提取词性和翻译就会有问题。

我们得到两个travel的词性,理论上我们需要通过一个for循环来获取。通过分析源码,我们可以看到代码一个词性和对应的翻译都放在一个大的div标签了。

但现在又有一个问题就是这个翻译并不是一个字符串,是一个列表,多个span标签组成的。所以我们想要把翻译搞到一起就得多写两句代码,把列表换成字符串。

Elements translationElements = parent.select("span.mean-text_4MwRe");
StringBuilder translations = new StringBuilder();for (Element element : translationElements) {// 去除分号,避免重复String text = element.text().replace(";", "").trim();if (!text.isEmpty()) {translations.append(text).append(";");}
}

把数据格式安排明白之后,我们就可以继续存储数据了。

for (Element posElement : posElements) {// 获取当前词性的翻译和音标Element parent = posElement.parent();if (parent != null) {Elements translationElements = parent.select("span.mean-text_4MwRe");StringBuilder translations = new StringBuilder();for (Element element : translationElements) {// 去除分号,避免重复String text = element.text().replace(";", "").trim();if (!text.isEmpty()) {translations.append(text).append(";");}}// 创建一个结果映射Map<String, String> result = new HashMap<>();result.put("translation", translations.toString());result.put("pos", posElement.text());results.add(result);}}

最终的results当然是多个map映射的列表了,不要嫌麻烦,我们继续转换数据,把得到的词性翻译列表转换成一个可以直观的字符串。

StringBuilder combinedResult = new StringBuilder();
for (Map<String, String> result : results) {String pos = result.get("pos");String translation = result.get("translation");combinedResult.append(pos).append(translation).append(" ");
}
wordModel.setDescription(combinedResult.toString());

这样的话,我们就把所有的一个简易的爬虫式的单词翻译讲清楚了。我们后续会继续讲如何把查询到的翻译存到本地数据库。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/497872.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT 学习第十四天 QWidget布局

QT 学习十四天 布局 布局管理Qt Widgets 布局布局管理器简介基本布局管理器栅格布局管理器窗体布局管理器综合使用布局管理器设置部件大小可扩展窗口 布局管理 今天讲 Qt Widgets 和 Qt Quick 中的布局。 前者主要用布局管理器 后者除了布局管理器还有基于锚的布局&#xff08…

jangow靶机

打开靶机&#xff0c;打开kali&#xff0c;有的人会发现扫不到靶机的ip 在网上搜索了半天&#xff0c;发现是靶机的网卡配置有问题 重启靶机&#xff0c;选第二个 进去后再选第二个&#xff0c;按e 找到ro这一行 把ro后面这一行的内容都替换成ro rw signin init/bin/bash ctr…

redis开发与运维-redis0401-补充-redis流水线与Jedis执行流水线

文章目录 【README】【1】redis流水线Pipeline【1.1】redis流水线概念【1.2】redis流水线性能测试【1.2.1】使用流水线与未使用流水线的性能对比【1.2.2】使用流水线与redis原生批量命令的性能对比【1.2.3】流水线缺点 【1.3】Jedis客户端执行流水线【1.3.1】Jedis客户端执行流…

KOI技术-事件驱动编程(Sping后端)

1 “你日渐平庸&#xff0c;甘于平庸&#xff0c;将继续平庸。”——《以自己喜欢的方式过一生》 2. “总是有人要赢的&#xff0c;那为什么不能是我呢?”——科比布莱恩特 3. “你那么憎恨那些人&#xff0c;和他们斗了那么久&#xff0c;最终却要变得和他们一样&#xff0c;…

小程序配置文件 —— 14 全局配置 - tabbar配置

全局配置 - tabBar配置 tabBar 字段&#xff1a;定义小程序顶部、底部 tab 栏&#xff0c;用以实现页面之间的快速切换&#xff1b;可以通过 tabBar 配置项指定 tab 栏的表现&#xff0c;以及 tab 切换时显示的对应页面&#xff1b; 在上面图中&#xff0c;标注了一些 tabBar …

小程序基础 —— 08 文件和目录结构

文件和目录结构 一个完整的小程序项目由两部分组成&#xff1a;主体文件、页面文件&#xff1a; 主体文件&#xff1a;全局文件&#xff0c;能够作用于整个小程序&#xff0c;影响小程序的每个页面&#xff0c;主体文件必须放到项目的根目录下&#xff1b; 主体文件由三部分组…

使用ArcGIS/ArcGIS pro绘制六边形/三角形/菱形渔网图

在做一些尺度分析时&#xff0c;经常会涉及到对研究区构建不同尺度的渔网进行分析&#xff0c;渔网的形状通常为规则四边形。构建渔网的方法也很简单&#xff0c;使用ArcGIS/ArcGIS Pro工具箱中的【创建渔网/CreateFishnet】工具来构建。但如果想构建其他形状渔网进行相关分析&…

【K8S问题系列 | 21 】K8S中如果PV处于Bound状态,如何删除?【已解决】

在Kubernetes&#xff08;K8S&#xff09;的存储管理体系中&#xff0c;持久卷&#xff08;PersistentVolume&#xff0c;PV&#xff09;是一种重要的资源&#xff0c;它为Pod提供了持久化存储能力。当PV处于Bound状态时&#xff0c;意味着它已经与某个持久卷声明&#xff08;P…

旅游管理系统|Java|SSM|VUE| 前后端分离

【技术栈】 1⃣️&#xff1a;架构: B/S、MVC 2⃣️&#xff1a;系统环境&#xff1a;Windowsh/Mac 3⃣️&#xff1a;开发环境&#xff1a;IDEA、JDK1.8、Maven、Mysql5.7 4⃣️&#xff1a;技术栈&#xff1a;Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5⃣️数据库可…

Qt5 中 QGroupBox 标题下沉问题解决

我们设置了QGroupBox 样式之后,发现标题下沉了,那么如何解决呢? QGroupBox {font: 12pt "微软雅黑";color:white;border:1px solid white;border-radius:6px; } 解决后的效果 下面是解决方法: QGroupBox {font: 12pt "微软雅黑";color:white;bo…

六大基础深度神经网络之CNN

左侧是传统卷积网络输入的是一列像素点&#xff0c;右侧是卷积神经网络&#xff0c;输入的是具有长宽通道数的原始图像 下图为整体架构。卷积层可以认为提取特征&#xff0c;池化层是压缩特征。全连接层是把图像展平然后计算10个类别的概率值 给出一张图像不同区域的特征不同&a…

抽象工厂设计模式的理解和实践

在软件开发中&#xff0c;设计模式是前人通过大量实践总结出的、可复用的、解决特定问题的设计方案。它们为我们提供了一种标准化的解决方案&#xff0c;使得代码更加简洁、灵活和易于维护。在众多设计模式中&#xff0c;抽象工厂模式&#xff08;Abstract Factory Pattern&…

从入门到精通:Vim 高效文本编辑全面指南

文章目录 前言&#x1f9ec;一、Vim 的编辑哲学&#xff1a;模式分离与高效键盘操作&#x1f9ec;二、基础命令与快捷键&#xff1a;从简单到熟悉&#x1f9ec;三、进阶功能&#xff1a;多文件、分屏与可视化模式&#x1f9ec;四、自定义配置与 .vimrc&#xff1a;打造你的专属…

大模型-ChatGLM2-6B模型部署与微调记录

大模型-ChatGLM2-6B模型部署与微调记录 模型权重下载&#xff1a; 登录魔塔社区&#xff1a;https://modelscope.cn/models/ZhipuAI/chatglm2-6b 拷贝以下代码执行后&#xff0c;便可快速权重下载到本地 # 备注&#xff1a;最新模型版本要求modelscope > 1.9.0 # pip insta…

连锁餐饮行业数据可视化分析方案

引言 随着连锁餐饮行业的迅速发展&#xff0c;市场竞争日益激烈。企业需要更加精准地把握运营状况、消费者需求和市场趋势&#xff0c;以制定科学合理的决策&#xff0c;提升竞争力和盈利能力。可视化数据分析可以帮助连锁餐饮企业整合多源数据&#xff0c;通过直观、动态的可…

NiChart 多模态神经影像(structural MRI,functional MRI,and diffusion MRI)处理和分析工具包安装

NiChart多模态神经影像部署 NiChart 本地安装Git clone 问题personal access token PAT 问题 NiChart 云端注册AWS验证问题 NiChart 是UPenn大学&#xff0c;Christos Davatzikos教授开发的一个多模态MRI影像&#xff0c;structural (sMRI), diffusion (dMRI)&#xff0c; and …

人工智能与云计算的结合:如何释放数据的无限潜力?

引言&#xff1a;数据时代的契机 在当今数字化社会&#xff0c;数据已成为推动经济与技术发展的核心资源&#xff0c;被誉为“21世纪的石油”。从个人消费行为到企业运营决策&#xff0c;再到城市管理与国家治理&#xff0c;每个环节都在生成和积累海量数据。然而&#xff0c;数…

【代码分析】Unet-Pytorch

1&#xff1a;unet_parts.py 主要包含&#xff1a; 【1】double conv&#xff0c;双层卷积 【2】down&#xff0c;下采样 【3】up&#xff0c;上采样 【4】out conv&#xff0c;输出卷积 """ Parts of the U-Net model """import torch im…

构建全志 T113 Tina SDK

1、环境配置&#xff1a; 准备一个 Ubuntu 系统&#xff0c;可以是 WSL&#xff0c;虚拟机等&#xff0c;建议版本是 20.04。 1.1、安装必要的软件 进入系统后&#xff0c;输入下方命令安装需要的工具 &#xff1a; sudo apt update -y sudo apt full-upgrade -y sudo apt i…

深度学习:基于MindSpore NLP的数据并行训练

什么是数据并行&#xff1f; 数据并行&#xff08;Data Parallelism, DP&#xff09;的核心思想是将大规模的数据集分割成若干个较小的数据子集&#xff0c;并将这些子集分配到不同的 NPU 计算节点上&#xff0c;每个节点运行相同的模型副本&#xff0c;但处理不同的数据子集。…