解决方案:软件测试---------数据采集

优采云 发布时间: 2022-11-08 04:05

  解决方案:软件测试---------数据采集

  数据采集,又称数据采集,是使用设备从系统外部采集数据并输入系统的接口。您说的数据采集 工作现在可以由软件机器人完成。它可以模拟手动操作,自动化你需要的采集字段信息。最后整理出一张Excel表格或其他数据库表格。

  数据采集,很多都是在中间环节执行的,没有接口测试,方便验证数据的正确性。开发需要写一个demo(模拟前端接口发送请求的程序)进行测试。这个项目没有任何借口,开发包Test成jar(jar包是一些别人已经写好的类,然后打包这些类。你可以将这些jar包导入到你的项目中,然后就可以直接使用了这些jar包中的类、属性和方法..),所以测试这类项目需要一定的代码知识,才能测试并快速发现问题。

  测试前(每个项目都要先了解业务才能做好测试):

  ①了解需求文档的需求和注意点(业务的顺序,业务逻辑是否清晰,从而明确测试思路,也提高工作效率)。

  

  ②由于没有来自前端接口的支持,测试人员需要提前和开发人员沟通,让他们在沟通中更快的了解业务。在数据方面,开发总是比测试人员更彻底,业务数据比测试人员更彻底。清楚了,毕竟整个逻辑都是开发者实现的,所以沟通很重要。

  ③数据量大的项目,需要提前规划好时间。每个项目都有时间限制。管理较好的公司可以按计划行事。管理不善可能留给测试人员测试的时间不多,因为处理代码需要一点时间,所以这些都需要提前计划和监督。

  测试时(和一般项目一样,主要业务需要测试):

  ① 明确业务逻辑,准备数据。开发者在测试的时候一般都有数据,但是我们需要根据需求文档准备数据。其实这有点像接口数据测试,可以发现很多bug(比如对字段没有限制或者限制)。错误)。

  

  ②因为是处理数据,所以需要验证是否实现了数据的增删改查功能(在数据库中查询)。

  ③程序出错时,提示信息是否合理。

  ④很多验证需要基于具体的业务,了解业务是成功的一半。

  数据采集测试需要测试人员的呵护,还有很多需要学习的地方。你要知道,学无止境,你需要提高你的测试技能,你可以关注我。

  解决方案:使用 Rust 做异步数据采集的实践

  Data采集,最完整最成熟的生态工具,我觉得Python,尤其是强大成熟的Scrapy库,是很多项目和产品的必备。作者曾在大数据项目的数据采集部分与团队同事合作。不管项目中的愿景如何,笔者认为scrapy是完全满意的。

  本文是在Rust生态中使用data采集相关crate进行data采集的实践,目的如下:在新项目中统一Rust技术栈;我想试试 Rust 的性能优势,数据采集是否也有优势。

  所以,这篇文章更多是讲 Rust 的生态实践,并不是说 Rust 在做数据方面比 Python 有优势采集。

  好的,我们正在从头开始进行数据采集 完整练习,针对网站,采集 每周都使用 Rust。

  创建项目

  我们使用货物,创建一个新项目。在这个项目中,我们将使用 Rust 的异步运行时 async-std、HTTP 客户端库 reqwest、数据库 采集 库刮板和控制台输出文本颜色标记库 coloured。创建项目后,我们使用 cargo-edit crate 将它们添加为依赖项:

  cargo-edit的安装和使用请参考文章《构建Rust异步GraphQL服务:基于潮汐+async-graphql+mongodb(一)——入门与Crate选择》

  cargo new rust-async-crawl-example

cd ./rust-async-crawl-example

cargo add async-std reqwest scraper colored

  复制

  执行成功后,Cargo.toml文件manifest的dependencies区会有以上4个 crate。但是对于 async-std,在这个实践中,我们将使用它的属性特性;对于 reqwest,我们将启用其阻塞功能。我们修改 Cargo.toml 文件,最终内容如下:

  

[package]

name = "rust-crawl-week"

version = "0.1.0"

authors = ["zzy "]

edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

async-std = { version = "1.9.0", features = ["attributes"] }

reqwest = { version = "0.11.2", features = ["blocking"] }

scraper = "0.12.0"

colored = "2.0.0"

  复制

  简要设计

  数据采集,我们绝不能局限于一个站点。因此,我们参考Python中库scrapy的思路,每个具体爬虫对应一个站点。因此,我们将文件结构组织为 main.rs 是执行入口;sites.rs 或站点模块是具体的站点爬取位置。在此示例中,我们只是 采集 站点,因此将其写入 sites.rs 文件。在实际项目产品中,推荐使用sites模块,该模块收录以各自站点命名的特定爬虫。

  对于 采集 结果,我们想通过输出接口将其输入到控制台、数据库、文档(文本、excel等)。这些输出和写入接口也需要在一个统一的位置,以便后续扩展。

  在此示例中,我们将其打印到控制台。并且在打印时,为不同的站点、标题和 url 链接着色。

  因此,在这个实例中,最终的工程结构是:

  此时,我们还没有编译构建,所以没有 Cargo.lock 文件,也没有目标目录。如果按照本文的做法,它们会在 cargo build 之后生成。下面将不作进一步解释。

  main.rs

  data采集 入口文件,其代码应尽量简洁明了。

  mod sites;

#[async_std::main]

async fn main() {

// this-week-in-rust.org

match sites::this_week_in_rust_org().await {

Ok(site) => println!("{:#?}", site),

Err(_) => eprintln!("Error fetching this-week-in-rust.org data."),

}

// 其它站点

// ……

}

  

  复制

  对于多个站点,我们可以一个一个地增加,有利于后续的简单扩展。再说一遍:在这个例子中,我们只是 采集 站点,所以它被写在了 sites.rs 文件中。在实际项目产品中,推荐使用sites模块,该模块收录以各自站点命名的特定爬虫。

  注意:println!("{:#?}", site),输出到控制台时,我们采用了Rust中默认的最美观可读的输出方式。这段代码是带注释的,因为我们稍后将迭代第一次显示如何不够“符合人体工程学”。

  sites.rs第一次编码,采集数据并输出

  首先,我们需要定义两个结构体,分别代表站点信息和采集目标数据信息(本例中为标题、url链接)。

  #[derive(Debug)]

pub struct Site {

name: String,

stories: Vec,

}

#[derive(Debug)]

struct Story {

title: String,

link: Option,

}

  复制

  对于目标数据采集,我们的思路很简单,三步:

  获取 HTML 文档;提取数据标题;提取数据 url 链接。

  我们定义了这三个方法,在具体的站点爬虫this_week_in_rust_org中调用:

  use reqwest::{blocking, Error};

use scraper::{ElementRef, Html, Selector};

use std::result::Result;

pub async fn this_week_in_rust_org() -> Result {

let s = Selector::parse("div.col-md-12 a").unwrap();

let body = get_html("https://this-week-in-rust.org/blog/archives/index.html").await?;

let stories = body

.select(&s)

.map(|element| Story {

title: parse_title(element),

link: parse_link(element),

})

.collect();

let site = Site {

name: "this-week-in-rust.org".to_string(),

stories,

};

Ok(site)

}

async fn get_html(uri: &str) -> Result {

Ok(Html::parse_document(&blocking::get(uri)?.text()?))

}

fn parse_link(element: ElementRef) -> Option {

let mut link: Option = None;

if let Some(link_str) = element.value().attr("href") {

let link_str = link_str.to_owned();

link = Some(link_str);

}

link

<p>

}

fn parse_title(element: ElementRef) -> String {

element.inner_html()

}</p>

  复制

  这段代码可读性很强,代码是最好的文档。注意获取HTML文档的get_html函数和爬虫调用函数this_week_in_rust_org是异步的,而提取标题的函数parse_link和函数parse_title不是。因为具体的提取是在一个数据解析过程中进行的,所以作者认为是不是异步的意义不大。当然,如果你有兴趣,也可以改成一个异步函数来进行性能对比。

  第一次编码完成后,我们编译运行,看看一些输出结果:

  有许多安装依赖项。如果耗时较长,请配置 Cargo 国内镜像源。

  输出数据为json格式,文字无色差。非常适合其他输入调用接口。比如数据库和导出文件。但是对于人眼阅读来说,还不够友好。我们希望输出是标题及其链接。

  二次编码,优化输出数据格式

  在我们的第一个代码中,我们使用了 Rust 的默认 Display trait。我们要实现一个自定义的输出数据格式,也就是我们需要为 Site 和 Story 这两个结构实现一个自定义的 Display trait。

  use colored::Colorize;

use std::fmt;

impl fmt::Display for Site {

fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

writeln!(f, "{}", self.name.blue().bold())?;

for story in &self.stories {

writeln!(f, "{}", story)?;

}

Ok(())

}

}

impl fmt::Display for Story {

fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

match &self.link {

Some(link) => write!(f, "\t{}\n\t\t({})", self.title.green(), link),

None => write!(f, "\t{}", self.title),

}

}

}

  复制

  此时,我们main.rs中的打印甚至不需要指定Display方法:

  mod sites;

#[async_std::main]

async fn main() {

// this-week-in-rust.org

match sites::this_week_in_rust_org().await {

Ok(site) => println!("{}", site),

Err(_) => eprintln!("Error fetching this-week-in-rust.org data."),

}

// 其它站点

// ……

}

  复制

  现在让我们看看输出:

  对于人眼阅读,这种方式比较适合,直接点击url链接即可。

  感兴趣的朋友可以参考github上完整的代码仓库。

  谢谢阅读!

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线