機(jī)器學(xué)習(xí)在移動端的使用烦绳,Tensorflow + BroadCast Extension(iOS原生錄屏插件) 移動端爬蟲解決方案

前言

傳統(tǒng)的移動端爬蟲一般是基于webView,通過注入JS的方式配紫,獲取登錄后的cookie讓服務(wù)端使用無頭瀏覽器模擬登錄狀態(tài)爬取數(shù)據(jù)径密。

這種方式簡單有效,但是對于有做反爬(IP限制笨蚁,是否模擬器睹晒,是否處于異常環(huán)境)的網(wǎng)站趟庄,爬取難度大,甚至無法爬取伪很。

業(yè)務(wù)驅(qū)動技術(shù)戚啥,在移動端爬蟲的演進(jìn)過程中經(jīng)歷了四個階段

  • cookie爬取(早期網(wǎng)站都沒有反爬的機(jī)制)
  • cookie + 本地爬蕊笔浴(部分網(wǎng)站出現(xiàn)反爬猫十,無法通過服務(wù)端爬取,則本地獲取HTML解析)
  • cookie + 本地爬取 + 截圖認(rèn)證(針對反爬嚴(yán)重呆盖,無法通過webView登錄采集的業(yè)務(wù)采用跳轉(zhuǎn)APP拖云,截圖OCR的方式爬取)
  • Tensorflow + BroadCast Extension(通過錄屏獲取實(shí)時界面內(nèi)容应又,Tensorflow做圖像識別獲取關(guān)鍵頁面內(nèi)容宙项,無視反爬機(jī)制)

什么是BroadCast Upload Extension?

BroadCast Upload Extension在iOS10的時候推出,當(dāng)時只能in-APP BroadCast株扛,即錄制當(dāng)前APP尤筐。

在WWDC2018中,蘋果發(fā)布的ReplayKit2中升級了這個擴(kuò)展洞就,做到了iOS System BroadCast,即錄制iOS系統(tǒng)界面盆繁,不限制與某個APP,但此時需要從控制中心喚起錄屏旬蟋,任然有些麻煩油昂。

image-20191118182045340.png

在iOS12中,iOS又推出了RPSystemBroadcastPickerView類倾贰,可以在APP內(nèi)通過按鈕喚起控制中心的錄屏選擇界面冕碟。

image-20191118182105865.png

客戶端流程:

image-20191118165847233.png

架構(gòu):

image-20191118151036879.png
  • 錄屏插件:iOS原生錄屏插件,獲取最新的錄屏幀匆浙,傳遞給中間件鸣哀。
  • 中間件:保存插件傳遞的最新一幀內(nèi)容,負(fù)責(zé)對幀對象的處理吞彤,消息的發(fā)送(心跳請求,幀請求)叹放。
  • APP端:負(fù)責(zé)對收到的圖片對象進(jìn)行classify饰恕,根據(jù)結(jié)果進(jìn)行步驟匹配(是否需要服務(wù)端OCR,下一個關(guān)鍵頁面是什么)井仰。

? 插件端不停的將最新視頻幀給到中間件埋嵌,中間件在上一次post請求完畢后獲取最新的一幀轉(zhuǎn)換成圖片對象并發(fā)送,配置文件中設(shè)置字段控制上一次post請求完畢到下一次圖片轉(zhuǎn)換之間的dealy時間俱恶。

? 將幀處理成圖片后做一次圖片壓縮(TensorFlow對圖片進(jìn)行檢測前也會做一次壓縮雹嗦,這里提前做掉)范舀,保證post請求的大小和速度。

? 為了盡量低的內(nèi)存占用(錄屏插件最大可使用的內(nèi)存50MB了罪,超過就會崩)锭环,控制圖片轉(zhuǎn)換的頻率,壓縮圖片請求泊藕,將圖片轉(zhuǎn)換放到autoreleasepool中辅辩。

錄屏插件端

錄屏插件使用的是iOS系統(tǒng)自帶的BroadCast Upload Extension,可以在project - target + Application Extension中添加娃圆。

image-20191118173254281.png

添加后項(xiàng)目中會多一個BroadCast的target玫锋,自帶一個SampleHandler類,用于接收系統(tǒng)錄屏插件的回調(diào)讼呢。

#import "SampleHandler.h"

@interface SampleHandler()
@end

@implementation SampleHandler

//開始錄屏
- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
    NSLog(@"APP錄屏開始");
}

//錄屏中切換APP iOS > 11.2
- (void)broadcastAnnotatedWithApplicationInfo:(NSDictionary *)applicationInfo {
    NSLog(@"錄屏中切換APP");
}

//錄屏結(jié)束
- (void)broadcastFinished {
    NSLog(@"APP錄屏結(jié)束");
}

//獲取錄屏幀信息
- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
    switch (sampleBufferType) {
        case RPSampleBufferTypeVideo://錄屏圖像信息回調(diào)
            //在這里將獲取到的圖像信息傳遞給中間類處理
            break;
            
        case RPSampleBufferTypeAudioApp://錄屏音頻信息回調(diào)
            // Handle audio sample buffer for app audio
            break;
        case RPSampleBufferTypeAudioMic://錄屏聲音輸入信息回調(diào)
            // Handle audio sample buffer for mic audio
            break;
            
        default:
            break;
    }
}

@end

這一塊做的事非常少撩鹿,只是單純的將獲取到的視頻幀信息傳遞給中間類,刷新中間類保存的最后一幀信息悦屏。

中間件

中間件負(fù)責(zé)做的事情比較多节沦,狀態(tài)同步,圖片轉(zhuǎn)換還要考慮內(nèi)存占用問題窜管。

  • CMSampleBufferRef轉(zhuǎn)UIImage對象
  • 控制buffer轉(zhuǎn)image的頻率
  • 通過HTTP請求的方式將圖片發(fā)送到主APP
  • 發(fā)送心跳包告知APP插件存活
//
//  MXSampleBufferManager.m
//  
//  buffer轉(zhuǎn)UIImage對象
//  Created by joker on 2018/9/18.
//  Copyright ? 2018 Scorpion. All rights reserved.
//

#import "MXSampleBufferManager.h"
#import <VideoToolbox/VideoToolbox.h>

#define clamp(a)                        (a>255?255:(a<0?0:a))

@implementation MXSampleBufferManager

+ (UIImage*)getImageWithSampleBuffer:(CMSampleBufferRef)sampleBuffer{
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer,0);

    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    uint8_t *yBuffer = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
    size_t yPitch = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0);
    uint8_t *cbCrBuffer = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 1);
    size_t cbCrPitch = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 1);

    int bytesPerPixel = 4;
    uint8_t *rgbBuffer = malloc(width * height * bytesPerPixel);

    for(int y = 0; y < height; y++) {
        uint8_t *rgbBufferLine = &rgbBuffer[y * width * bytesPerPixel];
        uint8_t *yBufferLine = &yBuffer[y * yPitch];
        uint8_t *cbCrBufferLine = &cbCrBuffer[(y >> 1) * cbCrPitch];

        for(int x = 0; x < width; x++) {
            int16_t y = yBufferLine[x];
            int16_t cb = cbCrBufferLine[x & ~1] - 128;
            int16_t cr = cbCrBufferLine[x | 1] - 128;

            uint8_t *rgbOutput = &rgbBufferLine[x*bytesPerPixel];

            int16_t r = (int16_t)roundf( y + cr *  1.4 );
            int16_t g = (int16_t)roundf( y + cb * -0.343 + cr * -0.711 );
            int16_t b = (int16_t)roundf( y + cb *  1.765);

            rgbOutput[0] = 0xff;
            rgbOutput[1] = clamp(b);
            rgbOutput[2] = clamp(g);
            rgbOutput[3] = clamp(r);
        }
    }

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(rgbBuffer, width, height, 8, width * bytesPerPixel, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
    CGImageRef quartzImage = CGBitmapContextCreateImage(context);
    UIImage *image = [UIImage imageWithCGImage:quartzImage];

    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    CGImageRelease(quartzImage);
    free(rgbBuffer);

    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);

    return image;
    
    
}

@end

主APP端

主APP端更多的是跟業(yè)務(wù)相關(guān)的操作

  • 開啟HTTP Serve接收請求(GCDAsyncSocket)
  • 獲取到圖片進(jìn)行TensorFlow識別散劫,輸出classify的結(jié)果。
  • 根據(jù)識別結(jié)果和獲取的配置信息進(jìn)行match幕帆,目標(biāo)關(guān)鍵幀則上傳服務(wù)端OCR
  • 錄屏插件存活檢測

模型怎么訓(xùn)練获搏?

參考鏈接:https://codelabs.developers.google.com/codelabs/tensorflow-for-poets/index.html#0
可以用官網(wǎng)提供的訓(xùn)練工程來簡單的訓(xùn)練模型。
demo工程中會帶一個訓(xùn)練過的微信的模型失乾。

使用效果

通訊錄頁面識別度77%
發(fā)現(xiàn)頁面識別度97%
我的頁面識別度100%

可以看到常熙,在模型訓(xùn)練好的情況下,實(shí)時錄屏的識別度是非常高的碱茁,配合服務(wù)端OCR可以獲取任何出現(xiàn)在屏幕上的內(nèi)容裸卫。

Demo

https://github.com/yushengchu/broadCastSpider

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纽竣,隨后出現(xiàn)的幾起案子墓贿,更是在濱河造成了極大的恐慌,老刑警劉巖蜓氨,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件聋袋,死亡現(xiàn)場離奇詭異,居然都是意外死亡穴吹,警方通過查閱死者的電腦和手機(jī)幽勒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來港令,“玉大人啥容,你說我怎么就攤上這事锈颗。” “怎么了咪惠?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵击吱,是天一觀的道長。 經(jīng)常有香客問我硝逢,道長姨拥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任渠鸽,我火速辦了婚禮叫乌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘徽缚。我一直安慰自己憨奸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布凿试。 她就那樣靜靜地躺著排宰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪那婉。 梳的紋絲不亂的頭發(fā)上板甘,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機(jī)與錄音详炬,去河邊找鬼盐类。 笑死,一個胖子當(dāng)著我的面吹牛呛谜,可吹牛的內(nèi)容都是我干的在跳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼隐岛,長吁一口氣:“原來是場噩夢啊……” “哼猫妙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起聚凹,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤割坠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后妒牙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體韭脊,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年单旁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饥伊。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡象浑,死狀恐怖蔫饰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情愉豺,我是刑警寧澤篓吁,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站蚪拦,受9級特大地震影響杖剪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜驰贷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一盛嘿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧括袒,春花似錦次兆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至恃慧,卻和暖如春园蝠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背痢士。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工彪薛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人良瞧。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓陪汽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親褥蚯。 傳聞我的和親對象是個殘疾皇子挚冤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 越努力地工作和生活,越發(fā)覺意志力像消耗品赞庶,而且训挡,漸漸地,我發(fā)現(xiàn)意志力很像一個游戲模型:血量/法力值歧强。 這個模型由四...
    豬的梳妝臺閱讀 319評論 0 2
  • WEB前端導(dǎo)航 http://www.alloyteam.com/nav/ CDN http://www.boot...
    幸運(yùn)兔腳_f0b5閱讀 189評論 0 0
  • 如果說世界上有一種最偉大的愛澜薄,那一定是母愛!今天是我們河南省商丘市梁園區(qū)謝集鎮(zhèn)良浩第四小學(xué)第十一次快樂音樂...
    沈丹丹閱讀 202評論 0 0
  • 最近在首頁看到了CocoaPods的安裝方法摊册,其實(shí)我也忘記了肤京,就拿了個新電腦試了一下,結(jié)果發(fā)現(xiàn)搬運(yùn)的還是比較老的東...
    sixthElement閱讀 489評論 0 13
  • 前段時間整理保險柜棋枕,看到多年前考取的會計證和會計培訓(xùn)結(jié)業(yè)證書,思緒一下子回到三十年前…… 八七年妒峦,我進(jìn)入一家小廠做...
    晚霞一閱讀 411評論 0 4