【Java】爬取澳门区划信息

news/2024/9/19 7:49:51/文章来源:https://www.cnblogs.com/mindzone/p/18402064

官网地址:

https://macaostreets.iam.gov.mo/zh_mo/freguesiaindex.html

  

大区部分是在页面展示的

 

点击发现并没有请求网络,所以数据是js中存在的

 

找到了展示街道方法,这一段:

使用大区id匹配上述变量的

 function showStreets(freguesia){var freguesiaStreets;switch(freguesia){case "fatima":freguesiaStreets = fatimaStreets;break;case "lourenco":freguesiaStreets = lourencoStreets;break;case "lazaro":freguesiaStreets = lazaroStreets;break;case "carno":freguesiaStreets = carnoStreets;break;case "se":freguesiaStreets = seStreets;break;case "antonio":freguesiaStreets = antionioStreets;break;case "xavier":freguesiaStreets = xavierStreets;break;}

  

可以发现,这一段是js代码实现的,我可以通过Jsoup解析文档获取js的源代码部分

但是要怎么在Java读取JS变量呢?

意外发现JDK8自带提供API 【JS解析引擎】

但是有使用限制,只支持ES5的语法 ,并且不支持任何第三方库的语法内容

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

网上的资料不多, 要边写边看才知道

 

@SneakyThrows
public static void main(String[] args) {ScriptEngineManager manager = new ScriptEngineManager();ScriptEngine engine = manager.getEngineByName("Nashorn");engine.eval("var obj = { a: 100, b: true, c: 'hello js-engine'}");ScriptObjectMirror jsObject = (ScriptObjectMirror) engine.get("obj");String[] ownKeys = jsObject.getOwnKeys(false); /* false表示只需要一般属性, true表示全部属性,包括对象原型的属性 */for (String ownKey : ownKeys) {Object o = jsObject.get(ownKey);System.out.println(o); /* 按具体类型强转即可。集合、对象类型,还是强转为ScriptObjectMirror来读取 */}
}

 

db.setting数据源配置文件:

## db.setting文件url = jdbc:mysql://localhost:3308/my-info?serverTimezone=Asia/Shanghai
user = root
pass = 123456## 可选配置
# 是否在日志中显示执行的SQL
showSql = true
# 是否格式化显示的SQL
formatSql = false
# 是否显示SQL参数
showParams = true
# 打印SQL的日志等级,默认debug,可以是info、warn、error
sqlLevel = debug#----------------------------------------------------------------------------------------------------------------
## 连接池配置项
#————————————————
#版权声明:本文为CSDN博主「soulCoke」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
#原文链接:https://blog.csdn.net/qq_36328170/article/details/105687633## ---------------------------------------------------- Druid
# 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
initialSize = 1
# 最大连接池数量
maxActive = 8
# 最小连接池数量
minIdle = 0
# 获取连接时最大等待时间,单位毫秒。配置了maxWait之后, 缺省启用公平锁,并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
maxWait = 0
# 是否缓存preparedStatement,也就是PSCache。 PSCache对支持游标的数据库性能提升巨大,比如说oracle。 在mysql5.5以下的版本中没有PSCache功能,建议关闭掉。作者在5.5版本中使用PSCache,通过监控界面发现PSCache有缓存命中率记录, 该应该是支持PSCache。
poolPreparedStatements = false
# 要启用PSCache,必须配置大于0,当大于0时, poolPreparedStatements自动触发修改为true。 在Druid中,不会存在Oracle下PSCache占用内存过多的问题, 可以把这个数值配置大一些,比如说100
maxOpenPreparedStatements = -1
# 用来检测连接是否有效的sql,要求是一个查询语句。 如果validationQuery为null,testOnBorrow、testOnReturn、 testWhileIdle都不会其作用。
validationQuery = SELECT 1
# 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
testOnBorrow = true
# 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
testOnReturn = false
# 建议配置为true,不影响性能,并且保证安全性。 申请连接的时候检测,如果空闲时间大于 timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
testWhileIdle = false
# 有两个含义: 1) Destroy线程会检测连接的间隔时间 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
timeBetweenEvictionRunsMillis = 60000
# 物理连接初始化的时候执行的sql
connectionInitSqls = SELECT 1
# 属性类型是字符串,通过别名的方式配置扩展插件, 常用的插件有: 监控统计用的filter:stat  日志用的filter:log4j 防御sql注入的filter:wall
# filters = stat
# 类型是List<com.alibaba.druid.filter.Filter>, 如果同时配置了filters和proxyFilters, 是组合关系,并非替换关系
# proxyFilters =

 

工具类代码:

package cn.cloud9.chinese.mazu;import cn.hutool.core.date.DateUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import lombok.Builder;
import lombok.Data;
import lombok.SneakyThrows;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;public class MaZuRegionUtil {private static final Db db = Db.use();private static String currentTableName = "";/* 首页 */private static final String INDEX_PAGE = "https://macaostreets.iam.gov.mo/zh_mo/freguesiaindex.html";/* 官网根地址 */private static final String ROOT_PATH = "https://macaostreets.iam.gov.mo";@Data@Builderpublic static final class MaZuRegionPO {private Integer id;private Integer parentId;private String name;private Integer level;private String link;private String fullPath;private String description;private byte[] image;private LocalDateTime genTime;}/* js 事件匹配数据对象 */private static Map<String, String> REGION_MAP = new LinkedHashMap<String, String>(){{this.put("fatima", "fatimaStreets");this.put("lourenco", "lourencoStreets");this.put("lazaro", "lazaroStreets");this.put("carno", "carnoStreets");this.put("se", "seStreets");this.put("antonio", "antionioStreets");this.put("xavier", "xavierStreets");}};@SneakyThrowsprivate static void writeToDB(MaZuRegionPO po) {db.insert(Entity.create(currentTableName).set("id", po.getId()).set("parent_id", po.getParentId()).set("full_path", po.getFullPath()).set("name", po.getName()).set("link", po.getLink()).set("level", po.getLevel()).set("description", po.getDescription()).set("image", po.getImage()).set("gen_time", LocalDateTime.now()));}@SneakyThrowspublic static void initialTableSpace() {String format = "`macao-region-" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + "`";final String SQL ="CREATE TABLE IF NOT EXISTS " + format + " (" +"  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键'," +"  `parent_id` int NOT NULL COMMENT '上级id'," +"  `name` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '名称'," +"  `link` varchar(192) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '链接'," +"  `full_path` varchar(128) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '完整路径'," +"  `level` varchar(12) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '层级'," +"  `description` varchar(2048) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '描述'," +"  `image` MEDIUMBLOB DEFAULT NULL COMMENT '图片'," +"  `gen_time` datetime DEFAULT NULL COMMENT '记录创建时间'," +"  PRIMARY KEY (`id`)" +") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='澳门区域表';";db.execute(SQL, null);currentTableName = format;}/*** 解析script标签中的js代码* @param targetScript* @return*/@SneakyThrowsprivate static ScriptEngine readJavaScriptData(String targetScript) {String targetJavaScriptCode = targetScript;// System.out.println(targetJavaScriptCode);/* 只保留前段变量代码 */int index = targetJavaScriptCode.indexOf("function");targetJavaScriptCode = targetJavaScriptCode.substring(0, index);ScriptEngineManager manager = new ScriptEngineManager();ScriptEngine engine = manager.getEngineByName("Nashorn");engine.eval(targetJavaScriptCode);return engine;}public static void goRead() {initialTableSpace();String string = HttpUtil.get(INDEX_PAGE);// System.out.println(string);Document document = Jsoup.parse(string);/* 先解析目标JS代码变量 */Elements scriptList = document.getElementsByTag("script");Element targetScript = scriptList.get(9);ScriptEngine scriptEngine = readJavaScriptData(targetScript.html());/*  提取页面区域部分 */Elements childList = document.select("#FreguesiaSectionText > [id]");int idx = 100;for (Element eachSector : childList) {String idKey = eachSector.id();MaZuRegionPO sector = MaZuRegionPO.builder().id(idx).name(eachSector.ownText()).fullPath(eachSector.ownText()).level(1).link(INDEX_PAGE).parentId(0).build();// System.out.println(sector);writeToDB(sector);String jsDataKey = REGION_MAP.get(idKey);ScriptObjectMirror streetsList = (ScriptObjectMirror) scriptEngine.get(jsDataKey);String[] ownKeys = streetsList.getOwnKeys(false);int c1 = 1;for (String key : ownKeys) {ScriptObjectMirror jsObject = (ScriptObjectMirror)streetsList.get(key);String name = jsObject.get("name").toString();String link = jsObject.get("link").toString(); // https://macaostreets.iam.gov.mo/ + linklink = ROOT_PATH + link;String detailPage = HttpUtil.get(link);Document detailDoc = Jsoup.parse(detailPage);/* 读取简介 */Element descElement = detailDoc.select(".SpotInfo > .SpotInfoText").get(0);String text = descElement.html();/* 读取目标图片 */Element linkA = detailDoc.select("a[data-caption='" + name + "']").get(0);String href = linkA.attr("href");href = ROOT_PATH + href;HttpResponse execute = HttpUtil.createGet(href).execute();byte[] bodyBytes = execute.bodyBytes();MaZuRegionPO street = MaZuRegionPO.builder().id(idx + c1).parentId(sector.getId()).name(name).fullPath(sector.getFullPath() + " -> " + name).level(2).description(text).image(bodyBytes).link(link).build();writeToDB(street);c1 += 1;}idx += 100;}}@SneakyThrowspublic static void main(String[] args) {goRead();}
}

  

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

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

相关文章

『模拟赛』CSP-S模拟2

『模拟赛记录』CSP-S模拟2Rank 非常好数据,使我成为 Rank1(雾数据换源后的狂流——齐秦北风在吹着清冷的街道 街灯在拉开长长的影子 走过的路 想过的事 仿佛越来越远越来越长 越来越多越难以抛开 多少平淡日子以来的夜晚 你曾是我渴望拥有的企盼 太多分手的记忆 仿佛越来越远…

(更新至 8/25) 不是暑假的暑假的不是游记的游记

持续更新中 Day1 - 8/23 因为在学校里待不下去了,所以订的十一点多的火车,打算八点钟就出门 结果教练在家长群里发我们十二点放假,所以我爸怕我赶不上就帮忙改签到一点半了 你说的对,但是为什么改成卧铺了??? 因此因为xfg的莫名其妙原因,还是决定十点钟出来 那么十点钟…

在 Alt + Tab 列表中隐藏指定窗口

安装并启动 AlexanderPro/SmartContextMenu,然后在指定窗口上Ctrl + rightClick,在出现的菜单中勾选在 Alt + Tab 列表中隐藏即可。这个程序还提供了置顶、调整透明度等功能,挺实用。

4-网络安全体系与网络安全模型

4.1 网络安全体系概述 1)概念 一般而言,网络安全体系是网络安全保障系统的最高层概念抽象,是由各种网络安全单元按照一定的规则组成的,共同实现网络安全的目标。 网络安全体系包括法律法规政策文件、安全策略、组织管理、技术措施、标准规范、安全建设与运营、人员队伍、教…

2024软件工程课程第一次个人作业

这个作业属于哪个课程 福州大学-软件工程2024这个作业要求在哪里 202409软件工程课程第一次个人作业这个作业的目标 初步使用博客园和GitHub,增强在博客园学习的意识和提升软件开发实践技能的意识,让老师和助教了解各个同学的水平学号 0723052261. 个人logo文生图任务个人风格…

【Hashcat工具】工具使用

数字破解 a、7位数字破解 hashcat64.exe -a 3 -m 0 --force 25c3e88f81b4853f2a8faacad4c871b6 ?d?d?d?d?d?d?db、7位小写字母破解 hashcat64.exe -a 3 -m 0 --force 7a47c6db227df60a6d67245d7d8063f3 ?l?l?l?l?l?l?lc、1-8位数字破解 hashcat64.exe -a 3 -m 0 …

洛谷 P4829 kry loves 2048——题解

洛谷P4829题解传送锚点摸鱼环节 kry loves 2048 题目背景 kls是一个人赢。 题目描述 kls最近在玩一款类似2048的游戏,规则是这样的: 一开始,有\(n\)个方块,每个方块上有一个\(1\)到\(m\)的整数。 kls可以进行两种操作:选择两个数字相同的方块(不一定要相邻),将它们合并…

代码整洁之道--读书笔记(4)

代码整洁之道简介: 本书是编程大师“Bob 大叔”40余年编程生涯的心得体会的总结,讲解要成为真正专业的程序员需要具备什么样的态度,需要遵循什么样的原则,需要采取什么样的行动。作者以自己以及身边的同事走过的弯路、犯过的错误为例,意在为后来者引路,助其职业生涯迈上更…

Javaweb-DQL-分页查询

1. select * from stu limit 0,3; 2. select * from stu limit 0,3; 3. select * from stu limit 3,3; 4. select * from stu limit 6,3;

有哪些让你「 爽到爆炸 」的 Windows 软件?

前言 本文源于知乎的一个提问,如标题所示:有哪些让你「 爽到爆炸 」的 Windows 软件?今天大姚给大家分享6款C#/.NET开源且免费的Windows软件,希望可以帮助大家提高学习、开发、办公效率。 Microsoft PowerToys项目简介: Microsoft PowerToys 是使用 C++ 和 C# 编程语言开发…

LeetCode刷题 堆

不会做简单题目的小菜菜!一:堆 1、一种二叉树的结构(完全二叉树) 2、完全二叉树:从上到下;从左到右;填满 3、最大堆:根节点的权值大于孩子节点 4、最小堆:根节点的权值依次小于孩子节点 5、常用操作 #创建堆(最大堆,最小堆) #添加元素 #获取堆顶元素 #删除堆顶元素…

单双链表

AcWing 826. 单链表 模板题: 实现一个单链表,链表初始为空,支持三种操作:向链表头插入一个数; 删除第 k 个插入的数后面的一个数; 在第 k 个插入的数后插入一个数。现在要对该链表进行 M 次操作,进行完所有操作后,从头到尾输出整个链表。 注意:题目中第 k 个插入的数并…