Hexo 使用 GitHub Actions 自动提交文章列表到各大搜索引擎
写在前面
偶然在逛 Bing 的 Webmasters 的时候,发现多了个 IndexNow 原先一直用的 Hexo-SEO-AutoPush 但是有新东西了,和乐特子提了一下,他让我 PR,可惜 JavaScript 不太熟,索性自己用 JAVA 写了个,也顺便学习了 XML 解析器和 XPath 表达式
项目地址:
开发思路
获取 RSS 地址
进行解析 RSS 并使用 XPath 表达式提取其中的 ID 标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29/**
* 从XML内容中提取id值。
* 首先解析XML内容,然后使用XPath表达式定位到id元素的文本内容,并将这些内容收集到一个列表中。
*
* @param xmlContent 要解析的XML内容,作为字符串提供。
* @param ids 用于收集提取到的id值的列表。
* @throws Exception 如果解析XML或执行XPath表达式时发生错误,则抛出异常。
*/
private static void extractIds(String xmlContent, List<String> ids) throws Exception {
// 创建一个文档工厂实例,用于构建XML文档解析器
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// 使用文档工厂创建一个文档构建器
DocumentBuilder db = dbf.newDocumentBuilder();
// 将XML内容解析为DOM文档
Document doc = db.parse(new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8)));
// 创建XPath工厂,用于生成XPath实例
XPathFactory xPathFactory = XPathFactory.newInstance();
// 创建XPath实例,用于评估XPath表达式
XPath xpath = xPathFactory.newXPath();
// 编译XPath表达式,用于定位id元素的文本内容
XPathExpression expr = xpath.compile("//feed/entry/id/text()");
// 执行XPath表达式并获取匹配的节点列表
NodeList nodeList = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
// 遍历节点列表,将id文本添加到收集列表中
for (int i = 0; i < nodeList.getLength(); i++) {
ids.add(nodeList.item(i).getNodeValue());
}
}最后将这些 ID 循环写入 urls.txt 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21/**
* 将一串ID写入到指定的文本文件中。
* 每个ID占一行。
*
* @param ids 包含需要写入文件的所有ID的列表。
* @throws IOException 在写入文件过程中发生IO异常。
*/
private static void writeIdsToFile(List<String> ids) throws IOException {
// 使用BufferedWriter来提高文件写入性能,通过FileWriter指定写入的文件路径
try (BufferedWriter writer = new BufferedWriter(new FileWriter(TXT_FILE_PATH))) {
// 遍历ids列表,将每个ID写入文件,如果ID不是最后一个,则在后面添加换行符
for (int i = 0; i < ids.size(); i++) {
// 写入当前ID
writer.write(ids.get(i));
if (i < ids.size() - 1) {
// 如果当前ID不是最后一个,则写入换行符
writer.newLine();
}
}
}
}使用并发批量提交 urls.txt 的文本内容到不同的搜索引擎
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73/**
* 向多个搜索引擎提交URLs。
*
* @param host 主机地址
* @param siteUrl 网站的URL
* @param indexNowkey IndexNow的密钥
* @param keyLocation 密钥存储位置
* @param bingApiKey Bing搜索引擎的API密钥
* @param baiduApiKey 百度搜索引擎的API密钥
* @param googleKey Google搜索引擎的json文件内容
* @param indexNowCount 向IndexNow提交的URL数量
* @param bingCount 向Bing提交的URL数量
* @param baiDuCount 向百度提交的URL数量
*/
private static void submitUrls(String host, String siteUrl, String indexNowkey, String keyLocation, String bingApiKey, String baiduApiKey, String googleKey, Integer indexNowCount, Integer bingCount, Integer baiDuCount) {
List<String> urlList;
try {
// 从文件中读取 urls 列表
urlList = ReptileRssTools.readUrlsFromFile();
if (urlList.isEmpty()) {
// 如果URL列表为空或读取失败, 取消提交
LOGGER.log(Level.SEVERE, "URL 列表为空或读取 rss 失败, 取消提交!");
return;
}
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "读取 URL 列表时发生异常" + e.getMessage());
return;
}
// 创建一个固定大小为 5 的线程池,用于并发提交URL到不同的搜索引擎
ExecutorService executorService = Executors.newFixedThreadPool(5);
// 向IndexNow提交URL任务
executorService.submit(() -> {
try {
AutoSubmitUrlServiceImpl.pushIndexNowUrl(urlList, host, indexNowkey, keyLocation, indexNowCount);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "提交 URL 到 IndexNow 时发生异常", e.getMessage());
}
});
// 向Bing提交URL任务
executorService.submit(() -> {
try {
AutoSubmitUrlServiceImpl.pushBingUrl(urlList, siteUrl, bingApiKey, bingCount);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "提交 URL 到 Bing 时发生异常", e.getMessage());
}
});
// 向百度提交URL任务
executorService.submit(() -> {
try {
AutoSubmitUrlServiceImpl.pushBaiduUrl(urlList, siteUrl, baiduApiKey, baiDuCount);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "提交 URL 到 Baidu 时发生异常", e.getMessage());
}
});
// 向Google提交URL任务
executorService.submit(() -> {
try {
AutoSubmitUrlServiceImpl.pushGoogleUrl(urlList, googleKey);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "提交 URL 到 Google 时发生异常", e.getMessage());
}
});
// 关闭线程池,并等待所有任务完成
executorService.shutdown();
try {
// 长时间等待所有任务完成,以确保所有提交任务执行完毕
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
// 如果在等待线程池关闭时线程被中断时,尝试恢复中断状态
LOGGER.log(Level.SEVERE, "线程池等待终止时发生异常", e.getMessage());
Thread.currentThread().interrupt();
}
}
如何使用
本项目是利用
hexo-generator-feed
生成的 RSS 进行解析并获取文章列表,所以需要你在 Hexo 安装该插件1
npm install hexo-generator-feed --save
然后在博客的配置文件里添加如下配置
1
2
3
4
5
6
7
8
9
10
11
12
13feed:
enable: true
type: atom
path: atom.xml
limit: 0
hub:
content: true
content_limit:
content_limit_delim: ' '
order_by: -date
icon: 图标.icon
autodiscovery: true
template:详情见插件地址:hexojs/hexo-generator-feed
【Fork】本项目并在仓库的
settings -> Secrets and variables -> Actions -> New repository secret
添加环境变量- 详情见【参数说明】
最后在 Actions 运行 Workflows 文件
参数说明
Secrets | Value 说明 |
---|---|
RSS_URL | rss 地址,eg:https://example.org/atom.xml |
INDEX_NOW_KEY | https://www.bing.com/indexnow/getstarted#implementation 获取 KEY 并把文件下载到本地,放在 Hexo 根目录的 source 下 eg: 6b0e36ed24d24c68a6f3415c41ee849a |
BING_KEY | https://www.bing.com/webmasters/home 设置 -> API 访问 -> 查看 API 密钥 |
BAIDU_KEY | https://ziyuan.baidu.com/linksubmit/index 只要 token 的值 |
GOOGLE_KEY | JSON 内容,到 json.cn 压缩代码 |
BOT_TOKEN | 通过 @BotFather 获取机器人 token |
CHAT_ID | 和它对话获取 chat_id @userinfobot |
提交数量:
因本项目是获取你的 RSS 地址,所以你 RSS 有多少条文章链接,就提交多少条,如需要设置提交数量可在 KEY 的后面加个 ,
隔开数量
1 | eg: hCvGPEqkx7L5hJur,100 |
特别说明:
INDEX_NOW_KEY:Secrets 变量里不仅需要填入 KEY,还需要你把它那个文件下载并放入到网站的根目录,可以参考官方的请求示例:
keyLocation
1
2
3
4
5
6
7
8
9
10
11
12
13POST /IndexNow
Content-Type: application/json; charset=utf-8
Host: api.indexnow.org
{
"host": "www.example.org",
"key": "960ca71a21c141f7a4deb8edcb256bf4",
"keyLocation": "https://www.example.org/960ca71a21c141f7a4deb8edcb256bf4.txt",
"urlList": [
"https://www.example.org/url1",
"https://www.example.org/folder/url2",
"https://www.example.org/url3"
]
}BAIDU_KEY:百度提交的好像大部分站长都是 10 条,所以本项目百度提交默认为 10 条,有需求的可以在 token 后加个
,提交的数量
1
hCvGPEqkx7L5hJur,100
GOOGLE_KEY:前提你需要创建项目并启用
Web Search Indexing API
,最后创建密钥时把JSON
文件下载到本地,前置操作可以参考【如何使用google index api来自动提交url】挺详细的。然后打开【json.cn】压缩 JSON 代码,并填入压缩后的代码
结语
该收录的自然会收录,瞧不上的自然瞧不上 —— 孙泽康
话虽如此,但是有新东西,我不用,我难受😭