React Native 網(wǎng)頁抓取與解析(基于 cheerio)

如果你打算用 RN 寫某網(wǎng)站的第三方 App,但該網(wǎng)站不提供可以返回 JSON 的接口坊夫,這種情況下就需要自己進行頁面抓取及解析搬葬。

首先,我們需要明確一件事绍移,RN 既不是 browser 也不是 node悄窃,這意味著有些 js 庫是不能直接拿來用的。

HTTP 請求

RN 提供了 Fetch APIXMLHttpRequest API蹂窖,基于這兩個庫的二次封裝庫也是可以用的轧抗,比如 frisbeeaxios,所以在 RN 下進行 HTTP 請求不是什么問題瞬测。

HTML 解析

當前横媚,最好用的 js html parser 應屬 cheerio,是否可以在 RN 使用呢月趟?讓我們試試灯蝴。

首先,安裝 cherrio(注意孝宗,一定是要 v0.22.0穷躁,后面解釋):

$ npm i cheerio@0.22.0

使用:

import cheerio from 'cheerio'
const $ = cheerio.load('<h2 class="title">Hello world</h2>')

很不幸,出現(xiàn)了錯誤:

error: bundling failed: "Unable to resolve module `events` 

這是因為 cheerio 的依賴 htmlparser2 依賴一些 node 內(nèi)置的庫因妇。不過這是可以被解決的问潭,理論上,只要這些依賴庫不依賴更底層的接口沙峻,那么就可以通過 npm 安裝上這些依賴:

$ npm i events stream buffer

再次刷新睦授,我們發(fā)現(xiàn) cheerio 已經(jīng)可以正常使用了!

其實這個問題有在 cheerio 的 issues 上討論過:https://github.com/cheeriojs/cheerio/issues/1058摔寨。有人為了解決這個問題弄了另外一個庫 cheerio-without-node-native去枷,然而這種做法不僅沒有必要而且非常糟糕,因為這個分裂出去的版本的質(zhì)量是難以保證的。作者的觀點是:

You can install the missing packages from npm (events, stream and utils afaict) and they will be automatically picked up.

I would not recommend the usage of a fork as it will make it difficult to track down issues and will delay, if not prevent, patches for bugs.

至于為什么只能用 cheerio@0.22.0删顶,是因為之后的版本竖螃,cheerio 引入了 parse5,而 parse5 依賴 stream.Writable逗余,npm 安裝的 stream 并不提供特咆。

測試

由于網(wǎng)頁隨時可能發(fā)生變化,測試就顯得尤為重要录粱。這里我以一段獲取簡書用戶數(shù)據(jù)的代碼為例腻格,做一個簡單的黑箱測試。

// api.js
// 這里啥繁,我實現(xiàn)了一個 getUserData 函數(shù)菜职,以 UserID 為參數(shù),
// 獲取個人主頁數(shù)據(jù)旗闽,并解析出用戶頭像鏈接酬核、用戶昵稱、發(fā)表的文章
async function getUserData(user) {
  const response = await fetch('http://www.reibang.com/u/' + user)
  const $ = cheerio.load(await response.text())
  return {
    avatar: 'http:' + $('.avatar img').attr('src'),
    name: $('.title .name').text(),
    articles: $('.note-list li').map(function () {
      return {
        title: $('.title', this).text(),
      }
    }).get()
  }
}

export {getUserData}

為了能在 node 環(huán)境下使用 fetch适室,需要安裝 node-fetch嫡意。RN 已經(jīng)默認安裝了 jest,我們就用它來測試吧:

// __test__/api.js
// 測試 getUserData 是否能正常運行捣辆,并返回預期的結果
// 這里為了更真實的模擬實際情況蔬螟,而用 node-fetch 模擬了 RN 里的 fetch
// 也可以 mock fetch 然后返回預設的測試數(shù)據(jù)
import {getUserData} from '../api'
global.fetch = require('node-fetch')

test('getUserData', async () => {
  const data = await getUserData('3747663284a0')
  expect(data.name).toBe('7c00')
  expect(data.avatar).toMatch(/http:\/\/upload\.jianshu\.io\/users\/upload_avatars.*\.jpg/)
  data.articles.forEach(article => expect(article.title).not.toBeNull())
  console.log(data)
})

運行測試:

$ npm test
npm test

另一種獲取網(wǎng)頁數(shù)據(jù)的黑科技

除了傳統(tǒng)的 HTML 請求解析,在某些情況下我們還可以用類似 PhantomJS 的方案罪帖,優(yōu)點是可以很好地避開一些限制促煮,降低解析難度。RN 里當然用不了 PhantomJS整袁,但我們有 WebView菠齿,可以通過 injectedJavaScript 注入 js,用 postMessage 回傳數(shù)據(jù)坐昙,比如這段用于獲取頁面中視頻鏈接的代碼:

<WebView
  injectedJavaScript={`
    const video = document.querySelector('video');
    if (video) {
      postMessage(video.src);
    }
  `}
  onMessage={event => this._loaded(event.nativeEvent.data)}
  source={{
    uri: this.state.webViewUrl,
    headers: {
      referer: 'https://newplayer.jfrft.com',
    }
  }}
/>

PS. 慎用該方法绳匀,首先是 WebView 消耗資源太大,其次是難以測試炸客,缺乏穩(wěn)定性疾棵。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市痹仙,隨后出現(xiàn)的幾起案子是尔,更是在濱河造成了極大的恐慌,老刑警劉巖开仰,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拟枚,死亡現(xiàn)場離奇詭異薪铜,居然都是意外死亡,警方通過查閱死者的電腦和手機恩溅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門隔箍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人脚乡,你說我怎么就攤上這事蜒滩。” “怎么了奶稠?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵俯艰,是天一觀的道長。 經(jīng)常有香客問我锌订,道長蟆炊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任瀑志,我火速辦了婚禮,結果婚禮上污秆,老公的妹妹穿的比我還像新娘劈猪。我一直安慰自己,他們只是感情好良拼,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布战得。 她就那樣靜靜地躺著,像睡著了一般庸推。 火紅的嫁衣襯著肌膚如雪常侦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天贬媒,我揣著相機與錄音聋亡,去河邊找鬼。 笑死际乘,一個胖子當著我的面吹牛坡倔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播脖含,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼罪塔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了养葵?” 一聲冷哼從身側(cè)響起征堪,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎关拒,沒想到半個月后佃蚜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體庸娱,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年爽锥,在試婚紗的時候發(fā)現(xiàn)自己被綠了涌韩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡氯夷,死狀恐怖臣樱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情腮考,我是刑警寧澤雇毫,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站踩蔚,受9級特大地震影響棚放,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜馅闽,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一飘蚯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧福也,春花似錦局骤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至现喳,卻和暖如春凯傲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嗦篱。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工冰单, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灸促。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓球凰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親腿宰。 傳聞我的和親對象是個殘疾皇子呕诉,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

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

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn)吃度,斷路器甩挫,智...
    卡卡羅2017閱讀 134,600評論 18 139
  • React Native學習<一> 認識Recat Native 博客原文:http://www.jianshu....
    AFinalStone閱讀 2,655評論 0 12
  • 1 熱發(fā)布 網(wǎng)頁發(fā)布 VS APP發(fā)布 網(wǎng)頁發(fā)布:服務端上線新的網(wǎng)頁代碼,用戶端通過鏈接直接訪問椿每。 APP發(fā)布:?...
    kkmoving閱讀 4,065評論 1 15
  • 昨晚收拾利索以后已經(jīng)快23點半了伊者,有點兒疲勞英遭,就沒有寫日志,早晨趕緊不上亦渗,絕不能拖沓挖诸。 天氣轉(zhuǎn)冷,跑步時的溫度-1...
    鐵腿閱讀 169評論 2 1
  • 上課了法精,發(fā)現(xiàn)老師拿出一大包花生多律,意外的是呂老師竟然給每人一顆!同桌說好想吃奥选狼荞!我心想,我也很想吃呢帮碰,老師該不...
    呂思融閱讀 397評論 0 0