爬虫介绍

爬虫就是抓取某个或某些Url地址的数据,可供自己使用;如果数据有价值,也可以商用。

就像要把大象装冰箱一样,爬虫一般也有三个步骤:

  1. 抓取Url数据
  2. 解析数据
  3. 使用数据,具体怎么使用看你的需求

要爬取目标网站是:http://quotes.toscrape.com/,该网站是一个国外的网站,专门展示名人名言。简单一点,我们只爬取首页的数据。

首页有十条数据,我们需要爬取每条名言的作者,内容和标签。

抓取数据

抓取数据需要用到一个三方类库,就是上个小节提到的jsoup,它具有http请求和网页数据解析的双重功能。先将它添加到依赖库,然后创建crawler.kt文件来编写爬虫。

编写一个getHtml方法来抓取数据,抓取数据是耗时操作,我们使用协程实现:

suspend fun main() {
    val url = "http://quotes.toscrape.com/"
    //1.抓取数据
    val document = getHtml(url).await()
}

fun getHtml(url: String): Deferred<Document?> {
    return GlobalScope.async {
        Jsoup.connect(url).get()
    }
}

解析数据

解析数据本质是解析html的结构结构,找到对应的标签,取出文本数据,这里需要你有一些基本的html知识。为了更好的分析目标元素的Dom结构,可以利用Chrome的开发者工具。

编写一个方法parseHtml来解析数据:

fun parseHtml(document: Document) {
    val elements = document.select("div.quote")
    elements.forEach {
        val content = it.selectFirst("span.text").html()
        val author = it.selectFirst("span>small.author").html()
        val tagEls = it.select("div.tags>a")
        tagEls.forEach { tag -> println(tag.html()) }
    }
}

数据虽然解析出来了,但是这些数据是散乱的,不方便传输,处理以及下一步的使用。我们需要编写一个类来封装这些信息:

data class Quote(
        var content: String,
        var author: String,
        var tags: List<String>
){
    fun toJson() = """
        {
            "content": $content,
            "author": $author,
            "tags": [${tags.joinToString(separator = ", ")}]
        }
    """.trimIndent()
}

改写parseHtml方法如下:

fun parseHtml(document: Document): List<Quote> {
    val elements = document.select("div.quote")
    val list = mutableListOf<Quote>()
    elements.forEach {
        val content = it.selectFirst("span.text").html()
        val author = it.selectFirst("span>small.author").html()
        val tagEls = it.select("div.tags>a")
        val tags = mutableListOf<String>()
        tagEls.forEach { tag -> tags.add(tag.html()) }
        list.add(Quote(content = content, author = author, tags = tags))
    }
    return list
}

最终的main方法如下:

suspend fun main() {
    val url = "http://quotes.toscrape.com/"
    //1.抓取数据
    val document = getHtml(url).await()
    //2.解析数据
    if (document != null) {
        parseHtml(document)
    }
}

使用数据

在企业级项目中我们在使用数据之前可能会将数据进行持久化存储,比如保存到Mysql。具体怎么使用,每个公司的需求都不一样,可以用图表展示,数据量大的话可以用大数据框架进行处理。我们这里只是简单的打印Json,编写一个方法printData

fun printData(quotes: List<Quote>){
    quotes.forEach { println(it.toJson()) }
}

最终的main方法如下:

suspend fun main() {
    val url = "http://quotes.toscrape.com/"
    //1.抓取数据
    val document = getHtml(url).await()
    //2.解析数据
    if (document != null) {
        val quotes = parseHtml(document)
        //3.打印数据
        printData(quotes)
    }
}

运行项目,将会打印出Json结构的数据:

{
    "author": Albert Einstein,
    "content": “The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”,
    "tags": [change, deep-thoughts, thinking, world]
}
{
    "author": J.K. Rowling,
    "content": “It is our choices, Harry, that show what we truly are, far more than our abilities.”,
    "tags": [abilities, choices]
}
...

通过这个小小的爬虫项目,我们综合练习了数据类,Kotlin协程,使用Gradle添加三方库,集合和高阶函数,原生字符串等知识。

我们目前只爬取了网站首页的数据,如果你对爬虫感兴趣,思考一下,如何能爬取整个网站的数据呢?

更新时间: 4/30/2019, 9:52:46 PM