Kotlin crawler utilise lambda pour réduire la réutilisation du code
De nombreuses structures de phrases dans kotlin sont des expressions, telles que try {…} catch () {…}, if… else… est beaucoup plus facile à écrire que Java. La syntaxe de Java est plus verbeuse, et elle est beaucoup moins simple que Python et nodejs lors de la création de programmes de robot.
Dans le programme de robot d'exploration, nodejs et Python ont des bibliothèques de sons, telles que le module marionnettiste de node, développé par Google, qui peut simuler l'environnement Chrome, exécuter des événements, installer des écouteurs et explorer des pages Web dynamiques. En revanche, Java est très laborieux, et l'utilisation dans ce domaine est plus lourde. Kotlin absorbe le sucre syntaxique de nombreux langages, et l'expression lambda de Kotlin est un peu similaire à la fonction de rappel de Js, ce qui la rend plus simple et plus flexible que Java en écriture, ce qui réduit considérablement la quantité de code.
Kotlin est facile à gérer les exceptions afin de ne pas signaler les erreurs autant que possible. Parce qu'une telle erreur n'est pas très nécessaire, mais mettra fin au programme.
Dans le même temps, kotlin permet d'écrire des fonctions d'extension, nous pouvons écrire une fonction basée sur cela, pour rendre la bibliothèque d'origine plus utilisable. En même temps, il n'y a aucune différence entre la fonction d'extension et la fonction dans le package.
Ici, j'ai parcouru Douban Books Top250, uniquement sur l'interface de la liste, et je n'ai pas entré la page de chaque livre.
Les tables de lecture et d'écriture utilisent le package POI, l'objet XSSFWorkBook peut lire et écrire des fichiers au format xlsx.
La hiérarchie des fichiers de table est classeur> feuille> ligne> cellule
Tout d'abord, le processus d'écriture d'une table est très fixe: créez un classeur, transmettez le flux d'entrée, écrivez des données dans le classeur et écrivez le classeur dans le flux de sortie du fichier.
Ainsi, le processus d'écriture des données dans le classeur est représenté par une fonction, et il suffit de compléter le nombre de fonctions. Afin d'améliorer les performances, définissez-le comme une fonction en ligne.
import org.apache.poi.ss.usermodel.CellType
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.xssf.usermodel.XSSFSheet
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
inline fun writeXLSX(fileName: String, operateFile: (XSSFWorkbook) -> Unit) {
//如果文件不存在,就创建一个新文件
if (!File(fileName).exists()) {
File(fileName).createNewFile()
}
val fIS = FileInputStream(fileName)
//这里使用try{}catch{},如果输入流为空,就创建一个空的WorkBook
val workbook = try {
XSSFWorkbook(fIS)
} catch (e: Exception) {
XSSFWorkbook()
}
//这里调用lambda函数,可以对其自定义
operateFile(workbook)
val out = FileOutputStream(fileName)
workbook.write(out)
fIS.close()
out.close()
workbook.close()
}
De cette façon, lorsque nous écrivons des données dans la table, nous n'avons besoin que du chemin du fichier de la table et du processus de complément de l'écriture des données.
writeXLSX("D:\\IdeaProjects\\spider\\src\\main\\java\\org\\wang\\spider\\out.xlsx") {
// 这里写上对表格的数据,使用it便可以得到函数的自变量,一个XSSFWorkBook对象
}
Ensuite, écrivez une fonction d'extension, vous pouvez écrire un tableau de 0 par défaut à une ligne de la feuille, bien sûr, il peut être modifié par le mot-clé start, isCreated indique s'il faut recréer ou obtenir la ligne
import org.apache.poi.ss.usermodel.CellType
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.xssf.usermodel.XSSFSheet
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
fun Sheet.writeArray(data: Array<String>, row: Int, start: Int = 0, isCreate: Boolean = true) {
val currentRow = if (isCreate) {
createRow(row)
} else {
getRow(row)
}
for ((index, d) in data.withIndex()) {
currentRow.createCell(index + start, CellType.STRING).setCellValue(d)
}
}
Ensuite, écrivez une fonction pour créer une feuille, aucune erreur ne sera signalée même si le nom de la feuille est répété
import org.apache.poi.ss.usermodel.CellType
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.xssf.usermodel.XSSFSheet
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
fun XSSFWorkbook.creatSheetIfNotExit(name: String): XSSFSheet = try {
getSheet(name)
} catch (e: IllegalArgumentException) {
createSheet(name)
} catch (e: NullPointerException) {
createSheet(name)
}
Ensuite, nous pouvons écrire une fonction pour mesurer le temps d'exécution du programme
import org.apache.poi.ss.usermodel.CellType
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.xssf.usermodel.XSSFSheet
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
fun measureTime(operation: () -> Unit): Long {
val t1 = System.currentTimeMillis()
operation()
val t2 = System.currentTimeMillis()
return t2 - t1
}
Nous pouvons voir que le lambda de Kotlin est comme une fonction de rappel de js, ce qui est très pratique à utiliser
Ensuite, analysez la page Web de Douban. Le package Jsoup est utilisé pour analyser la page Web. L'utilisation de ce package est
presque la même que celle de js . Vous pouvez utiliser le sélecteur css3 pour sélectionner des éléments avec précision. Dans le même temps, certains des livres très spéciaux ne sont pas traités, comme la Bible et les Analectes.
Lambda est également utilisé ici pour traiter les résultats de chaque élément renvoyé:
Section importante:
<td valign="top">
<div class="pl2">
<a href="https://book.douban.com/subject/1007305/" onclick=""moreurl(this,{i:'0'})"" title="红楼梦">
红楼梦
</a>
</div>
<p class="pl">[清] 曹雪芹 著 / 人民文学出版社 / 1996-12 / 59.70元</p>
<div class="star clearfix">
<span class="allstar50"></span>
<span class="rating_nums">9.6</span>
<span class="pl">(
314870人评价
)</span>
</div>
<p class="quote" style="margin: 10px 0; color: #666">
<span class="inq">都云作者痴,谁解其中味?</span>
</p>
<span class="rr">
<a name="1007305" class="j ll colbutt a_add2cart add2cart" href="javascript:;"><span><em>加入购书单</em></span></a>
<span class="hidden">已在<a href="https://book.douban.com/cart">购书单</a></span>
</span><br class="clearfix">
<span class="gact">
<a href="/wish/197805944/update?add=1007305" name="sbtn-1007305-wish" class="j a_collect_btn" rel="nofollow">想读</a>
</span>
<span class="gact">
<a href="/do/197805944/update?add=1007305" name="sbtn-1007305-do" class="j a_collect_btn" rel="nofollow">在读</a>
</span>
<span class="gact">
<a href="/collection/197805944/update?add=1007305" name="sbtn-1007305-collect" class="j a_collect_btn" rel="nofollow">读过</a>
</span>
</td>
import org.jsoup.nodes.Document
inline fun parserDomOfDouban(dom: Document, callBack: (Array<String>, Int) -> Unit) {
/* result[0] : 中文名,
result[1] : 原名,
result[2] : 作者,
result[3] : 译者,
result[4] : 出版社,
result[5] : 出版时间,
result[6] : 定价,
result[7] : 评分,
result[8] : 评价人数,
result[9] : 一句话简介,
*/
val items = dom.select("tr.item td[valign=top]:nth-child(2)")
items.mapIndexed {
index, it ->
val result = Array(10) {
"" }
val bookName = it.select("div.pl2")
val cName = bookName.select("a").text()
val fName = it.select("div.pl2 > span").text()
result[0] = cName
result[1] = fName
val infos = it.select("p.pl")[0].text()
// println(infos)
val infosSplit = infos.split("/")
when (infosSplit.size) {
5 -> {
result[2] = infosSplit[0]
result[3] = infosSplit[1]
result[4] = infosSplit[2]
result[5] = infosSplit[3]
result[6] = infosSplit[4]
}
4 -> {
result[2] = infosSplit[0]
result[4] = infosSplit[1]
result[5] = infosSplit[2]
result[6] = infosSplit[3]
}
6 -> {
result[2] = infosSplit[0]
result[3] = infosSplit[1]
result[4] = infosSplit[2]
result[5] = infosSplit[3]
result[6] = infosSplit[4] + " ; " + infosSplit[5]
}
}
result[7] = it.select("span.rating_nums").text()
result[8] = it.select("div.star.clearfix span:nth-child(3)").text().substringBefore('人').substring(2)
result[9] = it.select("span.inq").text()
callBack(result, index)
}
}
fonction mian pour exécuter le programme
fun main() {
val t = measureTime {
for (i in 0..9) {
val baseUrl = "https://book.douban.com/top250?start=${
i * 25}"
val dom = Jsoup.connect(baseUrl).get()
writeXLSX("D:\\IdeaProjects\\spider\\src\\main\\java\\org\\wang\\spider\\out.xlsx") {
wb ->
val sheet = wb.creatSheetIfNotExit("豆瓣图书Top250")
val title = listOf(
"中文名", "原名", "作者", "译者", "出版社", "出版时间", "定价",
"评分", "评价人数", "一句话简介"
).toTypedArray()
sheet.writeArray(title, 0)
parserDomOfDouban(dom) {
data, index ->
sheet.writeArray(data, index+i*25+1)
}
}
}
}
println("花费时间为 $t ms")
}
Alors tu as fini