基于功能需求,需要得知当前地点的天气状况;项目技术采用QT框架,利用C++集成python,获取python接口解析获取的天气数据,并吐给qml前端显示;
1.步骤一:cmakelist.txt方式构建带界面的qml基础程序,直接主程序通过QQuickView方式构建主界面;(QWindows的方式也行,按自己喜好)
main函数示例:
2.步骤二:编写python爬取天气网数据(利用requests和BeautifulSoup库);
注意: 若能直接解析天气网主页,触发主页js,应该能够直接获取到本地ip的天气情况;否则建议主页HTML直接ctrl+S,找到存储路径里面的城市对应的id,拼凑成具体城市天气的html,获取数据并解析;(本文主要示例后者)
参考链接:
爬取天气网数据:Python爬取天气数据及可视化分析-python爬取天气数据 (51cto.com)
天气网主页:天气网 (weather.com.cn)
python方法:
import requests
from bs4 import BeautifulSoup
def getHTMLtext(url):
"""请求获得网页内容"""
try:
r = requests.get(url, timeout = 30)
r.raise_for_status()
r.encoding = r.apparent_encoding
print("Success")
return r.text
except:
print("Fail")
return" "
def save(doc,fileName):
file = open(fileName, 'w',encoding="utf-8")
file.write(doc)
file.close()
def parseWeather(strHtml):
tmpSoup = BeautifulSoup(str(strHtml), 'html.parser')
day = tmpSoup.find_all("h1")[0].string
wea = tmpSoup.find_all("p",class_ = "wea")[0].string
temSoup = BeautifulSoup(str(tmpSoup.find_all("p",class_ = "tem")), 'html.parser')
hightem = temSoup.find_all("span")[0].string
lowtem = temSoup.find_all("i")[0].string
#print("天气信息====>>>",day,wea, ":", hightem,"/",lowtem)
return str(day+wea+":"+hightem+"/"+lowtem)
#101270101 成都的城市id
def cityHtml(url):
cityWeatherHtml = getHTMLtext(url)
citySoup = BeautifulSoup(cityWeatherHtml, 'html.parser')
h1 = citySoup.find_all("ul", class_="t clearfix")
soup2 = BeautifulSoup(str(h1), 'html.parser') #h1 type bs4.element.ResultSet
weatherList = soup2.find_all("li")
print("======weather info length:",len(weatherList))
weatherStrList = []
for i in weatherList:
info = parseWeather(str(i))
weatherStrList.append(info)
print("======Array:",weatherStrList)
print("======type of:",type(weatherStrList))
return weatherStrList
#cityHtml("")
3.步骤三:集成python项目到C++中:
1).确保已经安装了python环境;拷贝python环境下的lib、include、dlls目录到项目中,并拷贝带python方法的文件到项目里;我这里使用的是mingW64,所以采用python64的库;
include和libs文件夹编译需要,include中包含python入口的python.h头文件,libs主要包括python的编译链接库python312.lib;
2).CmakeList.txt文件中,链接上include所有头文件,和libs中的lib库(这些库和所有头文件是否全需要这个未作验证,有兴趣的小伙伴可以自行尝试)
3).引入头文件Python.h ,按步骤调用python方法,获取返回值即可
参考链接:
(1).C++调用python: C++调用python的那些坑(详细教程步骤)_c++调用python函数getattrstring失败-CSDN博客
C++调用python脚本 - 知乎 (zhihu.com)
(2).C++获取python返回值:Python + C/C++ 嵌入式编程(1):多维数组Numpy.Array()在Python和C/C++文件间的传递问题_c++ 调用python 传递多维数组-CSDN博客
4).参考代码:
QString WeatherData::doPython(){
QString toDayWeather = "";
PyObject* pModule = NULL;
PyObject* pFunc = NULL;
PyObject* pArg = NULL;
Py_SetPythonHome((wchar_t *)(L"./Python/"));//指定python库解释器的路径
Py_Initialize();//初始化Python
// 初始化python系统文件路径,保证可以访问到 .py文件
// python为运行时链接,即weather.py与.exe的相对路径;而不是本文件main.cpp与.py文件的相对路径
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
// 调用python文件名,不用写后缀
pModule = PyImport_ImportModule("weather");
if( pModule == NULL ){
qDebug() <<"module not found";
return toDayWeather;
}
// 获取函数
pFunc = PyObject_GetAttrString(pModule, "cityHtml");
if( !pFunc || !PyCallable_Check(pFunc)){
qDebug() <<"not found function add_num";
return toDayWeather;
}
// 构造参数
pArg = Py_BuildValue("(s)", "http://www.weather.com.cn/weather/101270101.shtml"); //一个字符串参数
PyObject* pReturn = PyObject_CallObject(pFunc, pArg);
// 7、接收python计算好的返回值
// QStringList nResult;
// i表示转换成int型变量。 s表示转换成string型变量
// 在这里,最需要注意的是:PyArg_Parse的最后一个参数,必须加上“&”符号
if(PyList_Check(pReturn)){ //检查是否为List对象
int sizeOfList = PyList_Size(pReturn);//List对象的大小,这里SizeOfList =
qDebug() << "=============> SizeOfList:"<<sizeOfList;
for(int i = 0; i < sizeOfList; i++){
PyObject *Item = PyList_GetItem(pReturn, i);//获取List对象中的每一个元素
char * result;
PyArg_Parse(Item, "s", &result);//s表示转换成string型变量
//python字符串转换完是utf8编码,需按需转换目标字符编码
QString result2 = QString::fromUtf8(result);
if(i == 0) {
toDayWeather = result2;
}
qDebug() << "=======QString Value:" <<result2;
//Py_DECREF(Item); //释放空间 #会导致释放崩溃
}
}else{
qDebug() <<"Not a List";
}
Py_Finalize(); //释放python接口
return toDayWeather;
}
注意:PyList_GetItem获取的空间需要手动释放(Py_DECREF),否则会造成内存泄漏;示例中释放导致崩溃,暂未解决;若集成此部分代码,需要考虑解决
4.打包集成:至此,程序若顺利,可以直接在带python环境的机器上编译运行;但需要打包发布,仍需要做一些操作;
1).利用windeployqt打包编译出来的exe所需的qt依赖库;这里暂不赘述,参考本篇文章:QT(qml)程序打包成绿色exe可执行或exe可安装文件(Enigma Virtual Box、Inner SetUp Compiler)_含qml的exe打包-CSDN博客
2).将python依赖,以及python运行环境编译到程序目录中;
说是编译,其实是拷贝到程序构建目录中,并指定执行环境,由于python是运行时链接,所有相对路径需要按照构建出的exe为程序的“当前路径”;
(1).拷贝依赖
示例:这里分别将带"爬虫方法的python文件"、"python312.dll动态库"、"python环境dll和lib"复制到目标路径;
(2).指定环境(上面参考代码中已经指明)
至此,程序构建后,生成的exe打包好QT的依赖,就可以直接双击exe运行了。运行效果截图:
源程序地址:天气预报-爬虫: C++嵌入python模块,python爬取天气数据并解析 1.C++调用python爬虫接口 2.C++qml显示爬虫数据 (gitee.com)