记一次开发实战-对提供接口的C/C++进行二次开发

点击蓝字

9a9f147b94f93fbde21a219e81a7a7f5.png

关注我们

一、需求描述

我有一个USB5538的库和头文件,并通过头文件提供了接口,我想把它更改一下,编译成python可调用的模块。

二、创建工程及其目录

1、创建空项目

c8f635fbfb470c12984831557a1f1d9f.png

ce7a18e115c6c73c1ab3295961c35d5e.png

32d978040e194d88e7cf00dc01995a4b.png

 2、创建目录

a6a1feaf33cbdc2acb653415e3c5dd61.png

d9f636520068ff753871a73adb39928c.png

三、创建文件

1、复制文件并添加

e9511d3a3f007f7a5dbcbb682e1b7f78.png

fb5543eb629bbe717fdc3dae144625b1.png

126612fe8f30a2d296b82c8b928466a0.png

2、添加新文件并写入

7bbbca0cc1f77e53aa9d350e954e5474.png

a44a5f03fde30f075e4a275c19557aeb.png

四、环境配置

1、环境异常情况

4ae3fe451ec45d3aa86fbbe7d5c008eb.png

2、配置环境以消除异常

615c05e7607410097236644473e34ef1.jpeg

0189b238a99e4cfe256e91ab055f28f6.png

194dafc2ceac7981cca398a9d2236db8.png

059c6fd93930e7a49f73222a4744cad7.png

五、运行代码

1、二次封装代码

定义一个接口对象,调用之前的接口,并将方法写入该接口对象即可。

#include <iostream>
using namespace std;
#include "usbpylib.h"
// usbpylib.cpp : 只包括标准包含文件的源文件
// Sys.pch 将作为预编译头
// usbpylib.obj 将包含预编译类型信息class AutoTest {//private:
public://USB5538数据采集器HANDLE createUSB5538();void releaseUSB5538(HANDLE hDevice);void resetUSB5538(HANDLE hDevice);  //复位,相当于与PC重连,等同于重新插上USBvoid getUSB5538DI_All(HANDLE hDevice, BYTE bDISts[16]);  //bDISts[16]为output参数void setUSB5538DO_All(HANDLE hDevice, BYTE bDOSts[16]);  //bDOSts[16]为input参数int getUSB5538DI_One(HANDLE hDevice, int iDI);void setUSB5538DO_One(HANDLE hDevice, int iDO, int value);
};// TODO: 在 STDAFX.H 中
// 引用任何所需的附加头文件,而不是在此文件中引用HANDLE AutoTest::createUSB5538()
{return USB5538_CreateDevice(0);
}void AutoTest::releaseUSB5538(HANDLE hDevice)
{if (hDevice == INVALID_HANDLE_VALUE){return;}USB5538_ReleaseDevice(hDevice);
}void AutoTest::resetUSB5538(HANDLE hDevice)
{if (hDevice == INVALID_HANDLE_VALUE){return;}USB5538_ResetDevice(hDevice);
}void AutoTest::getUSB5538DI_All(HANDLE hDevice, BYTE bDISts[])
{if (hDevice == INVALID_HANDLE_VALUE){return;}USB5538_GetDeviceDI(hDevice, bDISts);
}void AutoTest::setUSB5538DO_All(HANDLE hDevice, BYTE bDOSts[])
{if (hDevice == INVALID_HANDLE_VALUE){return;}USB5538_SetDeviceDO(hDevice, bDOSts);
}int AutoTest::getUSB5538DI_One(HANDLE hDevice, int iDI)
{if (hDevice == INVALID_HANDLE_VALUE){return -1;}BYTE bDISts[16];USB5538_GetDeviceDI(hDevice, bDISts);return bDISts[iDI];
}void AutoTest::setUSB5538DO_One(HANDLE hDevice, int iDO, int value)
{if (hDevice == INVALID_HANDLE_VALUE){return;}BYTE bDOSts[16];USB5538_RetDeviceDO(hDevice, bDOSts);//回读输出状态bDOSts[iDO] = value;USB5538_SetDeviceDO(hDevice, bDOSts);
}int main()
{HANDLE obj1;BYTE bd[16] = { 0,0,0,0,0,1,1,1, 0,0,0,0,0,1,1,1 };AutoTest AutoTest1;//cout << "Hello World";obj1 = AutoTest1.createUSB5538();cout << "句柄是\n" << obj1 << "\n";AutoTest1.getUSB5538DI_All(obj1, bd);AutoTest1.resetUSB5538(obj1);AutoTest1.releaseUSB5538(obj1);//cout << "Hello World";HANDLE hDevice = AutoTest1.createUSB5538();if (hDevice == INVALID_HANDLE_VALUE){cout << "create error...." << "\n";}BYTE bDOSts[16];BYTE bDISts[16];bDOSts[0] = 0;bDOSts[1] = 1;bDOSts[2] = 0;bDOSts[3] = 1;bDOSts[4] = 0;bDOSts[5] = 1;bDOSts[6] = 0;bDOSts[7] = 1;bDOSts[8] = 0;bDOSts[9] = 1;bDOSts[10] = 0;bDOSts[11] = 1;bDOSts[12] = 0;bDOSts[13] = 1;bDOSts[14] = 0;bDOSts[15] = 1;AutoTest1.setUSB5538DO_All(hDevice, bDOSts);AutoTest1.getUSB5538DI_All(hDevice, bDISts);cout << "bDISts是\n" << bDISts << "\n";
}

2、如图,运行正常,说明对原接口的二次封装是有效的

23f488875c374d72748871277b10d5b9.png

六、将原功能改写成接口,供python调用

1、基于原有代码,创建新文件USB5538.cpp编写如下:

#define PY_SSIZE_T_CLEAN  // 建议在包含Python.h之前总是定义PY_SSIZE_T_CLEAN。
#include <Python.h>  // 打包成python扩展所需要的头文件#include <iostream>
using namespace std;//#ifndef _USBPYLIB_H_ // 避免头文件被多次编译
//#define _USBPYLIB_H_
#include "../include/usbpylib.h"
//#endif// 函数的三种实现方式,C函数通常是通过将Python模块和函数名组合在一起命名的,如模块是Combinations(也是.cpp名称),函数是uniqueCombinations,组成了一个函数名
static PyObject* 
USB5538_get(PyObject* self)  // 定义功能有三种方式,详细文档(旧文档)请查阅https://www.tutorialspoint.com/python/python_further_extensions.htm
{   //PyLongObject one = USB5538_CreateDevice(0);//PyAddrPair one = USB5538_CreateDevice(0);//PyAnySet_Check one = USB5538_CreateDevice(0);//PyAnySet_CheckExact one = USB5538_CreateDevice(0);//PyAPI_DATA one = USB5538_CreateDevice(0);//PyAPI_FUNC one = USB5538_CreateDevice(0);//PyArena_AddPyObject one = USB5538_CreateDevice(0);//PyASCIIObject one = USB5538_CreateDevice(0);//PyBaseObject_Type one = USB5538_CreateDevice(0);//PyByteArrayObject one = USB5538_CreateDevice(0);//PyBytes_FromObject one = USB5538_CreateDevice(0);//PyBytesObject one = USB5538_CreateDevice(0);//PyObject_AsCharBuffer one = USB5538_CreateDevice(0);//PyObject_AsReadBuffer one = USB5538_CreateDevice(0);//PyObject_CallObject one = USB5538_CreateDevice(0);PyObject_Length one = USB5538_CreateDevice(0);//CompareObjectHandles one = USB5538_CreateDevice(0);//PyOS_sighandler_t one = USB5538_CreateDevice(0);//PyObject one = USB5538_CreateDevice(0);HANDLE hDevice = USB5538_CreateDevice(0);  // 获取句柄cout << hDevice;BYTE bd[16] = { 0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1 };//if (hDevice == INVALID_HANDLE_VALUE)//{//    return;//}BOOL a = USB5538_GetDeviceDI(hDevice, bd);  // 获取设备DI状态USB5538_ReleaseDevice(hDevice);  // 释放句柄return Py_BuildValue("s", "uniqueCombinations() return value (is of type 'string')");;//if (a == true)//{//    return NULL;//}//else //{ //    return 0;//};
};/*
函数的三种实现方式例子:
static PyObject *MyFunction( PyObject *self, PyObject *args );  // METH_VARARGS
static PyObject *MyFunctionWithKeywords(PyObject *self,PyObject *args,PyObject *kw);  // METH_KEYWORDS
static PyObject *MyFunctionWithNoArgs( PyObject *self );  // METH_NOARGS
*/static char get_docs[] = "获取设备的相关信息\n";  // 随意定义的文档字符串描述// 方法映射表,方法表是一个简单的PyMethodDef结构数组
static PyMethodDef module_methods[] = {{"get", (PyCFunction)USB5538_get, METH_NOARGS, get_docs},{ NULL, NULL, 0, NULL }// 格式解释:{ml_name,ml_meth,ml_flags,ml_doc}// ml_name:这是Python解释器在Python程序中使用的函数名。// ml_meth:这必须是函数名。// ml_flags:函数的三种实现方式,上述例子中已经标明对应字段选择// ml_doc:可以为空值,四个选项对应的空值分别为:{ NULL, NULL, 0, NULL }
};// 模块后面加module,比较规范。这个结构必须在模块的初始化函数中传递给解释器。初始化函数必须命名为PyInit_name(),其中name是模块的名称,并且应该是模块文件中定义的唯一非静态项
static struct PyModuleDef USB5538module =
{PyModuleDef_HEAD_INIT,"Combinations",  /* 模块名称 */"usage: Combinations.uniqueCombinations(lstSortableItems, comboSize)\n", /* 模块文档*/-1, /* 模块的每个解释器状态的大小,如果模块在全局变量中保持状态,则为-1。*/module_methods  /* 方法映射表 , 即需要引用定义好的引射表*/
};// 初始化函数,之前的初始化方法 PyMODINIT_FUNC initModule() 已弃用,新文档见 https://docs.python.org/3/extending/extending.html
PyMODINIT_FUNC PyInit_USB5538(void)
{return PyModule_Create(&USB5538module);  // 它返回一个模块对象,并根据模块定义中的表(PyMethodDef结构的数组)将内置函数对象插入到新创建的模块中。
}

2、尝试进行编译

26d11ce4cb804c9c8d853e8c6fff4f5e.png

3、尝试将该文件打包成python库

新建setup.py文件写入以下内容

from distutils.core import setup, Extension
setup(name='USB5538', version='0.1', ext_modules=[Extension('USB5538', [r'D:\MinGW\projects\USB5538ForPython\source\USB5538.cpp' ])])

打开cmd窗口执行setup.py文件(要进入该文件目录下执行)

python setup.py build
python setup.py install --record files.txt

以及调用其接口,均能成功

bd06ca28a667da30740c53b1204d67e7.png

七、丰富接口

1、将该接口改为传参对象

#define PY_SSIZE_T_CLEAN  // 建议在包含Python.h之前总是定义PY_SSIZE_T_CLEAN。
#include <Python.h>  // 打包成python扩展所需要的头文件#include <stdio.h>#include <iostream>
using namespace std;//#ifndef _USBPYLIB_H_ // 避免头文件被多次编译
//#define _USBPYLIB_H_
#include "../include/usbpylib.h"
//#endif// 函数的三种实现方式,C函数通常是通过将Python模块和函数名组合在一起命名的,如模块是Combinations(也是.cpp名称),函数是uniqueCombinations,组成了一个函数名
static PyObject* 
USB5538_set(PyObject* self, PyObject* args)  // 定义功能有三种方式,详细文档(旧文档)请查阅https://www.tutorialspoint.com/python/python_further_extensions.htm
{   //PyLongObject one = USB5538_CreateDevice(0);//PyAddrPair one = USB5538_CreateDevice(0);//PyAnySet_Check one = USB5538_CreateDevice(0);//PyAnySet_CheckExact one = USB5538_CreateDevice(0);//PyAPI_DATA one = USB5538_CreateDevice(0);//PyAPI_FUNC one = USB5538_CreateDevice(0);//PyArena_AddPyObject one = USB5538_CreateDevice(0);//PyASCIIObject one = USB5538_CreateDevice(0);//PyBaseObject_Type one = USB5538_CreateDevice(0);//PyByteArrayObject one = USB5538_CreateDevice(0);//PyBytes_FromObject one = USB5538_CreateDevice(0);//PyBytesObject one = USB5538_CreateDevice(0);//PyObject_AsCharBuffer one = USB5538_CreateDevice(0);//PyObject_AsReadBuffer one = USB5538_CreateDevice(0);//PyObject_CallObject one = USB5538_CreateDevice(0);PyObject_Length one = USB5538_CreateDevice(0);//CompareObjectHandles one = USB5538_CreateDevice(0);//PyOS_sighandler_t one = USB5538_CreateDevice(0);//PyObject one = USB5538_CreateDevice(0);int a1;int a2;int a3;int a4;int a5;int a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16;if (!PyArg_ParseTuple(args, "iiiiiiiiiiiiiiii", &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16)){//return Py_BuildValue("s", "参数输入有误,请传递全数字的列表!");return Py_BuildValue("s", "error!");}//return Py_BuildValue("(iiiiiiiiiiiiiiiii)", a1 + a1, a1 - a2, a1+a3);HANDLE hDevice = USB5538_CreateDevice(0);  // 获取句柄//cout << hDevice << "\n";BYTE bd[16] = { a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16 };//BYTE bd[16] = { 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1 };  // 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0USB5538_SetDeviceDO(hDevice, bd);//BOOL DIstatus = USB5538_GetDeviceDI(hDevice, bd);  // 获取设备DI状态//cout << DIstatus << "\n";USB5538_ReleaseDevice(hDevice);  // 释放句柄//return Py_BuildValue("s", "恭喜你,在窗口打印设备句柄成功!");return Py_BuildValue("s", "set success!");
};/*
函数的三种实现方式例子:
static PyObject *MyFunction( PyObject *self, PyObject *args );  // METH_VARARGS
static PyObject *MyFunctionWithKeywords(PyObject *self,PyObject *args,PyObject *kw);  // METH_KEYWORDS
static PyObject *MyFunctionWithNoArgs( PyObject *self );  // METH_NOARGS
*///static char get_docs[] = "获取设备的相关信息\n";  // 随意定义的文档字符串描述
static char get_docs[] = "get info of device\n";  // 随意定义的文档字符串描述// 方法映射表,方法表是一个简单的PyMethodDef结构数组
static PyMethodDef module_methods[] = {{"set", (PyCFunction)USB5538_set, METH_VARARGS, get_docs},{ NULL, NULL, 0, NULL }// 格式解释:{ml_name,ml_meth,ml_flags,ml_doc}// ml_name:这是Python解释器在Python程序中使用的函数名。// ml_meth:这必须是函数名。// ml_flags:函数的三种实现方式,上述例子中已经标明对应字段选择// ml_doc:可以为空值,四个选项对应的空值分别为:{ NULL, NULL, 0, NULL }
};// 模块后面加module,比较规范。这个结构必须在模块的初始化函数中传递给解释器。初始化函数必须命名为PyInit_name(),其中name是模块的名称,并且应该是模块文件中定义的唯一非静态项
static struct PyModuleDef USB5538module =
{PyModuleDef_HEAD_INIT,"USB5538",  /* 模块名称 这个只是python调用__name__时展示,即使写错也不会有影响*///"USB5538的python接口对象,提供丰富的接口,用于操作USB5538设备\n", /* 模块文档*/"USB5538 of python interface\n", /* 模块文档*/-1, /* 模块的每个解释器状态的大小,如果模块在全局变量中保持状态,则为-1。*/module_methods  /* 方法映射表 , 即需要引用定义好的引射表*/
};// 初始化函数,之前的初始化方法 PyMODINIT_FUNC initModule() 已弃用,新文档见 https://docs.python.org/3/extending/extending.html
PyMODINIT_FUNC PyInit_USB5538(void)
{return PyModule_Create(&USB5538module);  // 它返回一个模块对象,并根据模块定义中的表(PyMethodDef结构的数组)将内置函数对象插入到新创建的模块中。
}

2、验证

如图,验证成功!

b0ad84c3d84a88d2fe523e3fda1ff591.png

*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

a093e51feb17ca8b660843894a257093.png

e441ca715f87f5b38cebf9735fd04750.gif

戳“阅读原文”我们一起进步

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

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

相关文章

C++是如何实现多态的

C是如何实现多态的结论&#xff1a;C通过虚函数来实现多态的&#xff0c;根本原因是派生类和基类的虚函数表的不同。 构成多态的必要条件有如下3点&#xff1a; 存在继承关系基类存在虚函数&#xff0c;且派生类有相同原型的函数遮蔽它存在基类类型的指针指向派生类对象&…

C语言实现通讯录附详细代码(动态+静态)

点击蓝字关注我们一、通讯录简介实现一个通讯录&#xff1b;通讯录可以用来存储1000个人的信息&#xff0c;每个人的信息包括&#xff1a;姓名、性别、年龄、电话、住址提供方法&#xff1a;添加联系人信息删除指定联系人信息查找指定联系人信息修改指定联系人信息显示所有联系…

Lua协程Coroutine是什么

Lua协程Coroutine是什么协程和线程不同&#xff1a; 同一时刻&#xff0c;一个多线程程序可以用多个线程同时执行&#xff1b;而协程只能有一个在执行多线程是抢占式的&#xff1b;而协程是非抢占式的&#xff0c;只有协程显示被挂起&#xff0c;才会被挂起 协程和线程的相同…

C++程序的内存分区模型-栈区堆区

点击蓝字关注我们1、栈区&#xff1a;由编译器自动分配释放&#xff0c;存放函数的参数值&#xff0c;局部变量等&#xff08;由编译器管理其“生死”&#xff09;注意事项&#xff1a;不要返回局部变量的地址&#xff0c;栈区开辟的数据由编译器自动释放栈区代码演示&#xff…

CocosStudio的节点如何使用自定义shader

CocosStudio的节点如何使用自定义shader问题&#xff1a;我想对CocosStudio 的 某个UI 里的 某个图片&#xff08;如下图所示的Image类型&#xff09;使用自定义shader。但是&#xff0c;我把 对传统的cc.Sprite应用自定义shader的方式 应用于它时&#xff0c;并不生效&#xf…

excel随机抽取_简单随机抽样及其进阶分层随机抽样方法展示

一、分享简单随机抽样的几种方法1、抽样分析工具抽样2、INDIRECTRANDBETWEEN函数抽样3、RAND排序抽样4、SAS抽样二、分层抽样方法1、Python分层抽样2、SAS分层抽样3、EXCEL函数及功能分层抽样简单随机抽样的几种方法方法一抽样分析工具抽样如果你的EXCEL尚未安装数据分析&#…

为什么存在动态内存分配,动态内存函数(malloc函数,free函数,calloc函数,realloc函数)...

点击蓝字关注我们1.当前我们知道的内存的使用方法2.为什么存在动态内存分配如上我们已学的开辟空间的方式有两个特点&#xff1a;空间开辟的大小是固定的必须指定数组的长度所以就产生了空间开大了浪费开小了不够用的问题&#xff0c;所以使用动态内存分配3.动态内存函数&#…

C++ vector类的模拟实现

点击蓝字关注我们1.前言vector和string虽然底层都是通过顺序表来实现的&#xff0c;但是他们利用顺序表的方式不同&#xff0c;string是指定好了类型&#xff0c;通过使用顺序表来存储并对数据进行操作&#xff0c;而vector是利用了C中的泛型模板&#xff0c;可以存储任何类型的…

visual studio源文件的编译顺序是依据什么?

问题&#xff1a;visual studio源文件的编译顺序是依据什么&#xff1f; 结论&#xff1a;依据 .vcxproj 文件里 指定了ClCompile的ItemGroup &#xff0c;如下图所示&#xff0c;就是这么简单粗暴。

功能齐全的屏幕截图C++实现详解

点击蓝字关注我们1、概述要使用屏幕截图&#xff0c;其实很容易&#xff0c;装一款聊天软件或者办公软件就可以了&#xff0c;比如QQ、企业微信、钉钉、飞书等。但要开发出类似这些软件的屏幕截图模块&#xff0c;则没那么容易。其实实现屏幕截图的技术并不复杂&#xff0c;主要…

如何判断exe文件是debug还是release编译生成的

如何判断exe文件是debug还是release编译生成的结论&#xff1a; 用IDA工具打开exe&#xff0c;然后看Imports里面的依赖库是否有带d或D结尾的&#xff0c;如果有就说明是Debug的 实验&#xff1a;&#xff08;实验环境 vs2017&#xff0c; IDA工具&#xff09; &#xff08;0&…

大屏可视化分配率是什么意思_什么是分配率?

大屏可视化分配率是什么意思诸如“不可持续的分配率”和“您需要保持较低的分配率”之类的短语似乎仅属于Java Champions的词汇表。 复杂&#xff0c;恐怖并被魔术光环包围。 经常发生的情况是&#xff0c;当您更仔细地查看概念时&#xff0c;魔术会随着抽烟消失。 这篇文章试…

C/C++语言动态开辟的杨辉三角

点击蓝字关注我们问题引入杨辉三角相必大家并不陌生&#xff0c;第1行有1列、第二行有2列…第n行有n列&#xff0c;且每行行首和行尾的值都为1&#xff0c;其余的值为上一行两数相加我们在C语言阶段&#xff0c;第一次碰到的杨辉三角应该都是用常规的二维数组存储&#xff0c;可…

git gui 历史版本_这些Git命令都不会,还是不要去面试了

前言以下&#xff0c;项目中经常使用的Git命令&#xff0c;汇总到这里以便与你能快速的学习和掌握Git命令&#xff0c;在文章最后有惊喜哟&#xff0c;一定要看到最后啊&#xff01;使用的 Git版本&#xff1a;git version 2.24.0命令git log# 输出概要日志,这条命令等同于# gi…

java restful_Java EE中的RESTful计时器

java restful在这篇文章中...。 EJB计时器旋风之旅 通过带有示例实现的简单REST接口即时使用EJB计时器 更新&#xff08;2015年7月14日&#xff09; 该应用程序的前端现在可以在OpenShift上使用 。 由于我是前端新手&#xff0c;因此我在其他来源的帮助下组装了此HTML5 Ang…

c# 联合halcon 基于相关性 模板匹配_机器视觉之halcon入门(5)-字符识别exe生成...

2.3.2 第二个halcon程序转EXE程序&#xff1a;字符识别老规矩&#xff0c;每一段halcon代码得用C#二次开发下。根据上一节所教的&#xff0c;我们配置下C#的环境&#xff0c;顺便添加好控件&#xff0c;如下图(2-3-2-1)。图 2-3-2-1控件基本跟上一节一样&#xff0c;只是少了一…

C语言数据的存储和取出(超详细讲解)

点击蓝字关注我们整形的储存我们知道一个整形的存储是以补码的形式储存取出是原码的形式。比如&#xff1a;int a 5;的二进制是101那它的原码应该是&#xff1a;00000000 00000000 00000000 00000101正数的原反补相同那它存进去和取出来都是&#xff1a;00000000 00000000 000…

打印pdf就一页_PDF 文件转换工具

是将 PDF 文件转换为完全可编辑的 Windows 文档最好的转换软件。无论您需要您的内容是 Microsoft Word、Excel、PowerPoint、HTML 还是仅需要文本&#xff0c; 总会给您一个简单的方法&#xff0c;快捷地获取您要的内容。可转换整个文档或选择内容。亦可创建 PDF 文件。PDF 转换…

C++类的this指针,静态成员,友元函数友元类

点击蓝字关注我们1. this指针在上篇讲C中类&#xff0c;对象&#xff0c;封装&#xff0c;继承&#xff08;派生&#xff09;&#xff0c;多态的时候&#xff0c;this指针出现在成员函数中&#xff0c;并使用->成员提取符操作成员变量。在 C 中&#xff0c;每一个对象都能通…

批量提取文件创建时间_批量采集新浪微博用户内容

有时我们需要把某些用户的微博数据全部采集下来用作分析&#xff0c;每条信息复制的工作量是非常低效的&#xff0c;必须要借助工具。今天给大家介绍一款采集软件&#xff1a;微风采集器。打开软件&#xff0c;选择模板&#xff0c;下拉框选&#xff1a;批量提取指定用户微博内…