Python 是一门有用的语言。然而,由于脚本语言缺乏严格的类型评估和一些昂贵的操作,它可能会出错。 根据我个人的经验,在分析目标变大并且需要并行性的程序中,我经常被Python中不可重现的错误所困扰。 我随意尝试了一下Kotlin,发现它相当好用,所以我尝试移植Python3中实现的Scraper。
(顺便说一下,我从来没有真正接触过Java)
这是 Kotlin 新手,但 Python 线程和 Kotlin 线程的行为似乎不同。
尽管Kotlin的Thread没有进行进程拆分,但CPU使用率超过100%,因此看起来是在使用多个CPU进行高效的线程处理。 (也就是说,用Multiprocess划分后,似乎不需要在其下运行Thread了)
这是在 Ubuntu 上安装的方法。
$ curl -s https://get.sdkman.io | bash
$ sdk install kotlin
看来JVM内存是记录在环境变量JAVA_OPT中的,正常使用的话会因为内存不足而崩溃,所以还是用现代的方式修复一下吧。 我有这样的设置。
JAVA_OPTS= " -Xmx3000M -Xms3000M "
我不擅长Java,我想过尽可能避免Java的职业规划,但我觉得学习工具本身会很困难,主要是Eclipse和IDE,因为有很多。的事情。
如果用 IDE 来使用 Kotlin 会很方便,但我认为只要用 CUI 编译和运行没有问题,CUI 就可以。
编译的方法有很多,但我们发现将其编译成jar文件更有用,包括运行时。
$ kotlinc foo.kt -include-runtime -d foo.jar
现在你可以编译了。
您可以将多个文件合并到一个 jar 中。 (可以参考bar.kt的函数和foo.kt中的Class)
$ kotlinc foo.kt bar.kt -include-runtime -d foo.jar
可以通过将可以使用Java的Maven等编译的jar文件添加到类路径来使用它。 (假设您使用文件 alice.jar 和 bob.jar)
这非常有帮助,因为它允许我们重用许多 Java 资产。
$ kotlinc foo.kt bar.kt -cp alice.jar:bob.jar -include-runtime foo.jar
例如,当使用外部 jar 文件执行 kotlin jar 时,命令将如下所示。
$ kotlin -cp alice.jar:bob.jar:foo.jar FooKt
这个名字 FooKt 似乎是用来指定包含 main 函数的 foo.kt 文件。
当使用 JavaScript 进行异步数据加载时,如果您只是简单地检索它并使用 jsoup 等分析它,您将无法获取内容。您必须运行 JavaScript 来创建类似于人类所看到的状态,通过selenium运行phamtomjs使JavaScript工作例如,微软Bing的图像搜索是用Ajax渲染的,无法在JavaScript无法工作的环境中工作。 (这是出于实验目的,所以实际抓取图像时,请通过API进行。)
val driver = PhantomJSDriver ()
driver.manage().window().setSize( Dimension ( 4096 , 2160 ))
driver.get( " https://www.bing.com/images/search?q= ${encoded} " )
//すべての画像が描画されるのを待つ
Thread .sleep( 3001 )
val html = driver.getPageSource()
html 变量将包含 JavaScript 运行后渲染的 html。通过将其放入jsoup中,您可以找到各种图像的src URL,根据您找到的图像的URL,使用wget命令将其存储在任意目录下的文件夹中。
val doc = Jsoup .parse(html.toString(), " UTF-8 " )
println (doc.title())
doc.select( " img " ).filter { x ->
x.attr( " class " ) == " mimg "
}.map { x ->
val data_bm = x.attr( " data-bm " )
val src = x.attr( " src " )
Runtime .getRuntime().exec( " wget ${src} -O imgs/ ${name} / ${data_bm} .png " )
}
PhantomJS 需要从该站点下载并放置在 PATH 中。
似乎有多种写法,但这是最简单的实现。
{} 中包含的要抓取的整个逻辑成为一个线程实例,您可以启动或加入该线程以并行运行它。
val threads = url_details.keys.map { url ->
val th = Thread {
if (url_details[url] !! == "まだ" ) {
_parser (url).map { next ->
urls.add(next)
}
println ( "終わりに更新 : $url " )
url_details[url] = "終わり"
// save urls
_save_conf ( mapper.writeValueAsString(url_details) )
}
}
th
}
看来有一个叫jackson的序列化模块可以在有限的时间内使用。
看来单独Java库不行,需要单独加载Kotlin的模块。
受限制,我尝试序列化和反序列化 MutableMap<String, DataClass> 但它不起作用。
MutableMap<String, String> 工作正常,所以我不确定嵌套结构是否不好或者它是否不支持数据类。
序列化示例
val mapper = ObjectMapper ().registerKotlinModule()
val serialzied = mapper.writeValueAsString(url_details)
反序列化示例
val mapper = ObjectMapper ().registerKotlinModule()
val url_details = mapper.readValue< MutableMap < String , String >>(json)
首先,git克隆
$ git clone https://github.com/GINK03/kotlin-phantomjs-selenium-jsoup-parser.git
到目前为止,已经实现了两种类型的抓取:使用广度优先搜索简单地抓取到 100 的深度,而不评估 JavaScript。
(由于我用它来抓取我自己的网站,因此我没有设置任何特定限制,但默认为 50 或更多并行访问,因此请相应调整。)
$ sh run.scraper.sh widthSearch ${yourOwnSite}
使用 Microsoft Bing 在图像搜索屏幕上进行搜索。这是一个实验代码,目的是看看是否可以在不使用 API 的情况下获取使用 Ajax 绘制的内容,因此我认为不应该大量访问并造成麻烦。
搜索列表请参考github上的kancolle.txt文件。
sh run.scraper.sh image ${検索クエリリスト} ${出力ディレクトリ}