通过http请求获取天气信息:
这里借鉴一下 中国气象局网站举例
首先根据网址 分析:
http://weather.cma.cn/通过vscode插件:REST Client 发送请求我们会得到内容
首先我们的打开浏览器调试工具查看请求格式
筛选以下几个关键的格式,试着用插件发送请求
GET /web/weather/57516.html HTTP/1.1
Host: weather.cma.cn
Referer: http://weather.cma.cn/web/weather/58238.html
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36 可以看到我们获取到了内容,所有这个请求格式是正确的 所以单片机请求应该这样写:
所以单片机请求应该这样写:
 
这里用的库为ArduinoHttpClient.h
拿到一个库,首先应该是先看例程:
/*
  Dweet.io GET 客户端示例,使用 ArduinoHttpClient 库
  每隔十秒连接到 dweet.io,
  发送一个 GET 请求和请求体。使用 SSL 加密。
  展示了如何使用 Strings 组装路径和解析响应内容。
  dweet.io 预期的请求格式如下:
  https://dweet.io/get/latest/dweet/for/thingName
  更多关于 dweet.io 的信息,请参考 https://dweet.io/play/
  创建于 2016 年 2 月 15 日
  最后更新于 2019 年 1 月 22 日
  作者:Tom Igoe
  此示例代码属于公共领域,可自由使用
*/
// 包含 ArduinoHttpClient 库和 WiFi101 库
#include <ArduinoHttpClient.h>
#include <WiFi101.h>
// 包含敏感数据的头文件,如 WiFi 凭证
#include "arduino_secrets.h"
// WiFi 设置
// 注意:请在 Secret 标签下的 arduino_secrets.h 文件中输入您的敏感数据
char ssid[] = SECRET_SSID; // WiFi 网络名称
char pass[] = SECRET_PASS; // WiFi 密码
const char serverAddress[] = "dweet.io";  // 服务器地址
int port = 80;                            // 服务器端口
String dweetName = "scandalous-cheese-hoarder"; // 在此处使用您自己的设备名称
// 创建 WiFi 客户端和 HTTP 客户端实例
WiFiClient wifi;
HttpClient client = HttpClient(wifi, serverAddress, port);
int status = WL_IDLE_STATUS;              // WiFi 连接状态变量
// 初始化函数
void setup() {
  // 开始串行通信
  Serial.begin(9600);
  while (!Serial);
  // 尝试连接到指定的 WiFi 网络
  while (status != WL_CONNECTED) {
    Serial.print("尝试连接到名为: ");
    Serial.println(ssid); // 输出网络名称
    // 连接到 WPA/WPA2 网络
    status = WiFi.begin(ssid, pass);
  }
  // 输出已连接的 WiFi 网络的 SSID
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  // 输出 WiFi 盾牌的 IP 地址
  IPAddress ip = WiFi.localIP();
  Serial.print("IP 地址: ");
  Serial.println(ip);
}
// 主循环函数
void loop() {
  // 组装 GET 请求的路径
  String path = "/get/latest/dweet/for/" + dweetName;
  // 发送 GET 请求
  Serial.println("发送 GET 请求");
  client.get(path);
  // 读取响应的状态码和响应体
  int statusCode = client.responseStatusCode();
  String response = client.responseBody();
  Serial.print("状态码: ");
  Serial.println(statusCode);
  Serial.print("响应: ");
  Serial.println(response);
  // 典型响应示例:
  // {"this":"succeeded","by":"getting","the":"dweets","with":[{"thing":"my-thing-name","created":"2016-02-16T05:10:36.589Z","content":{"sensorValue":456}}]}
  // 我们关心的是 "content": 数值
  // 现在解析响应,寻找 "content" 字段
  int labelStart = response.indexOf("content\":");
  // 找到 "content" 后的第一个 {
  int contentStart = response.indexOf("{", labelStart);
  // 找到紧接着的 },并获取大括号之间的内容
  int contentEnd = response.indexOf("}", labelStart);
  String content = response.substring(contentStart + 1, contentEnd);
  Serial.println(content);
  // 接下来获取冒号后的数值,并转换成整数
  int valueStart = content.indexOf(":");
  String valueString = content.substring(valueStart + 1);
  int number = valueString.toInt();
  Serial.print("数值字符串: ");
  Serial.println(valueString);
  Serial.print("实际数值: ");
  Serial.println(number);
  // 等待十秒钟
  Serial.println("等待十秒钟\n");
  delay(10000);
}示例程序二
/*
  简单的 WebSocket 客户端示例,使用 ArduinoHttpClient 库
  连接到 WebSocket 服务器,并每隔 5 秒发送一条问候消息
  创建于 2016 年 6 月 28 日
  作者:Sandeep Mistry
  修改于 2019 年 1 月 22 日
  修改者:Tom Igoe
  此示例代码属于公共领域,可自由使用
*/
// 包含 ArduinoHttpClient 库和 WiFi101 库
#include <ArduinoHttpClient.h>
#include <WiFi101.h>
// 包含敏感数据的头文件,如 WiFi 凭证
#include "arduino_secrets.h"
// WiFi 设置
// 注意:请在 Secret 标签下的 arduino_secrets.h 文件中输入您的敏感数据
char ssid[] = SECRET_SSID; // WiFi 网络名称
char pass[] = SECRET_PASS; // WiFi 密码
char serverAddress[] = "echo.websocket.org"; // 服务器地址
int port = 80;                              // 服务器端口
// 创建 WiFi 客户端和 WebSocket 客户端实例
WiFiClient wifi;
WebSocketClient client = WebSocketClient(wifi, serverAddress, port);
int status = WL_IDLE_STATUS;                // WiFi 连接状态变量
int count = 0;                              // 计数器,用于发送消息
// 初始化函数
void setup() {
  // 开始串行通信
  Serial.begin(9600);
  while (status != WL_CONNECTED) {
    Serial.print("尝试连接到名为: ");
    Serial.println(ssid); // 输出网络名称
    // 连接到 WPA/WPA2 网络
    status = WiFi.begin(ssid, pass);
  }
  // 输出已连接的 WiFi 网络的 SSID
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  // 输出 WiFi 盾牌的 IP 地址
  IPAddress ip = WiFi.localIP();
  Serial.print("IP 地址: ");
  Serial.println(ip);
}
// 主循环函数
void loop() {
  // 开始 WebSocket 客户端
  Serial.println("启动 WebSocket 客户端");
  client.begin();
  // 当客户端与服务器保持连接时
  while (client.connected()) {
    Serial.print("发送问候 ");
    Serial.println(count); // 输出计数器的值
    // 发送一条文本类型的消息
    client.beginMessage(TYPE_TEXT);
    client.print("hello "); // 发送问候语
    client.print(count);    // 发送计数器的值
    client.endMessage();    // 结束消息发送
    // 增加计数器的值,用于下一次消息
    count++;
    // 检查是否有消息可接收
    int messageSize = client.parseMessage();
    if (messageSize > 0) {
      Serial.println("收到一条消息:");
      Serial.println(client.readString()); // 输出接收到的消息
    }
    // 等待 5 秒钟
    delay(5000);
  }
  Serial.println("已断开连接"); // 当不再连接时输出
}单片机代码:

然而结果不太理想
 那么这里就会有一个问题了:为什么没有反馈
那么这里就会有一个问题了:为什么没有反馈
 
我最开始的时候也是百思不得其解,甚至还尝试更换库
然而终于,在2024/7/27 今天的 0:15分我_悟了:想明白一件事是很有成就感的(被bug折磨得人都要疯了)
一切全部都是 网址的问题,因为我一开始就错了:
现在我们从头开始复盘:
首先,请求下发,得到如下结果:
 最开始,我们以为请求结果由html生成
最开始,我们以为请求结果由html生成
所以测试用例为:

当我们用这种方式去请求之后,确实如愿的取得了页面数据

当单片机发送请求之后,由于网页内容太多,加上,大部分内容都是由js控制动态生成.
所以获取页面信息然后走爬虫的路子,基本上要放弃.
直到刚刚,我才知道有这么一个请求,它就是数据!! json的交互数据请求: 是不是很眼熟? 53698!
 打开看看: 原来如此
 打开看看: 原来如此
 
看ip地址大致能猜出意思
api嘛就是 接口 now 现在 后面这个数字多半就是 表某城市 数字
 验证一下: 很明显,数据正常!
验证一下: 很明显,数据正常!
 
 更改单片机HTTP请求之后结果:
更改单片机HTTP请求之后结果:
 
 串口输出结果正常
串口输出结果正常
 
,那么问题解决了.下一步就应该是json解析了.

===前面的都是废话,点击 一键直达 结果===
获取天气,分3步:
第一步:得到请求地址: http://weather.cma.cn/api/now/54511
拆分为:
服务器地址:weather.cma.cn
天气请求地址:/api/now/
城市代码:54511 (北京)
第二步:编写请求代码,这里以 HttpClient.h 库 举例
WiFiClient ClientA;          
// 设置一个 联网 后客户端实例 类似于打开浏览器
HttpClient clienta(ClientA,"weather.cma.cn",80);
//把这个客户端 绑定到这个服务器  类似于用浏览器打开了这一个网页
clienta.kUserAgent="User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
//一个通用的浏览器标识  类似于告诉服务器 我是一个正儿八经的浏览器  不要拒绝我
//实际上单片机不设置这条,它也能...................
clienta.get("/api/now/53698");
//发送get请求  类似这样 GET /api/now/53698 HTTP/1.1
String buf=clienta.responseBody();
//获取返回的结果  
Serial.println(buf);
//串口输出第三步:处理json数据了,这里用 ArduinoJson.h 库举例
//json数据解析
DynamicJsonDocument doc(1024); // 动态分配内存用于存储JSON数据
deserializeJson(doc, buf);// 将JSON数据反序列化为doc
JsonObject locationobj= doc["data"]["location"].as<JsonObject>();// 获取JSON对象 data中location
JsonObject nowobj = doc["data"]["now"].as<JsonObject>();// 获取JSON对象data中now
JsonObject  lastUpdateobj= doc["data"]["lastUpdate"];// 获取JSON对象data中lastUpdate
String strjson=locationobj["path"];// 获取JSON对象data中location中的path属性
  int index1 = strjson.indexOf(",");  // 查找第一个逗号的位置
  int index2 = strjson.indexOf(",", index1 + 1);  // 查找第二个逗号的位置
  
  String part1 = strjson.substring(0, index1);  // 截取第一个部分
  String part2 = strjson.substring(index1 + 1, index2);  // 截取第二个部分
  String part3 = strjson.substring(index2 + 1);  // 截取第三个部分
  
  Serial.println("国家"+part1);// 输出第一个部分
  Serial.println("城市"+part2);// 输出第二个部分 这一步:还需进一步处理,测试结果显示补全
  Serial.println("区县"+part3);// 输出第三个部分
  Serial.println("温度"+String(nowobj["temperature"])+"℃");
  Serial.println("湿度"+String(nowobj["humidity"])+"%");
  Serial.println("气压"+String(nowobj["pressure"])+"hPa");
// 获取时间 这一步:还需进一步处理,测试结果显示补全
Serial.println("时间:"+String(lastUpdateobj["lastUpdate"]));
整篇结果展示: 现在时间2024/7/27 1:46 晚安!





















