Python+uiautomator2+夜神模拟器,实现安卓自动化操作的一些尝试

2023-10-31

前言

说一下这个配置的来源,最开始是想抓取某个应用里面的一些文本信息,自己的手机没root不好抓包,所以下载了安卓模拟器,然后安装抓包APP,直接抓,发现内容传输是加密的。那么在不去研究加密方法,最简单的方式,就是直接从屏幕控件中提取文本了,毕竟文本本身是明文显示在屏幕上的控件里的。

先说一下直接用adb操作安卓手机/安卓模拟器

在不知道uiautomator2之前,最初考虑的是直接用adb操作手机

方法如下:

  1. 进入安装位置 C:/Program Files (x86)/Nox/bin/
  2. 输入 nox_adb.exe connect 127.0.0.1:62001 即可以连接到adb
  3. adb devices查看是否连接成功
    这里用到是夜神模拟器,如果是手机,直接在有adb.exe的文件夹执行adb devices连手机就行了

adb指令

功能 代码
模拟输入001 adb shell input text “001”
模拟home按键 adb shell input keyevent 3
模拟点击 adb shell input tap 540 1104 # (540, 1104)坐标
模拟滑动 adb shell input swipe 250 250 300 300 # 从(250,250)滑动到(300,300)

然后就是考虑获取屏幕控件内容了

功能 代码
抓取界面 adb shell uiautomator dump /sdcard/ui.xml
导出到电脑 adb pull /sdcard/ui.xml ui.xml

效率比较低,而且导出的xml解析也需要花时间去弄

然后在查找资料的时候发现了uiautomator2

uiautomator2操作安卓手机/安卓模拟器

安装

# 安装 uiautomator2(安装总是超时,所以用了清华的源)
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple uiautomator2 -U uiautomator2
# 连接ADB调试,安装包含httprpc服务的apk到手机
python -m uiautomator2 init

然后开始写代码,这里写个抓取屏幕文字的例子,可以跑跑看看

import uiautomator2 as u2

# 连接手机
d = u2.connect() 
print(d.info)

def printAll():
    for i,v in enumerate(d.xpath('//*').all()):
        if v.text!='':
            print("【{0:0=4}】{1}".format(i,v.text))

def printTextviewAll():
	for i,v in enumerate(d.xpath('//android.widget.TextView').all()):
		print("【{0:0=4}】{1}".format(i,v.text))

printAll()
# printTextviewAll()

执行结果如下,会将屏幕上的文字逐一输出
在这里插入图片描述

uiautomator2在github上有 快速开始指南 推荐搭配web-editor快速抓取控件信息
还是很好懂的,抽出几分钟看一遍基本就可以写东西了,比如简单的

d.click(x,y)                      # 点击坐标
d.xpath(xp).click()               # 点击控件
d.xpath(xp).wait(timeout=3)       # 等待控件
d.press('back')                   # 按键/返回

至于xpath的写法,最常用的大概是这句了xp = "//*[re:match(@text, '^正则语句')]",用正则匹配查找对应文本的控件。

除了xpath还支持Uiselector的写法, 二者稍有不同, 以下是我对比测试两种写法的对比作为参考, 实际写的时候我还是用Uiselector比较多一些因为写起来整洁

UiSelector xpath 备注
d(text='立即开户')d(description='立即开户') d.xpath("立即开户") text或description等于立即开户的元素
d(textMatches='正则语句') d.xpath("//*[re:match(@text, '^正则语句')]") 正则
d(text='文本') d.xpath('//*[@text="文本"]') text
d(description='文本') d.xpath('//*[@content-desc="文本"]') description
d(resourceId='文本') d.xpath('//*[@resource-id="文本"]') resourceId
d(text='') d.xpath('//*[@text=""]').all() 如果存在多个, xpath需要通过all()返回列表,列表为空返回[]
d(text='').info d.xpath('//*[@text=""]').info 获取info
d(text='').bounds() d.xpath('//*[@text=""]').bounds 获取bounds

有了通过文本正则查找控件、获取文本、点击、返回等等,剩下的就是将这些动作组合循环,实现规律性抓取了,具体怎么写结合需要自行组合实现。

================

接下来说一下过程中遇到的问题:
在实际执行的时候,每跑几个小时,adb就会崩一次,“adb.exe 已停止工作”:
在这里插入图片描述
试了nox_adb.exe和adb.exe都不行(对比了一下夜神自带的这两个adb的sha1校验码,发现一模一样,说明这两个adb文件只是名字不同而已没什么区别)。
又从网上下载几个adb还会崩,于是开始写崩了自动重连的方法。

Windows弹出的这个崩溃弹窗,会导致程序阻塞,不往下进行,于是将注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting 分支下的DontShowUIDisabled选项都改成1,避免崩溃弹窗阻塞程序。

没有弹窗干扰,接下来就是写重连了

# 临时写的,凑活用,大概意思就是先把运行的adb都杀掉,然后重连
for i in range(3):
      os.system("taskkill /F /IM adb.exe")
      time.sleep(2)
      os.system("taskkill /F /IM nox_adb.exe")
      time.sleep(2)
while True:
    try:
        subprocess.call("nox_adb.exe connect 127.0.0.1:62001")
        d = u2.connect() # connect to device
        print(d.info)
        break
    except:
        print("[Maybe] Can't find any android device/emulator")
        time.sleep(10)

到目前为止,程序连续跑了两三天,还算稳定。

觉得这个东西还蛮好用,于是用这个它写了几个APP签到,放到NAS上每天定时执行去了。


回头想想,这两三年间,还用过一些其他的自动化手段。

Chrome浏览器,直接F12,Console输入一些纯js脚本实现的自动化:

点击:document.querySelector('#vreplysubmit').click();
文本:vf_tips = '我来说说爱看的书';$('vmessage').value = vf_tips;
随机数:Math.random()*5000
定时循环:setInterval(function(){//循环代码}, //毫秒)
计次停止:var timesRun = 0;var interval = setInterval(function(){timesRun += 1;if(timesRun === 60){clearInterval(interval);}//循环代码}, //毫秒);

简单组装一下,就能变成自动发贴机;

var timesMax = 70;
vf_tips = '每日灌水今天也要灌满50贴';
var timesRun = 0;
var interval = setInterval(function(){timesRun += 1;
if(timesRun === timesMax){clearInterval(interval);}
$('vmessage').value = vf_tips+' '+Math.floor(Math.random()*100);
document.querySelector('#vreplysubmit').click();
}, Math.random()*500+5000);

或者像是网页端自动抽奖,连续点击;

var timesRun = 0;var interval = setInterval(function(){timesRun += 1;if(timesRun === 120){ clearInterval(interval);}hidepop();lottery();},Math.random()*500+7000);

另外工作需要的时候,也可以用js实现一些,网页端功能测试循环点击之类的。

Selenium+Chromedriver的网页自动化:

其实严格来说Selenium+很多浏览器都可以,个人偏好Chrome,需要下载chromedriver.exe搭配使用。还需要注意文件支持的Chrome的版本,不过这一两年貌似我的Chrome更新过很多次,chromedriver一直都还没换过,大概是不那么强调对应关系了。

(就在写完这个文档草稿之后两天,居然又用到了一次这个方法。
在抓取某个站点的时候发现,该站点网页源代码的里的标签内容居然是加密的,展示的时候通过js方法解密显示成正常文字。
貌似是源自google的方法,居然还有这种网页源代码加密,大概了解到是通过js实现的后,首先想到的方法是Python+PyExecJS模块。
然后就想到用Selenium+Chromedriver试试看,发现也能绕过加密,直接获取网页上实际各框架标签内解密后的实际展示的文本)

Selenium这个东西不知道有多少人用过,想看安装使用的,可以搜一下网上教程如何安装使用。大概两年前我拿这个东西写过一些论坛自动签到的东西,现在挂在NAS上,每天跑的依旧很正常。
这里大致贴几条当初研究selenium时记录,就能看出这个东西能干什么。(从变量命名来看,不像是自己写的,可能是之前网上的代码自己加了注释,这里贴出来做个参考)

from selenium import webdriver   # pip install selenium
from PIL import Image,ImageGrab     # pip install pillow
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
import json,os,time,random

def initWork(chromedriverpath = "chromedriver.exe"):
    # 初始化配置根据自己chromedriver位置做相应的修改
    os.environ["webdriver.chrome.driver"] = chromedriverpath
    driver = webdriver.Chrome(chromedriverpath)
    return driver

def closeWork(driver):
    driver.close()
    driver.quit()

def SimpleLogin(driver,un,pw,url,unxp,pwxp,lgbutnxp):
    driver.set_window_size(480, 800)                                # 设置窗口大小
    driver.get(url)                                                 # 打开执行操作的页面地址
    time.sleep(2)                                                   # 休眠两秒钟后执行填写用户名和密码操作
    elem = driver.find_element_by_xpath(unxp)
    elem.send_keys(un)                                              # 输入用户名
    elem = driver.find_element_by_xpath(pwxp)
    elem.send_keys(pw)                                              # 输入密码
    elem = driver.find_element_by_xpath(lgbutnxp)                   # 根据xpath获取登录按钮
    elem.send_keys(Keys.ENTER)                                      # 发送确认按钮
    driver_cookie = driver.get_cookies()                            # 获得cookie信息
    cookies = {c['name']:c['value'] for c in driver_cookie}         # 整理成requests使用的dict形式
    return cookies

def screenshot(driver,path='screenshot.png',position=(0,0,0,0)):  # 截图(还可以剪切局部)
    driver.save_screenshot(path)
    if position[2]!=0:
        im = Image.open(path) 
        im = im.crop(position)
        im.save(path)

def elem_get_position(driver,elem): # 返回元素的左上右下四周边界位置
    left = elem.location['x']
    top = elem.location['y']
    right = elem.location['x'] + elem.size['width']
    bottom = elem.location['y'] + elem.size['height']
    return (left,top,right,bottom)

def elem_drag(driver,elem,x,y,iter,rdm=False): # 拖拽元素,按指定方向,迭代指定次数
    action = ActionChains(driver)
    action.click_and_hold(elem).perform()  #鼠标左键按下不放
    for index in range(iter):
        r = 2*random.random() if rdm else 1
        try:
            action.move_by_offset(x*r,y*r).perform() #平行移动鼠标
        except UnexpectedAlertPresentException:
            break
        action.reset_actions()
        time.sleep(0.1*r)  #等待停顿时间
    action.click_and_hold(elem).release().perform()

对网页元素的控制,点击、填写、拖动、滚动都可以实现。
如果结合pillow和tesseract还可以做一些,过验证码识别滑动等操作。不过现在的各种验证还在不断的推陈出新,定向去破解这些验证除非有必要,不然还是比较花时间和精力,来训练提高精准度的。
至于导入导出Cookies,搭配python的requests库可做的东西就更多了。

安卓手机,使用安卓软件直接实现的自动化:

手机是日常使用最多,所以也会有一些自动化的个人需求。公司的一些项目,也有用到一些安卓端的自动化。
这里说一下我个人用的在安卓端本身实现的自动化,

如果只是简单的频繁点击,那么有一款APP叫做 自动点击器 的,基本就能满足你的大部分需求,使用起来非常简单。只要将你要点击的所有点位置、顺序、间隔时间、循环次数设定好,执行自动连续点击就行了。适合一些单调的循环点击操作。

如果你想实现一些更多复杂的一些方式,而且还是在安卓端本身,那么可以考虑Auto.js。编写js脚本,使用Auto.js安卓APP应用执行。
编写可以在SublimeText3或VisualStudioCode安装一个插件,搭建控制台,连接手机编写和调试代码。

曾经用过这个应用写过很多APP的自动化签到,但是后续发现维护也需要消耗很多时间,就不再弄了。
为了最后能判断问题出在哪一步,可以将常用的操作,包装成附带日志打印的函数,方便出问题的直接看执行到了哪一步,每一步都执行了什么,贴一些之前写过功能模块。


function 按住(x, y, seconds) {
    // 按住(x,y),按住时长默认2秒
    if (!seconds) { seconds = 2000 }
    press(x, y, seconds);
    console.verbose('按住: (' + x.toString() + ',' + y.toString() + ')' + seconds.toString() + '秒');

}


function 滑动(x1, y1, x2, y2, seconds) {
    // 滑动(x1,y1)滑动到(x2,y2),滑动完成时长默认0.5秒
    if (!seconds) { seconds = 500 }
    gesture(seconds, [x1, y1], [x2, y2]);
    console.verbose('滑动: ' + seconds.toString() + '秒内由(' + x1.toString() + ',' + y1.toString() + ')滑动到(' + x2.toString() + ',' + y2.toString() + ')');
}

更复杂的可以写一些,通过控件的点击操作、找字等待点击、通过大小查找控件、正则匹配查找控件、模拟随机化滑动等等。


function 控件点击(obj, moveX, moveY) {
    // 输入控件,实现点击
    // 可点控件,直接调用系统方法,实现点击
    // 不可点控件,如果在屏幕范围内,模拟屏幕点击操作,实现点击
    // 不可点控件,实现点击时,可以附加偏移量。moveX为负正整数,表示点击控件中心位置偏左右N个像素点,同理moveY表示上下
    if (!moveX) { moveX = 0; }
    if (!moveY) { moveY = 0; }
    if (typeof (obj) != 'object') {
        console.verbose('控件点击: 输入内容非控件类型:', typeof (obj), '具体内容', obj);
        exit();
    }
    else if (obj.length > 1) {
        console.verbose('控件点击: 输入控件不唯一:', obj.length, '具体内容', obj);
        exit();
    }
    else {
        //直接控件点击
        if (obj.clickable() && moveX == 0 && moveY == 0) {
            console.verbose('控件点击: 直接控件');
            obj.click();
        }
        //模拟屏幕坐标点击
        else {
            //控件在屏幕显示范围内
            var b = obj.bounds();
            if (b.left >= 0 && b.top >= 0 && b.right <= device.width && b.bottom <= device.height) {
                var x = b.centerX() + moveX;
                var y = b.centerY() + moveY;
                console.verbose('控件点击: 模拟点屏(' + x.toString() + ',' + y.toString() + ')');
                click(x, y);
            }
            else {
                console.verbose('控件点击: 控件不在屏幕范围,无法点击:', b);
                exit();
            }
        }
    }
}


function 读取文本(obj) {
    // 输入控件,获取desc或text文本内容
    // obj:输入控件
    // if (!para) { para = ''; }
    var text = obj.text();
    var desc = obj.desc();
    var wenben = '';
    if (desc == null) { desc = ''; }
    if (text == null) { text = ''; }
    wenben = desc + text;
    return wenben;
}


function 找控件大小D(width, height, w_dif, h_dif, returntype) { //Matches
    // 找指定大小控件,支持像素误差范围
    if (!w_dif) { w_dif = 0; }
    if (!h_dif) { h_dif = 0; }
    var arr_find = [];
    var t = '';
    t = enabled(true).find(); sleep(100);
    t.forEach(function (e) {
        var w = e.bounds().right - e.bounds().left;
        var h = e.bounds().bottom - e.bounds().top;
        if (Math.abs(w - width) <= w_dif && Math.abs(h - height) <= h_dif) {
            arr_find.push(e);
        }
    });
    console.verbose('找控件大小D: 找到', arr_find.length, '个');
    // 打印所有arr_find
    // arr_find.forEach(function (e) {
    //     console.log('wz:', BoundsToWHM(e.bounds()), 'desc:', e.desc(), 'text:', e.text(), 'id:', e.id());
    // });
    // 返回结果
    if (!returntype) {
        if (arr_find.length < 1) { return ''; }
        else if (arr_find.length == 1) { return arr_find[0]; }
        else { return arr_find; }
    }
    else if (returntype == 'list') {
        if (arr_find.length < 1) { return []; }
        else { return arr_find; }
    }
    else {
        console.log('找控件大小D:', 'returntype输入值错误');
        exit();
    }
}


function 找字M(str, returntype) { //Matches
    //以descMatches和textMatches方式找字,可定义返回方式
    var arr_find = [];
    var t = '';
    t = descMatches(str).find(); sleep(100); t.forEach(function (e) { arr_find.push(e); });
    t = textMatches(str).find(); sleep(100); t.forEach(function (e) { arr_find.push(e); });
    console.verbose('找字:', str, '找到', arr_find.length, '个(正则)');
    // 打印所有arr_find
    // arr_find.forEach(function (e) {
    //     console.log('wz:', BoundsToWHM(e.bounds()), 'desc:', e.desc(), 'text:', e.text(), 'id:', e.id());
    // });
    // 返回结果
    if (!returntype) {
        if (arr_find.length < 1) { return ''; }
        else if (arr_find.length == 1) { return arr_find[0]; }
        else { return arr_find; }
    }
    else if (returntype == 'list') {
        if (arr_find.length < 1) { return []; }
        else { return arr_find; }
    }
    else {
        console.log('找字M:', 'returntype输入值错误');
        exit();
    }
}

function 滑动R(x1, y1, x2, y2) { //添加正负轻微随机数(所以注意四个点的范围不要距离上下所有边界太近)
    // 默认构建一个随机滑动,从中下,向右上滑动
    if (!x1) { x1 = 500; }
    if (!y1) { y1 = 1350; }
    if (!x2) { x2 = 700; }
    if (!y2) { y2 = 450; }
    // 构建随机位置
    x1 = x1 + 100 - getRndInteger(0, 280);
    y1 = y1 + 100 - getRndInteger(0, 280);
    x2 = x2 + 100 - getRndInteger(0, 280);
    y2 = y2 + 100 - getRndInteger(0, 280);
    w = getRndInteger(300, 500); // 随机滑动时间
    // 滑动
    滑动(x1, y1, x2, y2, w);
}

关于自动化

其实各种编程语言或多或少都有一些实现日常自动化的方法,比如微信跳一跳比较流行的时候,同事是做安卓开发的,就写了一个跳一跳脚本,当时也忘了问他是怎么实现的,大概是通过ADB。

另外这两天还看了一些Uipath,刚上手这个搭模块的感觉,一下子觉得回到了大学模电的时候的LabVIEW,但是这个东西更多的是搭逻辑,再加上输入输出和变量,封装好了一些模块化的东西给你用。如果你有相对稳定的重复的动作,这个东西可以减轻你的工作量。我一开始以为是给完全不懂编程的人用的,结果发现变量和一些语法的实现,还是要写一些VB代码。

这个东西我测试Chrome网页自动化的时候,发现找字点击会异常报错。网上也有其他人说,同样的代码IE正常,Chrome就报错。官网论坛提问了一下,很快有人答复,但是并没有解决。我自己研究了一下,通过 Click set Selector ""的方式实现了网页找字点击,间接解决了问题,写在了提问底下,相当于自问自答了。现在一周过去了,除了第一个回复我的,也没有收到其他答复。答复我的人头衔为Robot Master,意思是Users who completed the Advanced training in Academy,大概是完成了官方三种教程任一的人,成员组才只有一千多人。官网有免费在线网课,,国内也有论坛提供了一些翻译好的教程。

当我以为这个东西只是个不成熟的产品的时候,发现Uipath这个东西,确实也有一些大公司在用,所以也不太好给这个软件下结论,大概只有真正用这个软件实际开发人,才知道这个软件可以胜任什么工作。和我聊起这个的人是财务人员,整个部门还都在培训期。不过大致可以猜测一下,自动化软件做的,应该也就是跨应用文档,将一些手工的操作,变为自动化实现。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python+uiautomator2+夜神模拟器,实现安卓自动化操作的一些尝试 的相关文章

  • 将 JSON 发布到 Python CGI

    我已经安装了 Apache2 并且 Python 可以工作 但我有一个问题 我有两页 一个是 Python 页面 另一个是带有 JQuery 的 Html 页面 有人可以告诉我如何让我的 ajax 帖子正常工作吗
  • 如何在 Debian 上的 virtualenv 中安装 numpy?

    注 参见这另一篇文章 https stackoverflow com questions 6442754 how to install h5py numpylibhdf5 as non root on a debian linux syst
  • 通过 python 中的另外两个修改数组[重复]

    这个问题在这里已经有答案了 假设我们有三个一维数组 A 长度为 5 B 长度相同 示例中为5 C 更长 比如长度为 100 C最初用零填充 A给出索引C应更改的元素 它们可能会重复 以及B给出应添加到初始零的值C 例如 如果A 1 3 3
  • 将 Python Pandas DataFrame 写入 Word 文档

    我正在努力创建一个使用 Pandas DataFrames 的 Python 生成的报告 目前我正在使用DataFrame to string 方法 但是 这会作为字符串写入文件 有没有办法让我实现这一目标 同时将其保留为表格 以便我可以使
  • 使用pathlib获取主目录

    翻看新的pathlib在 Python 3 4 中 我注意到没有任何简单的方法来获取用户的主目录 我能想到的获取用户主目录的唯一方法是使用旧的os path像这样的库 import pathlib from os import path p
  • 为什么 re.findall 在查找字符串中的三元组项时不具体。 Python

    所以我有四行代码 seq ATGGAAGTTGGATGAAAGTGGAGGTAAAGAGAAGACGTTTGA OR 0 re findall r ATG 9 TAA TAG TGA seq 首先让我解释一下我正在尝试做什么 如果这令人困惑
  • 使用 subprocess.Popen() 或 subprocess.check_call() 时程序卡住

    我想从 python 运行一个程序并找到它的内存使用情况 为此 我正在使用 l a out lt in txt gt out txt p subprocess Popen l shell False stdout subprocess PI
  • Python 属性和 Swig

    我正在尝试使用 swig 为一些 C 代码创建 python 绑定 我似乎遇到了一个问题 试图从我拥有的一些访问器函数创建 python 属性 方法如下 class Player public void entity Entity enti
  • Python:在字典中查找具有唯一值的键?

    我收到一个字典作为输入 并且想要返回一个键列表 其中字典值在该字典的范围内是唯一的 我将用一个例子来澄清 假设我的输入是字典 a 构造如下 a dict a cat 1 a fish 1 a dog 2 lt unique a bat 3
  • Django 2、python 3.4 无法解码 urlsafe_base64_decode(uidb64)

    我正在尝试通过电子邮件激活用户 电子邮件有效 编码有效 我使用了 django1 11 中的方法 该方法运行成功 在 Django 1 11 中 以下内容成功解码为 28 其中 uidb64 b Mjg force text urlsafe
  • 如何按 pandas 中的值对系列进行分组?

    我现在有一只熊猫Series与数据类型Timestamp 我想按日期对其进行分组 并且每组中有许多行具有不同的时间 看似显而易见的方法类似于 grouped s groupby lambda x x date 然而 熊猫的groupby按索
  • 无法导入QUERY_TERMS

    我正在运行一个网站Python and Django Django filters 2 1 installed Django 2 1 installed 当我运行时 我收到以下错误 importError Could not import
  • Python 2.7 缩进错误[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 这个问题是由拼写错误或无法再重现的问题引起的 虽然类似的问题可能是on topic help on topic在这里 这个问题的解决方式不
  • 如何展平解析树并存储在字符串中以进行进一步的字符串操作 python nltk

    我正在尝试从树结构中获取扁平树 如下所示 我想将整个树放在一个字符串中 就像没有检测到坏树错误一样 S NP SBJ NP DT The JJ high JJ seven day PP IN of NP DT the CD 400 NNS
  • Python:如何在不先创建整个列表的情况下计算列表的总和?

    通常我们必须 1 声明一个列表 2 使用以下方法计算该列表的总和sum 但现在我希望指定一个以 1 开头 间隔为 4 100 个元素的列表 如下所示 1 5 9 13 17 21 25 29 33 37 我不想涉及数学公式 所以 1 如何在
  • 没有名为“turtle”的模块

    我正在学习并尝试用Python3制作贪吃蛇游戏 我正在进口海龟 我正在使用 Linux mint 19 PyCharm python37 python3 tk Traceback most recent call last File hom
  • 使用 pandas 单元格中列表的长度选择行[重复]

    这个问题在这里已经有答案了 我有一张表 df a b c 1 x y x 2 x z c d 3 x t e f g 只是想知道如何使用 c 列的长度选择行 such as df loc len df c gt 1 我知道这是不对的 正确的
  • 如何同时接受int和float类型的输入?

    我正在制作一个货币转换器 如何让 python 同时接受整数和浮点数 我就是这样做的 def aud brl amount From to ER 0 42108 if amount int if From strip aud and to
  • 在Python中停止ThreadPool中的进程

    我一直在尝试为控制某些硬件的库编写一个交互式包装器 用于 ipython 有些调用对 IO 的影响很大 因此并行执行任务是有意义的 使用 ThreadPool 几乎 效果很好 from multiprocessing pool import
  • Biopython 可以执行 Seq.find() 来解释歧义代码吗

    我希望能够在 Seq 对象中搜索考虑歧义代码的子序列 Seq 对象 例如 以下内容应该是正确的 from Bio Seq import Seq from Bio Alphabet IUPAC import IUPACAmbiguousDNA

随机推荐

  • C#中GDI绘制高质量平滑图形实例

    protected override void OnPaint PaintEventArgs e try Graphics g e Graphics 获取绘制对象 设置参数 g SmoothingMode System Drawing Dr
  • k8s部署nginx实例、iptables开放端口

    1 运行nginx实例 kubectl run nginx image nginx replicas 2 port 80 2 查看pod root localhost kubectl get pods NAME READY STATUS R
  • 【计算机毕业选题】2023~2024计算机毕业设计选题篇-选题推荐

    学弟学妹们 大家好 这里是JAVA编码选手的博客空间 一年一度的计算机专业毕业设计又要开始了 大四的你们准备好选题了吗 先介绍一下自己 本人软件工程毕业 5年软件开发经验 计算机程序设计 java程序 Java代做 微服务SSM Java管
  • linux删除大量文件时,报错  argument list too long 

    linux删除大量文件时 报错 argument list too long 原因 删除数据量太大 解决办法 1 删除某个文件夹下 所有文件 cd 到需要删除的文件夹内 删除所有文件 ls xargs rm r 执行完后 可能有些文件删除不
  • COMP 9417 T2_2021 Lesson 8

    贝叶斯 numeric attributes 决策树 优点 某种形式的树可能仍然是最流行的data mining 易于理解 易于实施 易于使用 可以分类可以回归 可用于大数据的处理 例子 例子 在N中需要多少个M来分类 N个特征 thres
  • MeshLab相关&纹理贴图

    安装MeshLab sudo apt get install meshlab 操作 旋转视图 鼠标左键 拖动 缩放视图 滑动鼠标滚轮 shift 左键 平移视图 鼠标滚轮按钮 拖动 指定旋转 轨迹球中心 鼠标左键双击模型特定点 改变界面左下
  • python爬虫什么意思-终于知道python爬虫是什么意思

    爬虫过程中也会经历一些绝望啊 比如被网站封IP 比如各种奇怪的验证码 userAgent访问限制 各种动态加载等等 下面是小编为您整理的关于python爬虫是什么意思 希望对你有所帮助 python爬虫是什么意思 python爬虫即网络爬虫
  • ndarray对象——创建

    首先需要创建数组才能对其进行运算和操作 可以通过arrray 函数传递Python的序列对象来创建数组 如果传递的是多层嵌套的序列 将创建多维数组 下例变量中的c import numpy as np a np array 1 2 3 4
  • 信用卡评分模型(R语言)

    信用卡评分 2016年1月10日 一 数据准备 1 问题的准备 目标 要完成一个评分卡 通过预测某人在未来两年内将会经历财务危机的可能性来提高信用评分的效果 帮助贷款人做出最好的决策 背景 银行在市场经济中起到至关重要的作用 他们决定谁在什
  • 1.业务架构·应用架构·数据架构实战 --- 架构实践全景图

    第1章 架构实践全景图 1 1 战略 BA DA AA TA五者的关系 业务架构是跨系统的业务架构蓝图 应用架构 数据架构 技术架构是解决方案的不同方面 BA Business Architecture 业务架构 DA Data Archi
  • 计算机网络-应用层协议3(SMTP、POP3、IMAP)

    1 SMTP 简单邮件传输协议 1 1 SMTP的基本操作 假设Alice想给Bob发送一封简单的ASCII报文 Alice调用她的邮件代理程序并提供Bob的邮件地址 bob someschool edu 撰写报文 然后指示用户代理发送该报
  • 【2022版】Golang面试题目全网超全超详细的口语化解答总结

    2022版 Golang面试题目全网超全总结 1 特性篇 1 1 Golang 使用什么数据类型 1 2 字符串的小问题 1 3 数组定义问题 1 4 内存四区 1 5 Go 支持什么形式的类型转换 1 6 空结构体的作用 1 7 单引号
  • 完全理解图(上)——图的概念、存储及遍历

    术语 图 由结点的有穷集合V和边的集合E组成 在图中 结点常被称为顶点 若两个顶点之间存在一条边 则表示两个顶点相邻 有向图 图的每条边都有方向 无向图 图的每条边没有方向 弧 有向图中 常将边称为弧 含箭头的一端称为弧头 另一端称为弧尾
  • spark机器学习训练模型示例(一)

    利用逻辑回归建立模型 建立训练集和测试集 from pyspark ml import Pipeline from pyspark ml classification import LogisticRegression from pyspa
  • 并发编程系列之线程池工厂类:Executors

    前言 上节讲了讲自定义线程池 今天我们来聊聊线程池框架 在实际开发中我们还是基本使用线程框架Executor给我们提供的一些工具类 Java提供的Executor都在JUC java util concurrent 包下面 主要包括 线程池
  • ChatGPT 与 Github Copilot 对于程序员的作用

    文章目录 1 ChatGPT 是什么 2 ChatGPT 的用处 ChatGPT 写代码 ChatGPT 定位问题 ChatGPT 厘清概念 ChatGPT 内容创作 3 Github Copilot 的用处 4 小结 参考文献 1 Cha
  • Qt Creater Bug: multiple define of ...

    在导入自己写的文件到Qt 工程时 发现报了好多个 multiple define of 的错误 网上查了以下 解决方法有提到 头文件重复包含 ifndef define endif 编译出来的 o文件链接失败 需要clean工程的生成文件
  • jvm原理(37)JVM内存空间划分与作用详解

    JVM内存区域分了如下几个区域 虚拟机栈 Stack Frame 在执行一个方法的时候 会有一个栈帧 用来存储 方法里边的操作数的出栈入栈 当java文件编译完成的时候 max stack 栈最大的深度 max local 最大局部变量表有
  • python定义函数prime判断是否是素数_用自定义函数判断素数 用C语言编写自定义函数prime(int x),判断x是否为素数?...

    用C语言编写自定义函数prime int x 判断x是否为素数 int prime int x int i k k int sqrt double x for i 2i lt ki if x i 0 break 如果完成所有循环 那么x为素
  • Python+uiautomator2+夜神模拟器,实现安卓自动化操作的一些尝试

    前言 说一下这个配置的来源 最开始是想抓取某个应用里面的一些文本信息 自己的手机没root不好抓包 所以下载了安卓模拟器 然后安装抓包APP 直接抓 发现内容传输是加密的 那么在不去研究加密方法 最简单的方式 就是直接从屏幕控件中提取文本了