首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 深層網絡爬蟲實現:異步鏈式請求與數據解析架構設計

     編輯:程式設計綜合問答

需求分析

目標:Android 端實現深層爬蟲 —— 首頁列表獲取新聞標題+鏈接 → 進入詳情頁解析圖片/正文。核心難點:網絡請求串行依賴(詳情頁 URL 依賴列表頁解析),且必須在子線程執行。

架構設計:協程 + 鏈式調用(現代最佳實踐)

拋棄嵌套 AsyncTask(「回調地獄」),採用 Kotlin 協程 + Retrofit + Jsoup,代碼同步寫法、異步執行。

依賴配置

// build.gradle (Module)
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-scalars:2.9.0" // 返回原始 HTML
implementation "org.jsoup:jsoup:1.16.1"

核心實現

// 1. 定義網絡接口
interface ApiService {
    @GET
    suspend fun getHtml(@Url url: String): String
}

// 2. 數據實體
data class News(val title: String, val link: String, var content: String = "", var images: List = emptyList())

// 3. 爬蟲邏輯(在 ViewModel 或 Repository 中)
class NewsRepository(private val api: ApiService) {
    // 獲取列表頁並解析標題+鏈接
    suspend fun fetchList(page: Int): List {
        val html = api.getHtml("https://example.com/news?page=$page")
        return parseList(html)
    }

    // 並發獲取所有詳情頁
    suspend fun fetchDetails(newsList: List): List {
        return coroutineScope {
            newsList.map { news ->
                async(Dispatchers.IO) {
                    val detailHtml = api.getHtml(news.link)
                    news.content = parseContent(detailHtml)
                    news.images = parseImages(detailHtml)
                    news
                }
            }.awaitAll()
        }
    }
}

// 4. UI 層調用(MainScope)
viewModelScope.launch {
    val list = repo.fetchList(1)
    val detailed = repo.fetchDetails(list)
    _newsList.postValue(detailed) // 更新 LiveData/StateFlow
}

關鍵優勢

  • 結構化並發:coroutineScope 確保所有詳情請求完成才返回,異常自動傳播取消。
  • 線程調度:Dispatchers.IO 專用於網絡/磁盤,不阻塞主線程。
  • 取消傳播:頁面銷毀自動取消所有未完成請求,無內存洩漏。
  • 代碼可讀性:同步寫法表達異步流程,易維護、易擴展(如加入重試、限流)。

Java 版本替代方案

若必須用 Java,使用 RxJava 3 + Retrofit:

Observable.fromIterable(newsList)
    .flatMap(news -> api.getHtml(news.link)
        .subscribeOn(Schedulers.io())
        .map(html -> { parseDetail(news, html); return news; }))
    .toList()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(this::onSuccess, this::onError);

工程化建議

  1. 封裝 HtmlParser 工具類,統一 Jsoup 選擇器邏輯,便於網站改版維護。
  2. 加入 緩存策略(Room/文件緩存),避免重複請求。
  3. 實現 斷點續爬:記錄已爬取 URL 集合(SharedPreferences/Room),啟動時去重。
  4. 遵守 robots.txt、設置合理 User-Agent、請求間隔隨機化,防反爲蟲封禁。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved