bms_table/
fetch.rs

1//! 网络请求与解析相关功能
2#![cfg(feature = "scraper")]
3
4pub mod reqwest;
5
6use anyhow::{anyhow, Result};
7use scraper::{Html, Selector};
8use serde_json::Value;
9
10/// [`get_web_header_json_value`]的返回类型
11pub enum HeaderQueryContent {
12    /// 注意:可能解析出相对或绝对Url,建议使用`url::Url::join`。
13    Url(String),
14    /// Json树
15    Json(Value),
16}
17
18/// 从相应数据中提取Json树(Json内容)或Header地址(HTML内容)
19pub fn get_web_header_json_value(response_str: &str) -> anyhow::Result<HeaderQueryContent> {
20    // 先尝试按 JSON 解析;失败则当作 HTML 提取 bmstable URL
21    match serde_json::from_str::<Value>(response_str) {
22        Ok(header_json) => Ok(HeaderQueryContent::Json(header_json)),
23        Err(_) => {
24            let bmstable_url = extract_bmstable_url(response_str)?;
25            Ok(HeaderQueryContent::Url(bmstable_url))
26        }
27    }
28}
29
30/// 从HTML页面内容中,提取bmstable字段指向的JSON文件URL
31pub fn extract_bmstable_url(html_content: &str) -> Result<String> {
32    let document = Html::parse_document(html_content);
33
34    // 查找所有meta标签
35    let Ok(meta_selector) = Selector::parse("meta") else {
36        return Err(anyhow!("未找到meta标签"));
37    };
38
39    for element in document.select(&meta_selector) {
40        // 检查是否有name属性为"bmstable"的meta标签
41        if let Some(name_attr) = element.value().attr("name") {
42            if name_attr == "bmstable" {
43                // 获取content属性
44                if let Some(content_attr) = element.value().attr("content") {
45                    if !content_attr.is_empty() {
46                        return Ok(content_attr.to_string());
47                    }
48                }
49            }
50        }
51    }
52
53    Err(anyhow!("未找到bmstable字段"))
54}