Android 使用Jsoup爬取碼云開源項目

先放一下官方文檔

implementation 'org.jsoup:jsoup:1.12.1'

Jsoup可以把網(wǎng)頁解析成Document對象,然后我們根據(jù)對應的元素id或者class以及其他的屬性当宴,獲取對應的信息

幾個重要且常用的方法:
 connect(url): 從URL獲取HTML來解析
 getElementById(String id):通過id來獲取
 getElementsByTag(String tagName):通過標簽名字來獲取
 getElementsByClass(String className):通過類名來獲取
 getElementsByAttribute(String key):通過屬性名字來獲取
 getElementsByAttributeValue(String key, String value):通過指定的屬性名字,屬性值來獲取
 getAllElements():獲取所有元素
 select(String cssQuery):通過類似于css或jQuery的選擇器來查找元素

話不多說擦囊,直接上教程

進入碼云->移動開發(fā)

碼云.jpg

按F12查看網(wǎng)頁內容拦键,按shift+ctrl+C選中列表可以在右邊查看到對應的信息
dev_html.jpg

每個元素的屬性都清楚后,開始寫代碼解析
根據(jù)上面分析的信息先建個文章實體類

data class ArticleBean(val avatar: String, //頭像
                       val title: String,  //標題
                       val label: String,  //分類
                       val watchers: Int,  //關注數(shù)
                       val collect: Int,   //收藏數(shù)
                       val forkNum: Int,   //fork數(shù)
                       val desc: String,   //描述
                       val date: String,   //時間
                       val urlLink: String //文章跳轉鏈接
): Serializable

然后使用上面提到的connect方法去獲取document

val url = "https://gitee.com/explore/mobile-develop?order=recommend"
val document = Jsoup.connect(url).get()

獲取到網(wǎng)頁內容后開始解析它行贪,根據(jù)上面的截圖可以看到,列表的內容被一個div包裹起來了模闲,這個div的class是ui relaxed divided items explore-repo__list建瘫,那我們就根據(jù)這個class去獲取我們需要的文章,注意:在填寫class時要將中間的空格改成"."

val elements = document.select("div.ui.relaxed.divided.items.explore-repo__list").select("div.item")

如果說這個屬性沒有class围橡,但是有id暖混,這時候就應該將"."(不是上面說的空格)改為"#"

val elements = document.select("div#ui.relaxed.divided.items.explore-repo__list").select("div.item")
article_item.jpg

下面就是重復上面的步驟,根據(jù)class或者id翁授,獲取我們需要的數(shù)據(jù)拣播,一層層解析就好了

elements.forEach {
                val social = it.select("div.content").select("div.explore-project__meta-social.pull-right").select("a")
                articles.add(
                    ArticleBean(
                        it.select("a.project-creator-link.ui.avatar.image.pull-left").select("img").attr("src"),
                        it.select("div.content").select("a.title.project-namespace-path").text(),
                        it.select("div.content").select("span>a").text(),
                        social[0].text().toInt(),
                        social[1].text().toInt(),
                        social[2].text().toInt(),
                        it.select("div.project-desc").text(),
                        it.select("div.project-latest").text(),
                        baseUrl + it.select("a.project-creator-link.ui.avatar.image.pull-left").attr("href")
                ))
            }
Video_20190719_031346_446.gif

MainActivity:

class MainActivity : AppCompatActivity(), ArticleAdapter.OnItemClick {
    private var articles = ArrayList<ArticleBean>()
    private val mAdapter: ArticleAdapter by lazy {
        ArticleAdapter(articles, this)
    }

    private val baseUrl = "https://gitee.com"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        recyclerView.run {
            mAdapter.setOnItenClick(this@MainActivity)
            adapter = mAdapter
            layoutManager = LinearLayoutManager(this@MainActivity)
            addItemDecoration(DividerItemDecoration(this@MainActivity, DividerItemDecoration.VERTICAL))
        }

        Thread(Runnable { jsoupData() }).start()
    }

    private fun jsoupData() {
        val url = "https://gitee.com/explore/mobile-develop?order=recommend"

        try {
            val document = Jsoup.connect(url).get()
            val elements = document.select("div.ui.relaxed.divided.items.explore-repo__list").select("div.item")
            elements.forEach {
                val social = it.select("div.content").select("div.explore-project__meta-social.pull-right").select("a")
                articles.add(
                    ArticleBean(
                        it.select("a.project-creator-link.ui.avatar.image.pull-left").select("img").attr("src"),
                        it.select("div.content").select("a.title.project-namespace-path").text(),
                        it.select("div.content").select("span>a").text(),
                        social[0].text().toInt(),
                        social[1].text().toInt(),
                        social[2].text().toInt(),
                        it.select("div.project-desc").text(),
                        it.select("div.project-latest").text(),
                        baseUrl + it.select("a.project-creator-link.ui.avatar.image.pull-left").attr("href")
                ))
            }
            runOnUiThread {
                mAdapter.notifyDataSetChanged()
            }
        } catch (e: Exception) {
            Log.e("error--->", e.message)
        }
    }

    override fun onClick(articleBean: ArticleBean, position: Int) {
        val intent = Intent(this, WebviewActivity::class.java)
        intent.putExtra("articleBean", articleBean)
        startActivity(intent)
    }
}

adapter:

class ArticleAdapter(var items: List<ArticleBean>, val content: Context): RecyclerView.Adapter<ArticleAdapter.ViewHolder>() {

    private var onItemClick: OnItemClick? = null

    public fun setOnItenClick(onItemClick: OnItemClick){
        this.onItemClick = onItemClick
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.article_item_layout, parent, false)
        val holder = ViewHolder(view)
        if (onItemClick != null){
            holder.itemView.setOnClickListener {
                val position = holder.adapterPosition
                val articleBean = items.get(position)
                onItemClick?.onClick(articleBean, position)
            }
        }
        return holder
    }

    override fun getItemCount(): Int {
        return items.size
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        Glide.with(content).load(items[position].avatar).apply(RequestOptions.circleCropTransform()).into(holder.ivAvatar)

        holder.tvTitle.text = items[position].title
        holder.tvContent.text = items[position].desc
        holder.tvWatchers.text = "${items[position].watchers}"
        holder.tvCollect.text = "${items[position].collect}"
        holder.tvFork.text = "${items[position].forkNum}"
        holder.tvDate.text = items[position].date

    }


    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val ivAvatar: ImageView = itemView.findViewById(R.id.iv_avatar)
        val tvTitle: TextView = itemView.findViewById(R.id.tv_title)
        val tvContent: TextView = itemView.findViewById(R.id.tv_content)
        val tvWatchers: TextView = itemView.findViewById(R.id.tv_watchers)
        val tvCollect: TextView = itemView.findViewById(R.id.tv_collect)
        val tvFork: TextView = itemView.findViewById(R.id.tv_fork)
        val tvDate: TextView = itemView.findViewById(R.id.tv_date)
    }

    interface OnItemClick{
        fun onClick(articleBean: ArticleBean, position: Int)
    }
}

有什么不懂得留言告訴我

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市收擦,隨后出現(xiàn)的幾起案子贮配,更是在濱河造成了極大的恐慌,老刑警劉巖塞赂,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泪勒,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機圆存,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門叼旋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沦辙,你說我怎么就攤上這事夫植。” “怎么了油讯?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵详民,是天一觀的道長。 經(jīng)常有香客問我陌兑,道長沈跨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任兔综,我火速辦了婚禮饿凛,結果婚禮上,老公的妹妹穿的比我還像新娘邻奠。我一直安慰自己笤喳,他們只是感情好为居,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布碌宴。 她就那樣靜靜地躺著,像睡著了一般蒙畴。 火紅的嫁衣襯著肌膚如雪贰镣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天膳凝,我揣著相機與錄音碑隆,去河邊找鬼。 笑死蹬音,一個胖子當著我的面吹牛上煤,可吹牛的內容都是我干的。 我是一名探鬼主播著淆,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼劫狠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了永部?” 一聲冷哼從身側響起独泞,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎苔埋,沒想到半個月后懦砂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年荞膘,在試婚紗的時候發(fā)現(xiàn)自己被綠了罚随。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡羽资,死狀恐怖毫炉,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情削罩,我是刑警寧澤瞄勾,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站弥激,受9級特大地震影響进陡,放射性物質發(fā)生泄漏。R本人自食惡果不足惜微服,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一趾疚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧以蕴,春花似錦糙麦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宝与,卻和暖如春焚廊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背习劫。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工咆瘟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诽里。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓袒餐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谤狡。 傳聞我的和親對象是個殘疾皇子灸眼,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354