复盘20211129

code 买入 卖出 收益 sz002056 横店东磁 20.64 20.23 -1.99 sh601515 东风股份 8.58 9.02 5.13 sz000546 金圆股份 14.87 15.97 7.4 sz002139 拓邦股份 21.0 20.77 -1.1 sz002063 远光软件 8.16 8.39 2.82 sz002176 江特电机 24.4 27.01 10.7 sz002326 永太科技 63.0 58.87 -6.56 sh600110 诺德股份 21.81 21.3 -2.34 sz000155 川能动力 29.53 29.21 -1.08 sz002191 劲嘉股份 16.42 15.5 -5.6 sh603906 龙蟠科技 48.15 46.79 -2.82 sh600418 江淮汽车 17.44 16.97 -2.69 sh600884 杉杉股份 38.15 38.42 0.71 sh601919 中远海控 16.05 17.48 8.91 sz002132 恒星科技 7.19 6.87 -4.45

November 29, 2021 · 1 min · 79 words

UI自动化图片相似度检测

在不同分辨率手机上校验图标是否存在的方法 Brute-Force匹配器基础 Brute-Force匹配器很简单,它取第一个集合里一个特征的描述子并用第二个集合里所有其他的特征和他通过一些距离计算进行匹配。最近的返回。 对于BF匹配器,首先我们得用cv2.BFMatcher()创建BF匹配器对象.它取两个可选参数,第一个是normType。它指定要使用的距离量度。默认是cv2.NORM_L2。对于SIFT,SURF很好。(还有cv2.NORM_L1)。对于二进制字符串的描述子,比如ORB,BRIEF,BRISK等,应该用cv2.NORM_HAMMING。使用Hamming距离度量,如果ORB使用VTA_K == 3或者4,应该用cv2.NORM_HAMMING2 第二个参数是布尔变量,crossCheck模式是false,如果它是true,匹配器返回那些和(i, j)匹配的,这样集合A里的第i个描述子和集合B里的第j个描述子最匹配。两个集合里的两个特征应该互相匹配,它提供了连续的结果, 当它创建以后,两个重要的方法是BFMatcher.match()和BFMatcher.knnMatch()。第一个返回最匹配的,第二个方法返回k个最匹配的,k由用户指定。当我们需要多个的时候很有用。 想我们用cv2.drawKeypoints()来画关键点一样,cv2.drawMatches()帮我们画匹配的结果,它把两个图像水平堆叠并且从第一个图像画线到第二个图像来显示匹配。还有一个cv2.drawMatchesKnn来画k个最匹配的。如果k=2,它会给每个关键点画两根匹配线。所以我们得传一个掩图,如果我们想选择性的画的话。 SIFT实现 加载图像 找到描述子 def sift(filename): img = cv2.imread(filename) # 读取文件 img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转化为灰度图 sift = cv2.SIFT_create() keyPoint, descriptor = sift.detectAndCompute(img, None) # 特征提取得到关键点以及对应的描述符(特征向量) return img, keyPoint, descriptor bf.match 接着我们用距离度量cv2.NORM_L2创建一个BFMatcher对象,crossCheck设为真。然后我们用Matcher.match()方法来获得两个图像里最匹配的。我们按他们距离升序排列,这样最匹配的(距离最小)在最前面。然后我们画出最开始的50个匹配 import cv2 from matplotlib import pyplot as plt def match(filename1, filename2): img1, kp1, des1 = sift(filename1) img2, kp2, des2 = sift(filename2) bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True) # sift的normType应该使用NORM_L2或者NORM_L1 matches = bf.match(des1, des2) matches = sorted(matches, key=lambda x: x.distance) len_before = len(matches) for m in matches: for n in matches: if(m != n and m.distance >= n.distance*0.75): matches.remove(m) break len_after = len(matches) img = cv2.drawMatches(img1, kp1, img2, kp2, matches[:20], img2, flags=2) plt.imshow(img), plt.show() val = round(len_after / len_before, 2) print(val) return val bf.knnMatch BFMatcher.knnMatch()方法会返回最佳匹配。而该方法为每个关键点返回 k 个最佳匹配(降序排列之后取前 k 个),其中 k 是由用户设定的,设置k=2这样我们可以应用比率检测 ...

November 25, 2020 · 3 min · 583 words

U2自动安装APK

import uiautomator2 as u2 import apkutils from loguru import logger class AndroidClient(object): d:u2 @classmethod def start(cls, udid): cls.d = u2.connect(udid) cls.d.healthcheck() cls.d.implicitly_wait(5) cls.d.set_fastinput_ime(True) return cls.d class Base(object): def __init__(self): self.d = AndroidClient.d class ApkInstall(Base): def watch_device(self, keyword): ''' 如果存在元素则自动点击 :param keyword: exp: keyword="yes|允许|好的|跳过" ''' for i in keyword.split("|"): self.d.watcher.when(i).click() self.d.watcher.start(1.0) time.sleep(2) def unwatch_device(self): '''关闭watcher ''' self.d.watcher.stop() time.sleep(2) def get_apk_info(self, path): '''从apk获取信息 ''' tmp = apkutils.APK(path).get_manifest() info = {} info['versionCode'] = str(tmp.get('@android:versionCode')) info['versionName'] = str(tmp.get('@android:versionName')) info['package'] = str(tmp.get('@package')) return info def local_install(self, apk_path): ''' 安装本地apk 覆盖安装,不需要usb链接 :param apk_path: apk文件本地路径 ''' pkg_name = self.get_apk_info(apk_path)['package'] file_name = os.path.basename(apk_path)[:12] + '.apk' logger.info('start install %s' % file_name) self.d.shell('rm -rf /sdcard/*.apk') self.d.shell('rm -rf /sdcard/apks/*.apk') self.d.shell(['/data/local/tmp/atx-agent', 'server', '-d']) if self.d.device_info['brand'] == 'vivo': '''Vivo 手机通过打开文件管理 安装app''' dst = '/sdcard/apks/' + file_name self.d.push(apk_path, dst) self.d.app_stop('com.android.packageinstaller') self.d.app_stop('com.android.filemanager') self.d.app_start('com.android.filemanager') time.sleep(4) if self.d(text="本地文件").exists(timeout=3): self.d(text="本地文件").click() if self.d(text="手机存储").exists(timeout=3): self.d(text="手机存储").click() time.sleep(1) # self.d(scrollable=True).scroll.toEnd() # time.sleep(1) for i in range(10): if self.d(textContains="apks").exists: self.d(textContains="apks").click() time.sleep(1) break else: # self.d(scrollable=True).scroll.vert.forward(steps=100) self.d.swipe_ext("up", scale=0.8) time.sleep(1) for i in range(40): if self.d(textContains=file_name).exists: self.d(textContains=file_name).click() time.sleep(5) break else: # self.d(scrollable=True).scroll.vert.forward(steps=100) self.d.swipe_ext("up", scale=0.8) print(i) time.sleep(1) # self.d(text=u"继续安装").click(timeout=15) if self.d(resourceId="android:id/button1").exists: self.d(resourceId="android:id/button1").click() else: self.d(resourceId="com.android.packageinstaller:id/continue_button").click() self.d(resourceId="com.android.packageinstaller:id/ok_button").click() time.sleep(8) elif self.d.device_info['brand'] == 'OPPO': dst = '/sdcard/apks/' + file_name self.d.push(apk_path, dst) self.d.app_stop('com.coloros.filemanager') self.d.app_start('com.coloros.filemanager') time.sleep(4) if self.d(text="手机存储").exists(timeout=3): self.d(text="手机存储").click() if self.d(text="所有文件").exists(timeout=3): self.d(text="所有文件").click() time.sleep(1) self.d(scrollable=True).scroll.to(textContains="apks") time.sleep(2) self.d(textContains="apks").click() time.sleep(2) # self.d(scrollable=True).scroll.to(textContains=file_name) # time.sleep(2) self.d(textContains=file_name).click() time.sleep(5) btn_done = self.d(className="android.widget.Button", text="完成") while not btn_done.exists: self.d(text="继续安装旧版本").click_exists() self.d(text="重新安装").click_exists() if self.d(resourceId="com.android.packageinstaller:id/install_confirm_panel").exists: # R11Plus if self.d(resourceId="com.android.packageinstaller:id/cancel_button").exists: self.d(resourceId="com.android.packageinstaller:id/bottom_button_layout") \ .click(offset=(0.5, 0.3)) # R9s elif self.d(resourceId="com.android.packageinstaller:id/bottom_button_layout").exists: self.d(resourceId="com.android.packageinstaller:id/bottom_button_layout") \ .click(offset=(0.75, 0.5)) # R17 elif not self.d(resourceId="com.android.packageinstaller:id/bottom_button_layout").exists: self.d(resourceId="com.android.packageinstaller:id/install_confirm_panel") \ .click(offset=(0.5, 0.95)) time.sleep(3) btn_done.click() else: dst = '/data/local/tmp/' + file_name self.d.push(apk_path, dst) self.watch_device('允许|继续安装|允许安装|始终允许|安装|重新安装') r = self.d.shell(['pm', 'install', '-r', dst], stream=True) id = r.text.strip() print(time.strftime('%H:%M:%S'), id) self.unwatch_device() packages = list(map(lambda p: p.split(':')[1], self.d.shell('pm list packages').output.splitlines())) if pkg_name in packages: self.d.shell(['rm', dst]) else: raise Exception('%s 安装失败' % apk_path) def install_apk(self): apk = 'xxx.apk' pkg_name = self.get_apk_info(apk)['package'] self.d.app_stop(pkg_name) self.d.app_uninstall(pkg_name) self.local_install(apk) self.d.app_start(pkg_name) time.sleep(2) # 授权 self.d.shell('pm grant {} android.permission.READ_PHONE_STATE'.format(pkg_name)) self.d.shell('pm grant {} android.permission.READ_EXTERNAL_STORAGE'.format(pkg_name)) self.d.shell('pm grant {} android.permission.ACCESS_COARSE_LOCATION'.format(pkg_name)) self.d.shell('pm grant {} android.permission.ACCESS_FINE_LOCATION'.format(pkg_name)) self.d.shell('pm grant {} android.permission.CAMERA'.format(pkg_name)) self.d.shell('pm grant {} android.permission.RECORD_AUDIO'.format(pkg_name)) self.d.shell('pm grant {} android.permission.WRITE_EXTERNAL_STORAGE'.format(pkg_name)) self.d.shell('pm grant {} android.permission.READ_CONTACTS'.format(pkg_name))

November 25, 2020 · 2 min · 338 words

本地 STF 内网穿透公网访问

有些事不能靠别人,更多的是靠自己 前提需要有一台公网服务器,ip在以下配置中称为 server_ip 1、local方式(适用本地部署stf,公网访问) 内网穿透配置,使用frp或其他内网穿透工具 frp下载地址 https://github.com/fatedier/frp/releases 服务端配置文件,启动./frps -c ./frps.ini # frps.ini [common] bind_port = 7000 authentication_method = token token = your_token allow_ports = 7400-7600,7100,7110 vhost_http_port = 7100 客户端配置文件,启动./frpc -c ./frpc.ini # frpc.ini [common] server_addr = server_ip server_port = 7000 token = your_token [stf_web] type = http local_port = 7100 custom_domains = server_ip_or_domain [range:stf] type = tcp local_ip = 127.0.0.1 local_port = 7400-7420 # 取决于设备数量,约2口/台 remote_port = 7400-7420 # 取决于设备数量 [stf_websocket] type = tcp local_ip = 127.0.0.1 local_port = 7110 remote_port = 7110 stf启动 本地启动 stf local --public-ip server_ip_or_domain --allow-remote 访问 server_ip_or_domain:7100

November 25, 2020 · 1 min · 92 words

Android 通过 VirtualXposed 进行 Charles https 抓包

Android7.0以上,无需root,即可抓包的方法 由于Android的机制,7.0以上不再信任用户证书,如Charles中的介绍 所以有3种方法可以解决这个问题: 最暴力的,root,把证书加入到系统证书 如果是自家APP,参考上面链接,在APP中设置信任用户证书 通过VirtualXposed+插件绕过证书检查(本文) 1、手机安装VirtualXposed 不多介绍,直接下载安装 地址:https://github.com/android-hacker/VirtualXposed/releases 2、VirtualXposed中安装 JustTrustMe 或 SSLUnpinning 用于绕过 SSL 证书检查 JustTrustMe:https://github.com/Fuzion24/JustTrustMe/releases TrustMeAlready:https://github.com/ViRb3/TrustMeAlready SSLUnpinning:https://github.com/ac-pm/SSLUnpinning_Xposed/blob/master/mobi.acpm.sslunpinning_latest.apk 在VirtualXposed中安装apk并启用模块 并在设置中,点击重启以使模块生效 3、VirtualXposed中安装目标apk 在VirtualXposed中安装目标apk,并配置好抓包工具,从VirtualXposed中启动APP开始抓包

November 25, 2020 · 1 min · 23 words

iOS 越狱后安装 ssl-kill-switch2 进行 https 抓包

今天使用charles开启了SSL抓包,发现有些APP抓不到,有的APP就可以,例如优X二手车,经过google发现抓不到包是因为app使用了SSL Pinning技术 查询发现,越狱的ios只要安装ssl-kill-switch2就可以抓到了 1、在Cydia中安装下面3个依赖 Debian Packager Cydia Substrate PreferenceLoader 2、下载ssl-kill-switch2.deb https://github.com/nabla-c0d3/ssl-kill-switch2/releases 3、Mac通过USB连接手机,安装ssl-kill-switch2.deb ios9 需要通过Cydia安装 openssh brew install libimobiledevice iproxy 2222 22 scp -P 2222 ~/Downloads/ssl-kill-switch2.deb [email protected]:~ #输入密码 默认 alpine ssh -p 2222 [email protected] dpkg -i <package>.deb killall -HUP SpringBoard 然后在设置中就会增加一个选项 SSL Kill Switch2,开启后,重启APP即可抓包

November 22, 2020 · 1 min · 43 words